Repository: kimchi-project/kimchi
Branch: master
Commit: 36ed74be5d20
Files: 491
Total size: 12.3 MB
Directory structure:
gitextract_awwiafkd/
├── .flake8
├── .github/
│ ├── ISSUE_TEMPLATE/
│ │ ├── bug_report.md
│ │ └── feature_request.md
│ ├── pull_request_template.md
│ ├── scripts/
│ │ ├── setup_instance.sh
│ │ └── setup_kimchi_ubuntu.sh
│ └── workflows/
│ └── CI.yml
├── .gitignore
├── .pre-commit-config.yaml
├── ABOUT-NLS
├── API.json
├── AUTHORS
├── CONTRIBUTE.md
├── COPYING
├── COPYING.ASL2
├── COPYING.LGPL
├── ChangeLog
├── INSTALL
├── Makefile.am
├── VERSION
├── __init__.py
├── autogen.sh
├── build-aux/
│ ├── config.rpath
│ ├── genChangelog
│ ├── generateDepsFiles.py
│ └── pkg-version
├── build_packages.py
├── check_spec_errors.sh
├── check_ui_code_errors.sh
├── config.py.in
├── config.rpath
├── configure.ac
├── contrib/
│ ├── DEBIAN/
│ │ ├── Makefile.am
│ │ └── control.in
│ ├── Makefile.am
│ ├── check_i18n.py
│ ├── kimchi.spec.fedora.in
│ ├── kimchi.spec.suse.in
│ ├── kimchid.service.debian
│ ├── kimchid.service.fedora
│ └── make-deb.sh.in
├── control/
│ ├── Makefile.am
│ ├── __init__.py
│ ├── cpuinfo.py
│ ├── groups.py
│ ├── host.py
│ ├── interfaces.py
│ ├── networks.py
│ ├── ovsbridges.py
│ ├── storagepools.py
│ ├── storageservers.py
│ ├── storagevolumes.py
│ ├── templates.py
│ ├── users.py
│ ├── vm/
│ │ ├── Makefile.am
│ │ ├── __init__.py
│ │ ├── hostdevs.py
│ │ ├── ifaces.py
│ │ ├── snapshots.py
│ │ └── storages.py
│ └── vms.py
├── dependencies.yaml
├── disks.py
├── distroloader.py
├── distros.d/
│ ├── Makefile.am
│ ├── debian.json
│ ├── fedora.json
│ ├── gentoo.json
│ ├── opensuse.json
│ └── ubuntu.json
├── docs/
│ ├── API.md
│ ├── CI.md
│ ├── Makefile.am
│ ├── README.md
│ └── README.md.tmpl
├── i18n.py
├── imageinfo.py
├── iscsi.py
├── isoinfo.py
├── kimchi.conf
├── kvmusertests.py
├── m4/
│ ├── ac_python_module.m4
│ ├── gettext.m4
│ ├── iconv.m4
│ ├── intlmacosx.m4
│ ├── lib-ld.m4
│ ├── lib-link.m4
│ ├── lib-prefix.m4
│ ├── nls.m4
│ ├── po.m4
│ └── progtest.m4
├── mockmodel.py
├── model/
│ ├── Makefile.am
│ ├── __init__.py
│ ├── cpuinfo.py
│ ├── diskutils.py
│ ├── featuretests.py
│ ├── groups.py
│ ├── host.py
│ ├── hostdev.py
│ ├── interfaces.py
│ ├── libvirtconnection.py
│ ├── libvirtevents.py
│ ├── libvirtstoragepool.py
│ ├── model.py
│ ├── networks.py
│ ├── ovsbridges.py
│ ├── storagepools.py
│ ├── storageservers.py
│ ├── storagetargets.py
│ ├── storagevolumes.py
│ ├── templates.py
│ ├── users.py
│ ├── utils.py
│ ├── virtviewerfile.py
│ ├── vmhostdevs.py
│ ├── vmifaces.py
│ ├── vms.py
│ ├── vmsnapshots.py
│ └── vmstorages.py
├── network.py
├── osinfo.py
├── po/
│ ├── LINGUAS
│ ├── Makefile.in.in
│ ├── Makevars
│ ├── POTFILES.in
│ ├── de_DE.po
│ ├── en_US.po
│ ├── es_ES.po
│ ├── fr_FR.po
│ ├── gen-pot.in
│ ├── it_IT.po
│ ├── ja_JP.po
│ ├── kimchi.pot
│ ├── ko_KR.po
│ ├── pt_BR.po
│ ├── ru_RU.po
│ ├── zh_CN.po
│ └── zh_TW.po
├── requirements-FEDORA.txt
├── requirements-OPENSUSE-LEAP.txt
├── requirements-UBUNTU.txt
├── requirements-dev.txt
├── root.py
├── scan.py
├── screenshot.py
├── serialconsole.py
├── setup.cfg
├── template.conf
├── tests/
│ ├── Makefile.am
│ ├── iso_gen.py
│ ├── run_tests.sh.in
│ ├── test_authorization.py
│ ├── test_config.py.in
│ ├── test_disks.py
│ ├── test_host.py
│ ├── test_livemigration.py
│ ├── test_mock_network.py
│ ├── test_mock_storagepool.py
│ ├── test_mock_storagevolume.py
│ ├── test_mockmodel.py
│ ├── test_model.py
│ ├── test_model_libvirtevents.py
│ ├── test_model_network.py
│ ├── test_model_storagepool.py
│ ├── test_model_storagevolume.py
│ ├── test_networkxml.py
│ ├── test_osinfo.py
│ ├── test_rest.py
│ ├── test_storagepoolxml.py
│ ├── test_template.py
│ └── test_vmtemplate.py
├── ui/
│ ├── Makefile.am
│ ├── config/
│ │ ├── Makefile.am
│ │ └── tab-ext.xml
│ ├── css/
│ │ ├── Makefile.am
│ │ ├── kimchi.css
│ │ └── src/
│ │ ├── kimchi.scss
│ │ └── modules/
│ │ ├── _edit-guests.scss
│ │ ├── _guests.scss
│ │ ├── _iso-list.scss
│ │ ├── _network.scss
│ │ ├── _storage.scss
│ │ └── _templates.scss
│ ├── images/
│ │ └── Makefile.am
│ ├── js/
│ │ ├── Makefile.am
│ │ └── src/
│ │ ├── kimchi.api.js
│ │ ├── kimchi.guest_add_main.js
│ │ ├── kimchi.guest_edit_main.js
│ │ ├── kimchi.guest_livemigration.js
│ │ ├── kimchi.guest_main.js
│ │ ├── kimchi.guest_media_main.js
│ │ ├── kimchi.guest_storage_add.main.js
│ │ ├── kimchi.main.js
│ │ ├── kimchi.network.js
│ │ ├── kimchi.network_add_main.js
│ │ ├── kimchi.network_edit_main.js
│ │ ├── kimchi.storage_main.js
│ │ ├── kimchi.storagepool_add_main.js
│ │ ├── kimchi.storagepool_add_volume_main.js
│ │ ├── kimchi.storagepool_resize_volume_main.js
│ │ ├── kimchi.template_add_main.js
│ │ ├── kimchi.template_edit_main.js
│ │ └── kimchi.template_main.js
│ ├── pages/
│ │ ├── Makefile.am
│ │ ├── guest-add.html.tmpl
│ │ ├── guest-clone.html.tmpl
│ │ ├── guest-edit.html.tmpl
│ │ ├── guest-migration.html.tmpl
│ │ ├── guest-storage-add.html.tmpl
│ │ ├── guest.html.tmpl
│ │ ├── help/
│ │ │ ├── Makefile.am
│ │ │ ├── de_DE/
│ │ │ │ ├── Makefile.am
│ │ │ │ ├── guests.dita
│ │ │ │ ├── network.dita
│ │ │ │ ├── storage.dita
│ │ │ │ └── templates.dita
│ │ │ ├── dita-help.xsl
│ │ │ ├── en_US/
│ │ │ │ ├── Makefile.am
│ │ │ │ ├── guests.dita
│ │ │ │ ├── network.dita
│ │ │ │ ├── storage.dita
│ │ │ │ └── templates.dita
│ │ │ ├── es_ES/
│ │ │ │ ├── Makefile.am
│ │ │ │ ├── guests.dita
│ │ │ │ ├── network.dita
│ │ │ │ ├── storage.dita
│ │ │ │ └── templates.dita
│ │ │ ├── fr_FR/
│ │ │ │ ├── Makefile.am
│ │ │ │ ├── guests.dita
│ │ │ │ ├── network.dita
│ │ │ │ ├── storage.dita
│ │ │ │ └── templates.dita
│ │ │ ├── it_IT/
│ │ │ │ ├── Makefile.am
│ │ │ │ ├── guests.dita
│ │ │ │ ├── network.dita
│ │ │ │ ├── storage.dita
│ │ │ │ └── templates.dita
│ │ │ ├── ja_JP/
│ │ │ │ ├── Makefile.am
│ │ │ │ ├── guests.dita
│ │ │ │ ├── network.dita
│ │ │ │ ├── storage.dita
│ │ │ │ └── templates.dita
│ │ │ ├── kimchi.css
│ │ │ ├── ko_KR/
│ │ │ │ ├── Makefile.am
│ │ │ │ ├── guests.dita
│ │ │ │ ├── network.dita
│ │ │ │ ├── storage.dita
│ │ │ │ └── templates.dita
│ │ │ ├── pt_BR/
│ │ │ │ ├── Makefile.am
│ │ │ │ ├── guests.dita
│ │ │ │ ├── network.dita
│ │ │ │ ├── storage.dita
│ │ │ │ └── templates.dita
│ │ │ ├── ru_RU/
│ │ │ │ ├── Makefile.am
│ │ │ │ ├── guests.dita
│ │ │ │ ├── network.dita
│ │ │ │ ├── storage.dita
│ │ │ │ └── templates.dita
│ │ │ ├── zh_CN/
│ │ │ │ ├── Makefile.am
│ │ │ │ ├── guests.dita
│ │ │ │ ├── network.dita
│ │ │ │ ├── storage.dita
│ │ │ │ └── templates.dita
│ │ │ └── zh_TW/
│ │ │ ├── Makefile.am
│ │ │ ├── guests.dita
│ │ │ ├── network.dita
│ │ │ ├── storage.dita
│ │ │ └── templates.dita
│ │ ├── i18n.json.tmpl
│ │ ├── network-add.html.tmpl
│ │ ├── network-edit.html.tmpl
│ │ ├── storagepool-add-volume.html.tmpl
│ │ ├── storagepool-add.html.tmpl
│ │ ├── storagepool-resize-volume.html.tmpl
│ │ ├── tabs/
│ │ │ ├── Makefile.am
│ │ │ ├── guests.html.tmpl
│ │ │ ├── network.html.tmpl
│ │ │ ├── storage.html.tmpl
│ │ │ └── templates.html.tmpl
│ │ ├── template-add.html.tmpl
│ │ └── template-edit.html.tmpl
│ ├── robots.txt
│ ├── serial/
│ │ ├── Makefile.am
│ │ ├── html/
│ │ │ ├── Makefile.am
│ │ │ └── serial.html
│ │ └── libs/
│ │ ├── Makefile.am
│ │ └── term.js
│ ├── spice-html5/
│ │ ├── Makefile.am
│ │ ├── atKeynames.js
│ │ ├── bitmap.js
│ │ ├── css/
│ │ │ ├── Makefile.am
│ │ │ └── spice.css
│ │ ├── cursor.js
│ │ ├── display.js
│ │ ├── enums.js
│ │ ├── inputs.js
│ │ ├── lz.js
│ │ ├── main.js
│ │ ├── pages/
│ │ │ ├── Makefile.am
│ │ │ └── spice_auto.html
│ │ ├── playback.js
│ │ ├── png.js
│ │ ├── quic.js
│ │ ├── resize.js
│ │ ├── simulatecursor.js
│ │ ├── spicearraybuffer.js
│ │ ├── spiceconn.js
│ │ ├── spicedataview.js
│ │ ├── spicemsg.js
│ │ ├── spicetype.js
│ │ ├── thirdparty/
│ │ │ ├── Makefile.am
│ │ │ ├── jsbn.js
│ │ │ ├── prng4.js
│ │ │ ├── rng.js
│ │ │ ├── rsa.js
│ │ │ └── sha1.js
│ │ ├── ticket.js
│ │ ├── utils.js
│ │ ├── webm.js
│ │ └── wire.js
│ └── spice-web-client/
│ ├── LICENSE
│ ├── Makefile.am
│ ├── README.md
│ ├── application/
│ │ ├── Makefile.am
│ │ ├── WorkerProcess.js
│ │ ├── agent.js
│ │ ├── application.js
│ │ ├── clientgui.js
│ │ ├── imagecache.js
│ │ ├── inputmanager.js
│ │ ├── packetfactory.js
│ │ ├── packetfilter.js
│ │ ├── packetprocess.js
│ │ ├── rasteroperation.js
│ │ ├── spiceconnection.js
│ │ ├── stream.js
│ │ └── virtualmouse.js
│ ├── benchmark.html
│ ├── commit-stage.sh
│ ├── index.html
│ ├── keymaps/
│ │ ├── Makefile.am
│ │ ├── keymap.js
│ │ ├── keymapes.js
│ │ ├── keymapit.js
│ │ └── keymapus.js
│ ├── lib/
│ │ ├── AsyncConsumer.js
│ │ ├── AsyncWorker.js
│ │ ├── CollisionDetector.js
│ │ ├── DataLogger.js
│ │ ├── GenericObjectPool.js
│ │ ├── GlobalPool.js
│ │ ├── ImageUncompressor.js
│ │ ├── IntegrationBenchmark.js
│ │ ├── Makefile.am
│ │ ├── PacketWorkerIdentifier.js
│ │ ├── SyncAsyncHandler.js
│ │ ├── base64.js
│ │ ├── biginteger.js
│ │ ├── bowser.js
│ │ ├── displayRouter.js
│ │ ├── encrypt.js
│ │ ├── flipper.js
│ │ ├── graphic.js
│ │ ├── graphicdebug.js
│ │ ├── images/
│ │ │ ├── Makefile.am
│ │ │ ├── bitmap.js
│ │ │ ├── jsquic_family.js
│ │ │ ├── jsquic_rgba.js
│ │ │ ├── jsquic_uncompress.js
│ │ │ ├── lz.js
│ │ │ └── png.js
│ │ ├── jquery-2.0.3.js
│ │ ├── jquery-mousewheel.js
│ │ ├── jsbn.js
│ │ ├── jsbn2.js
│ │ ├── modernizr.js
│ │ ├── pixastic.js
│ │ ├── prettyprint.js
│ │ ├── prng4.js
│ │ ├── queue.js
│ │ ├── rasterEngine.js
│ │ ├── rng.js
│ │ ├── runqueue.js
│ │ ├── sha1.js
│ │ ├── stuckkeyshandler.js
│ │ ├── timelapsedetector.js
│ │ ├── utils.js
│ │ └── virtualjoystick.js
│ ├── network/
│ │ ├── Makefile.am
│ │ ├── busconnection.js
│ │ ├── clusternodechooser.js
│ │ ├── connectioncontrol.js
│ │ ├── packetcontroller.js
│ │ ├── packetextractor.js
│ │ ├── packetlinkfactory.js
│ │ ├── packetreassembler.js
│ │ ├── reassemblerfactory.js
│ │ ├── sizedefiner.js
│ │ ├── socket.js
│ │ ├── socketqueue.js
│ │ ├── spicechannel.js
│ │ └── websocketwrapper.js
│ ├── package.json
│ ├── process/
│ │ ├── Makefile.am
│ │ ├── busprocess.js
│ │ ├── cursorprocess.js
│ │ ├── displaypreprocess.js
│ │ ├── displayprocess.js
│ │ ├── inputprocess.js
│ │ ├── mainprocess.js
│ │ └── playbackprocess.js
│ ├── resources/
│ │ └── Makefile.am
│ ├── run.js
│ ├── sonar.properties
│ ├── spiceobjects/
│ │ ├── Makefile.am
│ │ ├── generated/
│ │ │ ├── Makefile.am
│ │ │ └── protocol.js
│ │ └── spiceobjects.js
│ ├── spiceproxy/
│ │ ├── .gitignore
│ │ ├── .npmignore
│ │ ├── Makefile.am
│ │ ├── concatenator.js
│ │ ├── filelist.js
│ │ ├── globalpool.js
│ │ ├── package.json
│ │ ├── socket.js
│ │ └── spicechannel.js
│ ├── swcanvas/
│ │ ├── Makefile.am
│ │ ├── benchmark.html
│ │ ├── swcanvas.js
│ │ └── test.html
│ └── unittest/
│ ├── application.test.js
│ ├── busconnection.test.js
│ ├── busprocess.test.js
│ ├── clientgui.test.js
│ ├── clusternodechooser.test.js
│ ├── collisiondetector.test.js
│ ├── connectioncontrol.test.js
│ ├── displayprocess.test.js
│ ├── displayrouter.test.js
│ ├── eventobject.test.js
│ ├── graphic.test.js
│ ├── graphictest.test.js
│ ├── graphictestfiles/
│ │ ├── SPICE_MSG_DISPLAY_DRAW_ALPHA_BLEND_login_page
│ │ ├── SPICE_MSG_DISPLAY_DRAW_BLACKNESS_login_page
│ │ ├── SPICE_MSG_DISPLAY_DRAW_COPY_-_JPEG_ALPHA
│ │ ├── SPICE_MSG_DISPLAY_DRAW_COPY_explorer_icon
│ │ ├── SPICE_MSG_DISPLAY_DRAW_COPY_start_button
│ │ ├── SPICE_MSG_DISPLAY_DRAW_COPY_user_icon_windows_menu
│ │ ├── SPICE_MSG_DISPLAY_DRAW_COPY_windows_menu
│ │ ├── SPICE_MSG_DISPLAY_DRAW_FILL
│ │ ├── SPICE_MSG_DISPLAY_DRAW_STROKE_libreoffice_tooltip
│ │ ├── SPICE_MSG_DISPLAY_DRAW_TEXT_login_page
│ │ └── uris.js
│ ├── imageuncompressor.test.js
│ ├── inputmanager.test.js
│ ├── keymap.test.js
│ ├── packetcontroller.test.js
│ ├── packetextractor.test.js
│ ├── packetfactory.test.js
│ ├── packetlinkfactory.test.js
│ ├── packetprocess.test.js
│ ├── packetreassembler.test.js
│ ├── queue.test.js
│ ├── reassemblerfactory.test.js
│ ├── runqueue.test.js
│ ├── sizedefiner.test.js
│ ├── socket.test.js
│ ├── socketqueue.test.js
│ ├── some.html
│ ├── spicechannel.test.js
│ ├── spiceconnection.test.js
│ ├── stuckkeyshandler.test.js
│ ├── syncasynchandler.test.js
│ ├── tests.js
│ ├── timelapsedetector.test.js
│ └── viewqueue.test.js
├── utils.py
├── vmtemplate.py
└── xmlutils/
├── Makefile.am
├── __init__.py
├── bootorder.py
├── cpu.py
├── disk.py
├── graphics.py
├── interface.py
├── network.py
├── qemucmdline.py
├── serial.py
└── usb.py
================================================
FILE CONTENTS
================================================
================================================
FILE: .flake8
================================================
[flake8]
ignore = E203, E266, E501, W503, W504, E741, C901
max-line-length = 88
max-complexity = 18
select = B,C,E,F,W,T4,B9,B950
================================================
FILE: .github/ISSUE_TEMPLATE/bug_report.md
================================================
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: ''
assignees: ''
---
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
**Expected behavior**
A clear and concise description of what you expected to happen.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**Desktop (please complete the following information):**
- OS: [e.g. Fedora 31, Ubuntu 19.10]
- Browser [e.g. chrome, safari]
- Version [e.g. 2.5, local@]
**Additional context**
Add any other context about the problem here.
================================================
FILE: .github/ISSUE_TEMPLATE/feature_request.md
================================================
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: ''
assignees: ''
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.
================================================
FILE: .github/pull_request_template.md
================================================
# Pull Request Template
## Description
Please, include a summary of the patch and why it should be accepted.
Link it to any open issue and share any other information and context you judge relevant for this PR.
Fixes # (issue)
## How Has This Been Tested?
Please, describe the tests that you ran to verify your changes. Provide instructions so we can reproduce.
- [ ] Test A
- [ ] Test B
## Checklist:
- [ ] My commit message follow the pattern described in [here](https://chris.beams.io/posts/git-commit/)
- [ ] I have signed-off my commit (git commit -s) to certify I have the rights to submit this work under the same license and agrees to a Developer Certificate of Origin (see http://developercertificate.org/ for more information).
- [ ] My code follows the style guidelines of this project and I have run `make check-local` to confirm it.
- [ ] I have run `make` to build the project and update any documentation that was added as part of this PR.
- [ ] I have performed a self-review of my own code
- [ ] I have commented my code, particularly in hard-to-understand areas
- [ ] I have added tests that prove my fix is effective or that my feature works
- [ ] New and existing unit tests pass locally with my changes (Run `make check` to confirm it)
================================================
FILE: .github/scripts/setup_instance.sh
================================================
#!/bin/bash
set -euxo pipefail
DISKS="gcloud compute disks"
IMAGES="gcloud compute images"
INSTANCES="gcloud compute instances"
VMX="https://compute.googleapis.com/compute/v1/projects/vm-options/global/licenses/enable-vmx"
DEFAULT_ZONE=us-central1-a
function createDisk() {
# Create disk
#
# $1: disk name
# $2: image project
# $3: image-family
# $4: zone
zone=${4:-$DEFAULT_ZONE}
diskName=$1
${DISKS} create $diskName \
--image-project $2 \
--image-family $3 \
--size 20GB \
--zone $zone
}
function createImage() {
# Create image with nested virtualization
#
# $1: image name
# $2: disk name
# $3: zone
zone=${3:-$DEFAULT_ZONE}
imageName=$1
${IMAGES} create $imageName \
--source-disk $2 \
--source-disk-zone $zone \
--licenses "${VMX}"
}
function createVM() {
# Create VM with nested virtualization
#
# $1: VM name
# $2: image name
# $3: zone
zone=${3:-$DEFAULT_ZONE}
instanceName=$1
${INSTANCES} create $1 \
--zone $zone \
--min-cpu-platform "Intel Haswell" \
--image $2
}
# Entrypoint
#
# $1: vm name
# $2: image project
# $3: image family
# $4: zone
vmName=$1
imageProject=$2
imageFamily=$3
zone=${4:-$DEFAULT_ZONE}
# create disk
diskName=$vmName-disk
createDisk $vmName-disk $imageProject $imageFamily $zone
# create image
imageName=$vmName-image
createImage $imageName $diskName $zone
# create vm
createVM $1 $imageName $zone
================================================
FILE: .github/scripts/setup_kimchi_ubuntu.sh
================================================
#!/bin/bash
set -euxo pipefail
function get_deps() {
echo $(python3 -c "import yaml;print(' '.join(yaml.load(open('dependencies.yaml'), Loader=yaml.FullLoader)[\"$1\"][\"$2\"]))")
}
# install deps
sudo apt update
sudo apt install -y python3-pip
sudo apt install -y $(get_deps development-deps common)
sudo apt install -y $(get_deps development-deps ubuntu)
sudo apt install -y $(get_deps runtime-deps common)
sudo apt install -y $(get_deps runtime-deps ubuntu | sed 's/python3-cheetah//')
pip3 install -r requirements-UBUNTU.txt
pip3 install -r requirements-dev.txt
# autogen and make
./autogen.sh --system
make
================================================
FILE: .github/workflows/CI.yml
================================================
name: kimchi-CI
on: ["push"]
env:
VM_NAME: ubuntu-${{ github.sha }}
ZONE: us-central1-a
PROJECT_ID: ${{ secrets.GCP_PROJECT }}
WOK_DIR: wok
KIMCHI_DIR: wok/src/wok/plugins/kimchi/
jobs:
run-kimchi-tests:
runs-on: ubuntu-latest
steps:
- uses: GoogleCloudPlatform/github-actions/setup-gcloud@master
with:
version: '270.0.0'
service_account_email: ${{ secrets.GCP_SA_EMAIL }}
service_account_key: ${{ secrets.GCP_SA_KEY }}
- run: gcloud config set project $PROJECT_ID
- uses: actions/checkout@v2-beta
- name: create instance
run: bash .github/scripts/setup_instance.sh $VM_NAME ubuntu-os-cloud ubuntu-1804-lts
shell: bash
- name: checkout repos
run: |
gcloud compute ssh $VM_NAME --zone=$ZONE --command "git clone https://github.com/kimchi-project/wok"
gcloud compute ssh $VM_NAME --zone=$ZONE --command "git clone https://github.com/$GITHUB_REPOSITORY $KIMCHI_DIR"
gcloud compute ssh $VM_NAME --zone=$ZONE --command "cd $KIMCHI_DIR; git checkout $GITHUB_SHA"
shell: bash
- name: setup wok deps
run: |
gcloud compute ssh $VM_NAME --zone=$ZONE --command "cd $WOK_DIR; bash .github/scripts/setup_wok_ubuntu.sh"
shell: bash
- name: setup kimchi deps
run: gcloud compute ssh $VM_NAME --zone=$ZONE --command "cd $KIMCHI_DIR; bash .github/scripts/setup_kimchi_ubuntu.sh"
shell: bash
- name: run tests
run: gcloud compute ssh $VM_NAME --zone=$ZONE --command "cd $KIMCHI_DIR; sudo make check-local; sudo make check"
shell: bash
- name: Cleanup instance
if: always()
run: |
gcloud compute instances delete ${VM_NAME} --delete-disks=all --zone=$ZONE -q || true
gcloud compute images delete ${VM_NAME}-image -q || true
gcloud compute disks delete ${VM_NAME}-disk --zone=$ZONE -q || true
shell: bash
================================================
FILE: .gitignore
================================================
*.pyc
*~
*.list
i18n/mo/*
log
data
mo
autom4te.cache
Makefile
Makefile.in
aclocal.m4
m4/pkg.m4
build-aux/compile
build-aux/config.guess
build-aux/config.sub
build-aux/install-sh
build-aux/missing
build-aux/py-compile
build-aux/*-pkg-deps
configure
config.log
config.py
config.status
contrib/DEBIAN/control
contrib/kimchi.spec.fedora
contrib/kimchi.spec.suse
contrib/make-deb.sh
*.min.css
*.min.js
*.gmo
stamp-po
kimchi-*.tar.gz
tests/run_tests.sh
tests/test_config.py
po/POTFILES
po/gen-pot
*.orig
*.rej
*.pem
ui/pages/help/*/*.html
================================================
FILE: .pre-commit-config.yaml
================================================
# Pre-commit git hooks, run locally before every commit
# Init with
# $ pip install -r requirements-dev.txt
# $ pre-commit install
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v2.1.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
exclude: '\.list$'
#- id: check-docstring-first
- id: check-json
#- id: check-added-large-files
- id: check-yaml
- id: debug-statements
#- id: name-tests-test
- id: double-quote-string-fixer
- id: requirements-txt-fixer
- repo: https://gitlab.com/pycqa/flake8
rev: 3.7.1
hooks:
- id: flake8
- repo: https://github.com/pre-commit/mirrors-autopep8
rev: v1.4.4
hooks:
- id: autopep8
- repo: https://github.com/asottile/reorder_python_imports
rev: v1.3.5
hooks:
- id: reorder-python-imports
language_version: python3
================================================
FILE: ABOUT-NLS
================================================
1 Notes on the Free Translation Project
***************************************
Free software is going international! The Free Translation Project is
a way to get maintainers of free software, translators, and users all
together, so that free software will gradually become able to speak many
languages. A few packages already provide translations for their
messages.
If you found this `ABOUT-NLS' file inside a distribution, you may
assume that the distributed package does use GNU `gettext' internally,
itself available at your nearest GNU archive site. But you do _not_
need to install GNU `gettext' prior to configuring, installing or using
this package with messages translated.
Installers will find here some useful hints. These notes also
explain how users should proceed for getting the programs to use the
available translations. They tell how people wanting to contribute and
work on translations can contact the appropriate team.
1.1 INSTALL Matters
===================
Some packages are "localizable" when properly installed; the programs
they contain can be made to speak your own native language. Most such
packages use GNU `gettext'. Other packages have their own ways to
internationalization, predating GNU `gettext'.
By default, this package will be installed to allow translation of
messages. It will automatically detect whether the system already
provides the GNU `gettext' functions. Installers may use special
options at configuration time for changing the default behaviour. The
command:
./configure --disable-nls
will _totally_ disable translation of messages.
When you already have GNU `gettext' installed on your system and run
configure without an option for your new package, `configure' will
probably detect the previously built and installed `libintl' library
and will decide to use it. If not, you may have to to use the
`--with-libintl-prefix' option to tell `configure' where to look for it.
Internationalized packages usually have many `po/LL.po' files, where
LL gives an ISO 639 two-letter code identifying the language. Unless
translations have been forbidden at `configure' time by using the
`--disable-nls' switch, all available translations are installed
together with the package. However, the environment variable `LINGUAS'
may be set, prior to configuration, to limit the installed set.
`LINGUAS' should then contain a space separated list of two-letter
codes, stating which languages are allowed.
1.2 Using This Package
======================
As a user, if your language has been installed for this package, you
only have to set the `LANG' environment variable to the appropriate
`LL_CC' combination. If you happen to have the `LC_ALL' or some other
`LC_xxx' environment variables set, you should unset them before
setting `LANG', otherwise the setting of `LANG' will not have the
desired effect. Here `LL' is an ISO 639 two-letter language code, and
`CC' is an ISO 3166 two-letter country code. For example, let's
suppose that you speak German and live in Germany. At the shell
prompt, merely execute `setenv LANG de_DE' (in `csh'),
`export LANG; LANG=de_DE' (in `sh') or `export LANG=de_DE' (in `bash').
This can be done from your `.login' or `.profile' file, once and for
all.
You might think that the country code specification is redundant.
But in fact, some languages have dialects in different countries. For
example, `de_AT' is used for Austria, and `pt_BR' for Brazil. The
country code serves to distinguish the dialects.
The locale naming convention of `LL_CC', with `LL' denoting the
language and `CC' denoting the country, is the one use on systems based
on GNU libc. On other systems, some variations of this scheme are
used, such as `LL' or `LL_CC.ENCODING'. You can get the list of
locales supported by your system for your language by running the
command `locale -a | grep '^LL''.
Not all programs have translations for all languages. By default, an
English message is shown in place of a nonexistent translation. If you
understand other languages, you can set up a priority list of languages.
This is done through a different environment variable, called
`LANGUAGE'. GNU `gettext' gives preference to `LANGUAGE' over `LANG'
for the purpose of message handling, but you still need to have `LANG'
set to the primary language; this is required by other parts of the
system libraries. For example, some Swedish users who would rather
read translations in German than English for when Swedish is not
available, set `LANGUAGE' to `sv:de' while leaving `LANG' to `sv_SE'.
Special advice for Norwegian users: The language code for Norwegian
bokma*l changed from `no' to `nb' recently (in 2003). During the
transition period, while some message catalogs for this language are
installed under `nb' and some older ones under `no', it's recommended
for Norwegian users to set `LANGUAGE' to `nb:no' so that both newer and
older translations are used.
In the `LANGUAGE' environment variable, but not in the `LANG'
environment variable, `LL_CC' combinations can be abbreviated as `LL'
to denote the language's main dialect. For example, `de' is equivalent
to `de_DE' (German as spoken in Germany), and `pt' to `pt_PT'
(Portuguese as spoken in Portugal) in this context.
1.3 Translating Teams
=====================
For the Free Translation Project to be a success, we need interested
people who like their own language and write it well, and who are also
able to synergize with other translators speaking the same language.
Each translation team has its own mailing list. The up-to-date list of
teams can be found at the Free Translation Project's homepage,
`http://translationproject.org/', in the "Teams" area.
If you'd like to volunteer to _work_ at translating messages, you
should become a member of the translating team for your own language.
The subscribing address is _not_ the same as the list itself, it has
`-request' appended. For example, speakers of Swedish can send a
message to `sv-request@li.org', having this message body:
subscribe
Keep in mind that team members are expected to participate
_actively_ in translations, or at solving translational difficulties,
rather than merely lurking around. If your team does not exist yet and
you want to start one, or if you are unsure about what to do or how to
get started, please write to `coordinator@translationproject.org' to
reach the coordinator for all translator teams.
The English team is special. It works at improving and uniformizing
the terminology in use. Proven linguistic skills are praised more than
programming skills, here.
1.4 Available Packages
======================
Languages are not equally supported in all packages. The following
matrix shows the current state of internationalization, as of June
2010. The matrix shows, in regard of each package, for which languages
PO files have been submitted to translation coordination, with a
translation percentage of at least 50%.
Ready PO files af am an ar as ast az be be@latin bg bn_IN bs ca
+--------------------------------------------------+
a2ps | [] [] |
aegis | |
ant-phone | |
anubis | |
aspell | [] [] |
bash | |
bfd | |
bibshelf | [] |
binutils | |
bison | |
bison-runtime | [] |
bluez-pin | [] [] |
bombono-dvd | |
buzztard | |
cflow | |
clisp | |
coreutils | [] [] |
cpio | |
cppi | |
cpplib | [] |
cryptsetup | |
dfarc | |
dialog | [] [] |
dico | |
diffutils | [] |
dink | |
doodle | |
e2fsprogs | [] |
enscript | [] |
exif | |
fetchmail | [] |
findutils | [] |
flex | [] |
freedink | |
gas | |
gawk | [] [] |
gcal | [] |
gcc | |
gettext-examples | [] [] [] [] |
gettext-runtime | [] [] |
gettext-tools | [] [] |
gip | [] |
gjay | |
gliv | [] |
glunarclock | [] [] |
gnubiff | |
gnucash | [] |
gnuedu | |
gnulib | |
gnunet | |
gnunet-gtk | |
gnutls | |
gold | |
gpe-aerial | |
gpe-beam | |
gpe-bluetooth | |
gpe-calendar | |
gpe-clock | [] |
gpe-conf | |
gpe-contacts | |
gpe-edit | |
gpe-filemanager | |
gpe-go | |
gpe-login | |
gpe-ownerinfo | [] |
gpe-package | |
gpe-sketchbook | |
gpe-su | [] |
gpe-taskmanager | [] |
gpe-timesheet | [] |
gpe-today | [] |
gpe-todo | |
gphoto2 | |
gprof | [] |
gpsdrive | |
gramadoir | |
grep | |
grub | [] [] |
gsasl | |
gss | |
gst-plugins-bad | [] |
gst-plugins-base | [] |
gst-plugins-good | [] |
gst-plugins-ugly | [] |
gstreamer | [] [] [] |
gtick | |
gtkam | [] |
gtkorphan | [] |
gtkspell | [] [] [] |
gutenprint | |
hello | [] |
help2man | |
hylafax | |
idutils | |
indent | [] [] |
iso_15924 | |
iso_3166 | [] [] [] [] [] [] [] |
iso_3166_2 | |
iso_4217 | |
iso_639 | [] [] [] [] |
iso_639_3 | |
jwhois | |
kbd | |
keytouch | [] |
keytouch-editor | |
keytouch-keyboa... | [] |
klavaro | [] |
latrine | |
ld | [] |
leafpad | [] [] |
libc | [] [] |
libexif | () |
libextractor | |
libgnutls | |
libgpewidget | |
libgpg-error | |
libgphoto2 | |
libgphoto2_port | |
libgsasl | |
libiconv | [] |
libidn | |
lifelines | |
liferea | [] [] |
lilypond | |
linkdr | [] |
lordsawar | |
lprng | |
lynx | [] |
m4 | |
mailfromd | |
mailutils | |
make | |
man-db | |
man-db-manpages | |
minicom | |
mkisofs | |
myserver | |
nano | [] [] |
opcodes | |
parted | |
pies | |
popt | |
psmisc | |
pspp | [] |
pwdutils | |
radius | [] |
recode | [] [] |
rosegarden | |
rpm | |
rush | |
sarg | |
screem | |
scrollkeeper | [] [] [] |
sed | [] [] |
sharutils | [] [] |
shishi | |
skencil | |
solfege | |
solfege-manual | |
soundtracker | |
sp | |
sysstat | |
tar | [] |
texinfo | |
tin | |
unicode-han-tra... | |
unicode-transla... | |
util-linux-ng | [] |
vice | |
vmm | |
vorbis-tools | |
wastesedge | |
wdiff | |
wget | [] [] |
wyslij-po | |
xchat | [] [] [] [] |
xdg-user-dirs | [] [] [] [] [] [] [] [] [] |
xkeyboard-config | [] [] |
+--------------------------------------------------+
af am an ar as ast az be be@latin bg bn_IN bs ca
6 0 1 2 3 19 1 10 3 28 3 1 38
crh cs da de el en en_GB en_ZA eo es et eu fa
+-------------------------------------------------+
a2ps | [] [] [] [] [] [] [] |
aegis | [] [] [] |
ant-phone | [] () |
anubis | [] [] |
aspell | [] [] [] [] [] |
bash | [] [] [] |
bfd | [] |
bibshelf | [] [] [] |
binutils | [] |
bison | [] [] |
bison-runtime | [] [] [] [] |
bluez-pin | [] [] [] [] [] [] |
bombono-dvd | [] |
buzztard | [] [] [] |
cflow | [] [] |
clisp | [] [] [] [] |
coreutils | [] [] [] [] |
cpio | |
cppi | |
cpplib | [] [] [] |
cryptsetup | [] |
dfarc | [] [] [] |
dialog | [] [] [] [] [] |
dico | |
diffutils | [] [] [] [] [] [] |
dink | [] [] [] |
doodle | [] |
e2fsprogs | [] [] [] |
enscript | [] [] [] |
exif | () [] [] |
fetchmail | [] [] () [] [] [] |
findutils | [] [] [] |
flex | [] [] |
freedink | [] [] [] |
gas | [] |
gawk | [] [] [] |
gcal | [] |
gcc | [] [] |
gettext-examples | [] [] [] [] |
gettext-runtime | [] [] [] [] |
gettext-tools | [] [] [] |
gip | [] [] [] [] |
gjay | [] |
gliv | [] [] [] |
glunarclock | [] [] |
gnubiff | () |
gnucash | [] () () () () |
gnuedu | [] [] |
gnulib | [] [] |
gnunet | |
gnunet-gtk | [] |
gnutls | [] [] |
gold | [] |
gpe-aerial | [] [] [] [] |
gpe-beam | [] [] [] [] |
gpe-bluetooth | [] [] |
gpe-calendar | [] |
gpe-clock | [] [] [] [] |
gpe-conf | [] [] [] |
gpe-contacts | [] [] [] |
gpe-edit | [] [] |
gpe-filemanager | [] [] [] |
gpe-go | [] [] [] [] |
gpe-login | [] [] |
gpe-ownerinfo | [] [] [] [] |
gpe-package | [] [] [] |
gpe-sketchbook | [] [] [] [] |
gpe-su | [] [] [] [] |
gpe-taskmanager | [] [] [] [] |
gpe-timesheet | [] [] [] [] |
gpe-today | [] [] [] [] |
gpe-todo | [] [] [] |
gphoto2 | [] [] () [] [] [] |
gprof | [] [] [] |
gpsdrive | [] [] [] |
gramadoir | [] [] [] |
grep | [] |
grub | [] [] |
gsasl | [] |
gss | |
gst-plugins-bad | [] [] [] [] [] |
gst-plugins-base | [] [] [] [] [] |
gst-plugins-good | [] [] [] [] [] [] |
gst-plugins-ugly | [] [] [] [] [] [] |
gstreamer | [] [] [] [] [] |
gtick | [] () [] |
gtkam | [] [] () [] [] |
gtkorphan | [] [] [] [] |
gtkspell | [] [] [] [] [] [] [] |
gutenprint | [] [] [] |
hello | [] [] [] [] |
help2man | [] |
hylafax | [] [] |
idutils | [] [] |
indent | [] [] [] [] [] [] [] |
iso_15924 | [] () [] [] |
iso_3166 | [] [] [] [] () [] [] [] () |
iso_3166_2 | () |
iso_4217 | [] [] [] () [] [] |
iso_639 | [] [] [] [] () [] [] |
iso_639_3 | [] |
jwhois | [] |
kbd | [] [] [] [] [] |
keytouch | [] [] |
keytouch-editor | [] [] |
keytouch-keyboa... | [] |
klavaro | [] [] [] [] |
latrine | [] () |
ld | [] [] |
leafpad | [] [] [] [] [] [] |
libc | [] [] [] [] |
libexif | [] [] () |
libextractor | |
libgnutls | [] |
libgpewidget | [] [] |
libgpg-error | [] [] |
libgphoto2 | [] () |
libgphoto2_port | [] () [] |
libgsasl | |
libiconv | [] [] [] [] [] |
libidn | [] [] [] |
lifelines | [] () |
liferea | [] [] [] [] [] |
lilypond | [] [] [] |
linkdr | [] [] [] |
lordsawar | [] |
lprng | |
lynx | [] [] [] [] |
m4 | [] [] [] [] |
mailfromd | |
mailutils | [] |
make | [] [] [] |
man-db | |
man-db-manpages | |
minicom | [] [] [] [] |
mkisofs | |
myserver | |
nano | [] [] [] |
opcodes | [] [] |
parted | [] [] |
pies | |
popt | [] [] [] [] [] |
psmisc | [] [] [] |
pspp | [] |
pwdutils | [] |
radius | [] |
recode | [] [] [] [] [] [] |
rosegarden | () () () |
rpm | [] [] [] |
rush | |
sarg | |
screem | |
scrollkeeper | [] [] [] [] [] |
sed | [] [] [] [] [] [] |
sharutils | [] [] [] [] |
shishi | |
skencil | [] () [] |
solfege | [] [] [] |
solfege-manual | [] [] |
soundtracker | [] [] [] |
sp | [] |
sysstat | [] [] [] |
tar | [] [] [] [] |
texinfo | [] [] [] |
tin | [] [] |
unicode-han-tra... | |
unicode-transla... | |
util-linux-ng | [] [] [] [] |
vice | () () |
vmm | [] |
vorbis-tools | [] [] |
wastesedge | [] |
wdiff | [] [] |
wget | [] [] [] |
wyslij-po | |
xchat | [] [] [] [] [] |
xdg-user-dirs | [] [] [] [] [] [] [] [] [] |
xkeyboard-config | [] [] [] [] [] [] |
+-------------------------------------------------+
crh cs da de el en en_GB en_ZA eo es et eu fa
5 64 105 117 18 1 8 0 28 89 18 19 0
fi fr ga gl gu he hi hr hu hy id is it ja ka kn
+----------------------------------------------------+
a2ps | [] [] [] [] |
aegis | [] [] |
ant-phone | [] [] |
anubis | [] [] [] [] |
aspell | [] [] [] [] |
bash | [] [] [] [] |
bfd | [] [] [] |
bibshelf | [] [] [] [] [] |
binutils | [] [] [] |
bison | [] [] [] [] |
bison-runtime | [] [] [] [] [] [] |
bluez-pin | [] [] [] [] [] [] [] [] |
bombono-dvd | [] |
buzztard | [] |
cflow | [] [] [] |
clisp | [] |
coreutils | [] [] [] [] [] |
cpio | [] [] [] [] |
cppi | [] [] |
cpplib | [] [] [] |
cryptsetup | [] [] [] |
dfarc | [] [] [] |
dialog | [] [] [] [] [] [] [] |
dico | |
diffutils | [] [] [] [] [] [] [] [] [] |
dink | [] |
doodle | [] [] |
e2fsprogs | [] [] |
enscript | [] [] [] [] |
exif | [] [] [] [] [] [] |
fetchmail | [] [] [] [] |
findutils | [] [] [] [] [] [] |
flex | [] [] [] |
freedink | [] [] [] |
gas | [] [] |
gawk | [] [] [] [] () [] |
gcal | [] |
gcc | [] |
gettext-examples | [] [] [] [] [] [] [] |
gettext-runtime | [] [] [] [] [] [] |
gettext-tools | [] [] [] [] |
gip | [] [] [] [] [] [] |
gjay | [] |
gliv | [] () |
glunarclock | [] [] [] [] |
gnubiff | () [] () |
gnucash | () () () () () [] |
gnuedu | [] [] |
gnulib | [] [] [] [] [] [] |
gnunet | |
gnunet-gtk | [] |
gnutls | [] [] |
gold | [] [] |
gpe-aerial | [] [] [] |
gpe-beam | [] [] [] [] |
gpe-bluetooth | [] [] [] [] |
gpe-calendar | [] [] |
gpe-clock | [] [] [] [] [] |
gpe-conf | [] [] [] [] |
gpe-contacts | [] [] [] [] |
gpe-edit | [] [] [] |
gpe-filemanager | [] [] [] [] |
gpe-go | [] [] [] [] [] |
gpe-login | [] [] [] |
gpe-ownerinfo | [] [] [] [] [] |
gpe-package | [] [] [] |
gpe-sketchbook | [] [] [] [] |
gpe-su | [] [] [] [] [] [] |
gpe-taskmanager | [] [] [] [] [] |
gpe-timesheet | [] [] [] [] [] |
gpe-today | [] [] [] [] [] [] [] |
gpe-todo | [] [] [] |
gphoto2 | [] [] [] [] [] [] |
gprof | [] [] [] [] |
gpsdrive | [] [] [] |
gramadoir | [] [] [] |
grep | [] [] |
grub | [] [] [] [] |
gsasl | [] [] [] [] [] |
gss | [] [] [] [] [] |
gst-plugins-bad | [] [] [] [] [] [] |
gst-plugins-base | [] [] [] [] [] [] |
gst-plugins-good | [] [] [] [] [] [] |
gst-plugins-ugly | [] [] [] [] [] [] |
gstreamer | [] [] [] [] [] |
gtick | [] [] [] [] [] |
gtkam | [] [] [] [] [] |
gtkorphan | [] [] [] |
gtkspell | [] [] [] [] [] [] [] [] [] |
gutenprint | [] [] [] [] |
hello | [] [] [] |
help2man | [] [] |
hylafax | [] |
idutils | [] [] [] [] [] [] |
indent | [] [] [] [] [] [] [] [] |
iso_15924 | [] () [] [] |
iso_3166 | [] () [] [] [] [] [] [] [] [] [] [] |
iso_3166_2 | () [] [] [] |
iso_4217 | [] () [] [] [] [] |
iso_639 | [] () [] [] [] [] [] [] [] |
iso_639_3 | () [] [] |
jwhois | [] [] [] [] [] |
kbd | [] [] |
keytouch | [] [] [] [] [] [] |
keytouch-editor | [] [] [] [] [] |
keytouch-keyboa... | [] [] [] [] [] |
klavaro | [] [] |
latrine | [] [] [] |
ld | [] [] [] [] |
leafpad | [] [] [] [] [] [] [] () |
libc | [] [] [] [] [] |
libexif | [] |
libextractor | |
libgnutls | [] [] |
libgpewidget | [] [] [] [] |
libgpg-error | [] [] |
libgphoto2 | [] [] [] |
libgphoto2_port | [] [] [] |
libgsasl | [] [] [] [] [] |
libiconv | [] [] [] [] [] [] |
libidn | [] [] [] [] |
lifelines | () |
liferea | [] [] [] [] |
lilypond | [] [] |
linkdr | [] [] [] [] [] |
lordsawar | |
lprng | [] |
lynx | [] [] [] [] [] |
m4 | [] [] [] [] [] [] |
mailfromd | |
mailutils | [] [] |
make | [] [] [] [] [] [] [] [] [] |
man-db | [] [] |
man-db-manpages | [] |
minicom | [] [] [] [] [] |
mkisofs | [] [] [] [] |
myserver | |
nano | [] [] [] [] [] [] |
opcodes | [] [] [] [] |
parted | [] [] [] [] |
pies | |
popt | [] [] [] [] [] [] [] [] [] |
psmisc | [] [] [] |
pspp | |
pwdutils | [] [] |
radius | [] [] |
recode | [] [] [] [] [] [] [] [] |
rosegarden | () () () () () |
rpm | [] [] |
rush | |
sarg | [] |
screem | [] [] |
scrollkeeper | [] [] [] [] |
sed | [] [] [] [] [] [] [] [] |
sharutils | [] [] [] [] [] [] [] |
shishi | [] |
skencil | [] |
solfege | [] [] [] [] |
solfege-manual | [] [] |
soundtracker | [] [] |
sp | [] () |
sysstat | [] [] [] [] [] |
tar | [] [] [] [] [] [] [] |
texinfo | [] [] [] [] |
tin | [] |
unicode-han-tra... | |
unicode-transla... | [] [] |
util-linux-ng | [] [] [] [] [] [] |
vice | () () () |
vmm | [] |
vorbis-tools | [] |
wastesedge | () () |
wdiff | [] |
wget | [] [] [] [] [] [] [] [] |
wyslij-po | [] [] [] |
xchat | [] [] [] [] [] [] [] [] [] |
xdg-user-dirs | [] [] [] [] [] [] [] [] [] [] [] [] [] |
xkeyboard-config | [] [] [] [] [] |
+----------------------------------------------------+
fi fr ga gl gu he hi hr hu hy id is it ja ka kn
105 121 53 20 4 8 3 5 53 2 120 5 84 67 0 4
ko ku ky lg lt lv mk ml mn mr ms mt nb nds ne
+-----------------------------------------------+
a2ps | [] |
aegis | |
ant-phone | |
anubis | [] [] |
aspell | [] |
bash | |
bfd | |
bibshelf | [] [] |
binutils | |
bison | [] |
bison-runtime | [] [] [] [] [] |
bluez-pin | [] [] [] [] [] |
bombono-dvd | |
buzztard | |
cflow | |
clisp | |
coreutils | [] |
cpio | |
cppi | |
cpplib | |
cryptsetup | |
dfarc | [] |
dialog | [] [] [] [] [] |
dico | |
diffutils | [] [] |
dink | |
doodle | |
e2fsprogs | |
enscript | |
exif | [] |
fetchmail | |
findutils | |
flex | |
freedink | [] |
gas | |
gawk | |
gcal | |
gcc | |
gettext-examples | [] [] [] [] |
gettext-runtime | [] |
gettext-tools | [] |
gip | [] [] |
gjay | |
gliv | |
glunarclock | [] |
gnubiff | |
gnucash | () () () () |
gnuedu | |
gnulib | |
gnunet | |
gnunet-gtk | |
gnutls | [] |
gold | |
gpe-aerial | [] |
gpe-beam | [] |
gpe-bluetooth | [] [] |
gpe-calendar | [] |
gpe-clock | [] [] [] [] [] |
gpe-conf | [] [] |
gpe-contacts | [] [] |
gpe-edit | [] |
gpe-filemanager | [] [] |
gpe-go | [] [] [] |
gpe-login | [] |
gpe-ownerinfo | [] [] |
gpe-package | [] [] |
gpe-sketchbook | [] [] |
gpe-su | [] [] [] [] [] [] |
gpe-taskmanager | [] [] [] [] [] [] |
gpe-timesheet | [] [] |
gpe-today | [] [] [] [] |
gpe-todo | [] [] |
gphoto2 | |
gprof | [] |
gpsdrive | |
gramadoir | |
grep | |
grub | |
gsasl | |
gss | |
gst-plugins-bad | [] [] [] [] |
gst-plugins-base | [] [] |
gst-plugins-good | [] [] |
gst-plugins-ugly | [] [] [] [] [] |
gstreamer | |
gtick | |
gtkam | [] |
gtkorphan | [] [] |
gtkspell | [] [] [] [] [] [] [] |
gutenprint | |
hello | [] [] [] |
help2man | |
hylafax | |
idutils | |
indent | |
iso_15924 | [] [] |
iso_3166 | [] [] () [] [] [] [] [] |
iso_3166_2 | |
iso_4217 | [] [] |
iso_639 | [] [] |
iso_639_3 | [] |
jwhois | [] |
kbd | |
keytouch | [] |
keytouch-editor | [] |
keytouch-keyboa... | [] |
klavaro | [] |
latrine | [] |
ld | |
leafpad | [] [] [] |
libc | [] |
libexif | |
libextractor | |
libgnutls | [] |
libgpewidget | [] [] |
libgpg-error | |
libgphoto2 | |
libgphoto2_port | |
libgsasl | |
libiconv | |
libidn | |
lifelines | |
liferea | |
lilypond | |
linkdr | |
lordsawar | |
lprng | |
lynx | |
m4 | |
mailfromd | |
mailutils | |
make | [] |
man-db | |
man-db-manpages | |
minicom | [] |
mkisofs | |
myserver | |
nano | [] [] |
opcodes | |
parted | |
pies | |
popt | [] [] [] |
psmisc | |
pspp | |
pwdutils | |
radius | |
recode | |
rosegarden | |
rpm | |
rush | |
sarg | |
screem | |
scrollkeeper | [] [] |
sed | |
sharutils | |
shishi | |
skencil | |
solfege | [] |
solfege-manual | |
soundtracker | |
sp | |
sysstat | [] |
tar | [] |
texinfo | [] |
tin | |
unicode-han-tra... | |
unicode-transla... | |
util-linux-ng | |
vice | |
vmm | |
vorbis-tools | |
wastesedge | |
wdiff | |
wget | [] |
wyslij-po | |
xchat | [] [] [] |
xdg-user-dirs | [] [] [] [] [] [] [] [] |
xkeyboard-config | [] [] [] |
+-----------------------------------------------+
ko ku ky lg lt lv mk ml mn mr ms mt nb nds ne
20 5 10 1 13 48 4 2 2 4 24 10 20 3 1
nl nn or pa pl ps pt pt_BR ro ru rw sk sl sq sr
+---------------------------------------------------+
a2ps | [] [] [] [] [] [] [] [] |
aegis | [] [] [] |
ant-phone | [] [] |
anubis | [] [] [] |
aspell | [] [] [] [] [] |
bash | [] [] |
bfd | [] |
bibshelf | [] [] |
binutils | [] [] |
bison | [] [] [] |
bison-runtime | [] [] [] [] [] [] [] |
bluez-pin | [] [] [] [] [] [] [] [] |
bombono-dvd | [] () |
buzztard | [] [] |
cflow | [] |
clisp | [] [] |
coreutils | [] [] [] [] [] [] |
cpio | [] [] [] |
cppi | [] |
cpplib | [] |
cryptsetup | [] |
dfarc | [] |
dialog | [] [] [] [] |
dico | [] |
diffutils | [] [] [] [] [] [] |
dink | () |
doodle | [] [] |
e2fsprogs | [] [] |
enscript | [] [] [] [] [] |
exif | [] [] [] () [] |
fetchmail | [] [] [] [] |
findutils | [] [] [] [] [] |
flex | [] [] [] [] [] |
freedink | [] [] |
gas | |
gawk | [] [] [] [] |
gcal | |
gcc | [] |
gettext-examples | [] [] [] [] [] [] [] [] |
gettext-runtime | [] [] [] [] [] [] [] [] [] |
gettext-tools | [] [] [] [] [] [] |
gip | [] [] [] [] [] |
gjay | |
gliv | [] [] [] [] [] [] |
glunarclock | [] [] [] [] [] |
gnubiff | [] () |
gnucash | [] () () () |
gnuedu | [] |
gnulib | [] [] [] [] |
gnunet | |
gnunet-gtk | |
gnutls | [] [] |
gold | |
gpe-aerial | [] [] [] [] [] [] [] |
gpe-beam | [] [] [] [] [] [] [] |
gpe-bluetooth | [] [] |
gpe-calendar | [] [] [] [] |
gpe-clock | [] [] [] [] [] [] [] [] |
gpe-conf | [] [] [] [] [] [] [] |
gpe-contacts | [] [] [] [] [] |
gpe-edit | [] [] [] |
gpe-filemanager | [] [] [] |
gpe-go | [] [] [] [] [] [] [] [] |
gpe-login | [] [] |
gpe-ownerinfo | [] [] [] [] [] [] [] [] |
gpe-package | [] [] |
gpe-sketchbook | [] [] [] [] [] [] [] |
gpe-su | [] [] [] [] [] [] [] [] |
gpe-taskmanager | [] [] [] [] [] [] [] [] |
gpe-timesheet | [] [] [] [] [] [] [] [] |
gpe-today | [] [] [] [] [] [] [] [] |
gpe-todo | [] [] [] [] [] |
gphoto2 | [] [] [] [] [] [] [] [] |
gprof | [] [] [] |
gpsdrive | [] [] |
gramadoir | [] [] |
grep | [] [] [] [] |
grub | [] [] [] |
gsasl | [] [] [] [] |
gss | [] [] [] |
gst-plugins-bad | [] [] [] [] [] [] |
gst-plugins-base | [] [] [] [] [] |
gst-plugins-good | [] [] [] [] [] |
gst-plugins-ugly | [] [] [] [] [] [] |
gstreamer | [] [] [] [] [] |
gtick | [] [] [] |
gtkam | [] [] [] [] [] [] |
gtkorphan | [] |
gtkspell | [] [] [] [] [] [] [] [] [] [] |
gutenprint | [] [] |
hello | [] [] [] [] |
help2man | [] [] |
hylafax | [] |
idutils | [] [] [] [] [] |
indent | [] [] [] [] [] [] [] |
iso_15924 | [] [] [] [] |
iso_3166 | [] [] [] [] [] () [] [] [] [] [] [] [] [] |
iso_3166_2 | [] [] [] |
iso_4217 | [] [] [] [] [] [] [] [] |
iso_639 | [] [] [] [] [] [] [] [] [] |
iso_639_3 | [] [] |
jwhois | [] [] [] [] |
kbd | [] [] [] |
keytouch | [] [] [] |
keytouch-editor | [] [] [] |
keytouch-keyboa... | [] [] [] |
klavaro | [] [] |
latrine | [] [] |
ld | |
leafpad | [] [] [] [] [] [] [] [] [] |
libc | [] [] [] [] |
libexif | [] [] () [] |
libextractor | |
libgnutls | [] [] |
libgpewidget | [] [] [] |
libgpg-error | [] [] |
libgphoto2 | [] [] |
libgphoto2_port | [] [] [] [] [] |
libgsasl | [] [] [] [] [] |
libiconv | [] [] [] [] [] |
libidn | [] [] |
lifelines | [] [] |
liferea | [] [] [] [] [] () () [] |
lilypond | [] |
linkdr | [] [] [] |
lordsawar | |
lprng | [] |
lynx | [] [] [] |
m4 | [] [] [] [] [] |
mailfromd | [] |
mailutils | [] |
make | [] [] [] [] |
man-db | [] [] [] |
man-db-manpages | [] [] [] |
minicom | [] [] [] [] |
mkisofs | [] [] [] |
myserver | |
nano | [] [] [] [] |
opcodes | [] [] |
parted | [] [] [] [] |
pies | [] |
popt | [] [] [] [] |
psmisc | [] [] [] |
pspp | [] [] |
pwdutils | [] |
radius | [] [] [] |
recode | [] [] [] [] [] [] [] [] |
rosegarden | () () |
rpm | [] [] [] |
rush | [] [] |
sarg | |
screem | |
scrollkeeper | [] [] [] [] [] [] [] [] |
sed | [] [] [] [] [] [] [] [] [] |
sharutils | [] [] [] [] |
shishi | [] |
skencil | [] [] |
solfege | [] [] [] [] |
solfege-manual | [] [] [] |
soundtracker | [] |
sp | |
sysstat | [] [] [] [] |
tar | [] [] [] [] |
texinfo | [] [] [] [] |
tin | [] |
unicode-han-tra... | |
unicode-transla... | |
util-linux-ng | [] [] [] [] [] |
vice | [] |
vmm | [] |
vorbis-tools | [] [] |
wastesedge | [] |
wdiff | [] [] |
wget | [] [] [] [] [] [] [] |
wyslij-po | [] [] [] |
xchat | [] [] [] [] [] [] [] [] [] |
xdg-user-dirs | [] [] [] [] [] [] [] [] [] [] [] [] [] [] |
xkeyboard-config | [] [] [] |
+---------------------------------------------------+
nl nn or pa pl ps pt pt_BR ro ru rw sk sl sq sr
135 10 4 7 105 1 29 62 47 91 3 54 46 9 37
sv sw ta te tg th tr uk vi wa zh_CN zh_HK zh_TW
+---------------------------------------------------+
a2ps | [] [] [] [] [] | 27
aegis | [] | 9
ant-phone | [] [] [] [] | 9
anubis | [] [] [] [] | 15
aspell | [] [] [] | 20
bash | [] [] [] | 12
bfd | [] | 6
bibshelf | [] [] [] | 16
binutils | [] [] | 8
bison | [] [] | 12
bison-runtime | [] [] [] [] [] [] | 29
bluez-pin | [] [] [] [] [] [] [] [] | 37
bombono-dvd | [] | 4
buzztard | [] | 7
cflow | [] [] [] | 9
clisp | | 10
coreutils | [] [] [] [] | 22
cpio | [] [] [] [] [] [] | 13
cppi | [] [] | 5
cpplib | [] [] [] [] [] [] | 14
cryptsetup | [] [] | 7
dfarc | [] | 9
dialog | [] [] [] [] [] [] [] | 30
dico | [] | 2
diffutils | [] [] [] [] [] [] | 30
dink | | 4
doodle | [] [] | 7
e2fsprogs | [] [] [] | 11
enscript | [] [] [] [] | 17
exif | [] [] [] | 16
fetchmail | [] [] [] | 17
findutils | [] [] [] [] [] | 20
flex | [] [] [] [] | 15
freedink | [] | 10
gas | [] | 4
gawk | [] [] [] [] | 18
gcal | [] [] | 5
gcc | [] [] [] | 7
gettext-examples | [] [] [] [] [] [] [] | 34
gettext-runtime | [] [] [] [] [] [] [] | 29
gettext-tools | [] [] [] [] [] [] | 22
gip | [] [] [] [] | 22
gjay | [] | 3
gliv | [] [] [] | 14
glunarclock | [] [] [] [] [] | 19
gnubiff | [] [] | 4
gnucash | () [] () [] () | 10
gnuedu | [] [] | 7
gnulib | [] [] [] [] | 16
gnunet | [] | 1
gnunet-gtk | [] [] [] | 5
gnutls | [] [] [] | 10
gold | [] | 4
gpe-aerial | [] [] [] | 18
gpe-beam | [] [] [] | 19
gpe-bluetooth | [] [] [] | 13
gpe-calendar | [] [] [] [] | 12
gpe-clock | [] [] [] [] [] | 28
gpe-conf | [] [] [] [] | 20
gpe-contacts | [] [] [] | 17
gpe-edit | [] [] [] | 12
gpe-filemanager | [] [] [] [] | 16
gpe-go | [] [] [] [] [] | 25
gpe-login | [] [] [] | 11
gpe-ownerinfo | [] [] [] [] [] | 25
gpe-package | [] [] [] | 13
gpe-sketchbook | [] [] [] | 20
gpe-su | [] [] [] [] [] | 30
gpe-taskmanager | [] [] [] [] [] | 29
gpe-timesheet | [] [] [] [] [] | 25
gpe-today | [] [] [] [] [] [] | 30
gpe-todo | [] [] [] [] | 17
gphoto2 | [] [] [] [] [] | 24
gprof | [] [] [] | 15
gpsdrive | [] [] [] | 11
gramadoir | [] [] [] | 11
grep | [] [] [] | 10
grub | [] [] [] | 14
gsasl | [] [] [] [] | 14
gss | [] [] [] | 11
gst-plugins-bad | [] [] [] [] | 26
gst-plugins-base | [] [] [] [] [] | 24
gst-plugins-good | [] [] [] [] | 24
gst-plugins-ugly | [] [] [] [] [] | 29
gstreamer | [] [] [] [] | 22
gtick | [] [] [] | 13
gtkam | [] [] [] | 20
gtkorphan | [] [] [] | 14
gtkspell | [] [] [] [] [] [] [] [] [] | 45
gutenprint | [] | 10
hello | [] [] [] [] [] [] | 21
help2man | [] [] | 7
hylafax | [] | 5
idutils | [] [] [] [] | 17
indent | [] [] [] [] [] [] | 30
iso_15924 | () [] () [] [] | 16
iso_3166 | [] [] () [] [] () [] [] [] () | 53
iso_3166_2 | () [] () [] | 9
iso_4217 | [] () [] [] () [] [] | 26
iso_639 | [] [] [] () [] () [] [] [] [] | 38
iso_639_3 | [] () | 8
jwhois | [] [] [] [] [] | 16
kbd | [] [] [] [] [] | 15
keytouch | [] [] [] | 16
keytouch-editor | [] [] [] | 14
keytouch-keyboa... | [] [] [] | 14
klavaro | [] | 11
latrine | [] [] [] | 10
ld | [] [] [] [] | 11
leafpad | [] [] [] [] [] [] | 33
libc | [] [] [] [] [] | 21
libexif | [] () | 7
libextractor | [] | 1
libgnutls | [] [] [] | 9
libgpewidget | [] [] [] | 14
libgpg-error | [] [] [] | 9
libgphoto2 | [] [] | 8
libgphoto2_port | [] [] [] [] | 14
libgsasl | [] [] [] | 13
libiconv | [] [] [] [] | 21
libidn | () [] [] | 11
lifelines | [] | 4
liferea | [] [] [] | 21
lilypond | [] | 7
linkdr | [] [] [] [] [] | 17
lordsawar | | 1
lprng | [] | 3
lynx | [] [] [] [] | 17
m4 | [] [] [] [] | 19
mailfromd | [] [] | 3
mailutils | [] | 5
make | [] [] [] [] | 21
man-db | [] [] [] | 8
man-db-manpages | | 4
minicom | [] [] | 16
mkisofs | [] [] | 9
myserver | | 0
nano | [] [] [] [] | 21
opcodes | [] [] [] | 11
parted | [] [] [] [] [] | 15
pies | [] [] | 3
popt | [] [] [] [] [] [] | 27
psmisc | [] [] | 11
pspp | | 4
pwdutils | [] [] | 6
radius | [] [] | 9
recode | [] [] [] [] | 28
rosegarden | () | 0
rpm | [] [] [] | 11
rush | [] [] | 4
sarg | | 1
screem | [] | 3
scrollkeeper | [] [] [] [] [] | 27
sed | [] [] [] [] [] | 30
sharutils | [] [] [] [] [] | 22
shishi | [] | 3
skencil | [] [] | 7
solfege | [] [] [] [] | 16
solfege-manual | [] | 8
soundtracker | [] [] [] | 9
sp | [] | 3
sysstat | [] [] | 15
tar | [] [] [] [] [] [] | 23
texinfo | [] [] [] [] [] | 17
tin | | 4
unicode-han-tra... | | 0
unicode-transla... | | 2
util-linux-ng | [] [] [] [] | 20
vice | () () | 1
vmm | [] | 4
vorbis-tools | [] | 6
wastesedge | | 2
wdiff | [] [] | 7
wget | [] [] [] [] [] | 26
wyslij-po | [] [] | 8
xchat | [] [] [] [] [] [] | 36
xdg-user-dirs | [] [] [] [] [] [] [] [] [] [] | 63
xkeyboard-config | [] [] [] | 22
+---------------------------------------------------+
85 teams sv sw ta te tg th tr uk vi wa zh_CN zh_HK zh_TW
178 domains 119 1 3 3 0 10 65 51 155 17 98 7 41 2618
Some counters in the preceding matrix are higher than the number of
visible blocks let us expect. This is because a few extra PO files are
used for implementing regional variants of languages, or language
dialects.
For a PO file in the matrix above to be effective, the package to
which it applies should also have been internationalized and
distributed as such by its maintainer. There might be an observable
lag between the mere existence a PO file and its wide availability in a
distribution.
If June 2010 seems to be old, you may fetch a more recent copy of
this `ABOUT-NLS' file on most GNU archive sites. The most up-to-date
matrix with full percentage details can be found at
`http://translationproject.org/extra/matrix.html'.
1.5 Using `gettext' in new packages
===================================
If you are writing a freely available program and want to
internationalize it you are welcome to use GNU `gettext' in your
package. Of course you have to respect the GNU Library General Public
License which covers the use of the GNU `gettext' library. This means
in particular that even non-free programs can use `libintl' as a shared
library, whereas only free software can use `libintl' as a static
library or use modified versions of `libintl'.
Once the sources are changed appropriately and the setup can handle
the use of `gettext' the only thing missing are the translations. The
Free Translation Project is also available for packages which are not
developed inside the GNU project. Therefore the information given above
applies also for every other Free Software Project. Contact
`coordinator@translationproject.org' to make the `.pot' files available
to the translation teams.
================================================
FILE: API.json
================================================
{
"$schema": "http://json-schema.org/draft-03/schema#",
"title": "Kimchi API",
"description": "Json schema for Kimchi API",
"type": "object",
"kimchitype": {
"graphics": {
"description": "Configure graphics parameters for the new VM",
"type": "object",
"properties": {
"type": {
"type": "string",
"enum": ["spice", "vnc"],
"error": "KCHVM0014E"
},
"listen": {
"error": "KCHVM0015E",
"type": [
{
"type": "string",
"format": "ipv4"
},
{
"type": "string",
"format": "ipv6"
}
]
}
}
},
"cpu_info": {
"description": "Configure CPU specifics for a VM.",
"type": "object",
"properties": {
"vcpus": {
"description": "The new number of virtual CPUs for the VM",
"type": "integer",
"minimum": 1,
"error": "KCHTMPL0012E"
},
"maxvcpus": {
"description": "The maximum number of virtual CPUs that can be assigned to the VM",
"type": "integer",
"minimum": 1,
"error": "KCHTMPL0012E"
},
"topology": {
"description": "Configure the guest CPU topology.",
"type": "object",
"properties": {
"sockets": {
"type": "integer",
"minimum": 1,
"error": "KCHTMPL0026E"
},
"cores": {
"type": "integer",
"minimum": 1,
"error": "KCHTMPL0026E"
},
"threads": {
"type": "integer",
"minimum": 1,
"error": "KCHTMPL0026E"
}
},
"additionalProperties": false,
"error": "KCHCPUINF0009E"
}
},
"additionalProperties": false,
"error": "KCHCPUINF0008E"
},
"memory": {
"description": "Current memory and maximum memory values",
"type": "object",
"properties": {
"current": {
"description": "Memory (MB) for the template",
"type": "integer",
"minimum": 512,
"error": "KCHTMPL0013E"
},
"maxmemory": {
"description": "Maximum memory (MB) for the template",
"type": "integer",
"minimum": 512,
"error": "KCHTMPL0013E"
}
},
"additionalProperties": false,
"error": "KCHTMPL0030E"
},
"interface": {
"description": "Host network interface. This indicates how to configure the host network interface (Ethernet, Bond, VLAN) as direct macvtap or as OVS interface to a VM.",
"type": "object",
"properties": {
"type": {
"description": "Host network interface type. Valid types are: 'macvtap' for host network interface (Ethernet, Bond, VLAN) to be connected as direct MacVTap or 'ovs' for openvswitch host network interface to be connected as virtual switch to a VM.",
"type": "string",
"required": true,
"pattern": "^(macvtap|ovs)$",
"error": "KCHTMPL0034E"
},
"name": {
"description": "The host network interface name. It should be name of host network interface(Ethernet, Bond, VLAN) for type 'macvtap' and name of host openvswitch bridge interface for type ovs",
"type": "string",
"required": true,
"error": "KCHTMPL0035E"
},
"mode": {
"description": "Only applicable for macvtap interface type. That indicates whether packets will be delivered directly to target device (bridge) or to the external bridge (vepa-capable bridge).",
"type": "string",
"pattern": "^(bridge|vepa)$",
"error": "KCHTMPL0036E"
}
},
"additionalProperties": false,
"error": "KCHTMPL0038E"
}
},
"properties": {
"storagepools_create": {
"type": "object",
"error": "KCHPOOL0026E",
"properties": {
"name": {
"description": "The name of the Storage Pool",
"type": "string",
"required": true,
"minLength": 1,
"pattern": "^[^/]*$",
"error": "KCHPOOL0016E"
},
"type": {
"description": "The type of the defined Storage Pool",
"type": "string",
"required": true,
"pattern": "^dir|netfs|logical|kimchi-iso|iscsi|scsi$",
"error": "KCHPOOL0017E"
},
"path": {
"description": "The path of the defined Storage Pool",
"type": "string",
"error": "KCHPOOL0018E"
},
"source": {
"description": "Dictionary containing source information of the pool",
"type": "object",
"properties": {
"host": {
"description": "IP or hostname of server for a pool backed from a remote host",
"type": "string",
"error": "KCHPOOL0019E"
},
"path": {
"description": "Export path on NFS server for NFS pool",
"type": "string",
"error": "KCHPOOL0018E"
},
"devices": {
"description": "Array of devices to be used in the Storage Pool",
"type": "array",
"minItems": 1,
"uniqueItems": true,
"error": "KCHPOOL0021E",
"items": {
"description": "Full path of the block device node",
"type": "string",
"error": "KCHPOOL0020E"
}
},
"target": {
"description": "Target IQN of an iSCSI pool",
"type": "string",
"error": "KCHPOOL0022E"
},
"port": {
"description": "Listening port of a remote storage server",
"type": "integer",
"minimum": 1,
"maximum": 65535,
"error": "KCHPOOL0023E"
},
"adapter_name": {
"description": "SCSI host name",
"type": "string",
"error": "KCHPOOL0030E"
},
"auth": {
"description": "Storage back-end authentication information",
"type": "object",
"properties": {
"username": {
"description": "Login username of the iSCSI target",
"type": "string",
"error": "KCHPOOL0024E"
},
"password": {
"description": "Login password of the iSCSI target",
"type": "string",
"error": "KCHPOOL0025E"
}
}
},
"from_vg": {
"description": "Indicate if a logical pool will be created from an existing VG or not",
"type": "boolean",
"error": "KCHPOOL0026E"
}
}
}
}
},
"storagepool_update": {
"type": "object",
"properties": {
"autostart": {
"description": "Set autostart value of the pool",
"type": "boolean"
},
"disks": {
"description": "List of disks/partitions to be added",
"type": "array",
"items": { "type": "string" },
"minItems": 1,
"uniqueItems": true
}
},
"additionalProperties": false
},
"storagevolumes_create": {
"type": "object",
"properties": {
"name": {
"description": "The name of the Storage Volume",
"type": "string",
"minLength": 1,
"error": "KCHVOL0013E"
},
"capacity": {
"description": "The total size (MiB) of the storage volume",
"type": "number",
"minimum": 1,
"error": "KCHVOL0020E"
},
"upload": {
"description": "When the storage volume will be uploaded",
"type": "boolean",
"error": "KCHVOL0025E"
},
"allocation": {
"description": "The size(MiB) of allocation when create the storage volume",
"type": "number",
"minimum": 1,
"error": "KCHVOL0014E"
},
"format": {
"description": "The format of the volume",
"type": "string",
"pattern": "^(|qcow|qcow2|qed|raw|vmdk|vpc)$",
"error": "KCHVOL0015E"
},
"url": {
"description": "The remote URL of the storage volume",
"type": "string",
"pattern": "^(http|ftp)[s]?://",
"error": "KCHVOL0021E"
}
}
},
"storagevolume_update": {
"type": "object",
"properties": {
"chunk": {
"description": "Upload storage volume chunk",
"error": "KCHVOL0024E",
"required": true
},
"chunk_size": {
"description": "Chunk size of uploaded storage volume",
"type": "string",
"required": true,
"error": "KCHVOL0024E"
}
},
"additionalProperties": false
},
"vms_create": {
"type": "object",
"error": "KCHVM0016E",
"properties": {
"name": {
"description": "The name of the new VM",
"type": "string",
"pattern": "^[^/]*$",
"error": "KCHVM0011E"
},
"title": {
"description": "Title of VM",
"type": "string",
"error": "KCHVM0085E"
},
"description": {
"description": "Description of VM",
"type": "string",
"error": "KCHVM0086E"
},
"template": {
"description": "The URI of a template to use when building a VM",
"type": "string",
"pattern": "^/plugins/kimchi/templates/(.*?)/?$",
"required": true,
"error": "KCHVM0012E"
},
"storagepool": {
"description": "Assign a specefic Storage Pool to the new VM",
"type": "string",
"pattern": "^/plugins/kimchi/storagepools/[^/]+/?$",
"error": "KCHVM0013E"
},
"graphics": { "$ref": "#/kimchitype/graphics" }
}
},
"vm_update": {
"type": "object",
"properties": {
"name": {
"description": "New name of VM",
"type": "string",
"pattern": "^[^/]*$",
"minLength": 1,
"error": "KCHVM0011E"
},
"title": {
"description": "Title of VM",
"type": "string",
"error": "KCHVM0085E"
},
"description": {
"description": "Description of VM",
"type": "string",
"error": "KCHVM0086E"
},
"bootorder": {
"description": "Boot order",
"type": "array",
"error": "KCHVM0052E",
"items": [
{"type": "string",
"enum": ["hd", "cdrom", "network", "fd"]
},
{"type": "string",
"enum": ["hd", "cdrom", "network", "fd"]
},
{"type": "string",
"enum": ["hd", "cdrom", "network", "fd"]
},
{"type": "string",
"enum": ["hd", "cdrom", "network", "fd"]
}
],
"minItems": 1,
"maxItems": 4,
"additionalItems": false,
"uniqueItems": true
},
"bootmenu": {
"description": "Bootmenu on guest power on",
"error": "KCHVM0053E",
"type": "boolean"
},
"autostart": {
"description": "Enable/Disable guest autostart",
"type": "boolean"
},
"users": {
"description": "Array of users who have permission to the VM",
"type": "array",
"uniqueItems": true,
"error": "KCHVM0023E",
"items": {
"description": "User name",
"type": "string",
"error": "KCHVM0024E"
}
},
"groups": {
"description": "Array of groups who have permission to the VM",
"type": "array",
"uniqueItems": true,
"error": "KCHVM0025E",
"items": {
"description": "Group name",
"type": "string",
"error": "KCHVM0026E"
}
},
"graphics": {
"description": "Graphics information from guest",
"type": "object",
"properties": {
"passwd": {
"description": "New graphics password.",
"type": "string",
"error": "KCHVM0031E"
},
"passwdValidTo": {
"description": "Life time for the graphics password.",
"type": "number",
"error": "KCHVM0032E"
},
"type": {
"description": "Graphics type",
"type": "string",
"enum": ["spice", "vnc"],
"error": "KCHVM0054E"
}
}
},
"cpu_info": { "$ref": "#/kimchitype/cpu_info" },
"memory": { "$ref": "#/kimchitype/memory" },
"console": {
"description": "type of the console attached to the guest in s390x architecture",
"type": "string",
"pattern": "^sclp|virtio$",
"error": "KCHVM0088E"
}
},
"additionalProperties": false
},
"vm_migrate": {
"type": "object",
"properties": {
"remote_host": {
"description": "IP address or hostname of the remote server",
"type": "string",
"minLength": 1,
"required": true,
"error": "KCHVM0060E"
},
"user": {
"description": "User of the remote server",
"type": "string",
"minLength": 1,
"error": "KCHVM0059E"
},
"password": {
"description": "Password of the user in the remote server",
"type": "string",
"error": "KCHVM0069E"
},
"enable_rdma": {
"description": "Enables RDMA transport",
"type": "boolean",
"error": "KCHVM0091E"
}
},
"additionalProperties": false
},
"networks_create": {
"type": "object",
"error": "KCHNET0016E",
"properties": {
"name": {
"description": "The name of the new network",
"type": "string",
"minLength": 1,
"required": true,
"pattern": "^[^/\"]*$",
"error": "KCHNET0011E"
},
"connection": {
"description": "Specifies how this network should be connected to the other networks",
"type": "string",
"required": true,
"pattern": "^isolated|nat|bridge|macvtap|vepa|passthrough$",
"error": "KCHNET0012E"
},
"subnet": {
"description": "Network segment in slash-separated format with ip address and prefix or netmask",
"type": "string",
"error": "KCHNET0013E"
},
"interfaces": {
"description": "An array of network interfaces of the host",
"type": "array",
"minItems": 1,
"error": "KCHNET0014E"
},
"vlan_id": {
"description": "Network's VLAN ID",
"type": "integer",
"maximum": 4094,
"minimum": 1,
"error": "KCHNET0015E"
}
}
},
"network_update": {
"type": "object",
"additionalProperties": false,
"error": "KCHAPI0001E",
"properties": {
"name": {
"description": "The new name of the network",
"type": "string",
"minLength": 1,
"pattern": "^[^/\"]*$",
"error": "KCHNET0011E"
},
"subnet": {
"description": "Network segment in slash-separated format with ip address and prefix or netmask",
"type": "string",
"error": "KCHNET0013E"
},
"interfaces": {
"description": "An array of network interfaces of the host",
"type": "array",
"error": "KCHNET0014E"
},
"vlan_id": {
"description": "Network's VLAN ID",
"type": "integer",
"maximum": 4094,
"minimum": 1,
"error": "KCHNET0015E"
}
}
},
"vmifaces_create": {
"type": "object",
"error": "KCHVMIF0007E",
"properties": {
"type": {
"description": "The type of VM network interface that libvirt supports. Type 'macvtap' for host network interface (Ethernet, Bond, VLAN) to be connected as direct MacVTap or 'ovs' for openvswitch host network interface to be connected as virtual switch to a VM or 'network' for libvirt virtual network to be connected to VM. ",
"type": "string",
"required": true,
"pattern": "^network|macvtap|ovs$",
"error": "KCHVMIF0004E"
},
"network": {
"description": "the name of one available network",
"type": "string",
"error": "KCHVMIF0005E"
},
"source": {
"description": "The host network interface name. It should be name of host network interface(Ethernet, Bond, VLAN) for type 'macvtap' and name of host openvswitch bridge interface for type ovs",
"type": "string",
"error": "KCHVMIF0016E"
},
"mode": {
"description": "Only applicable for macvtap ifaces type. That indicates whether packets will be delivered directly to target device (bridge) or to the external bridge (vepa-capable bridge)",
"type": "string",
"pattern": "^bridge|vepa$",
"error": "KCHVMIF0017E"
},
"model": {
"description": "model of emulated network interface card",
"type": "string",
"pattern": "^ne2k_pci|i82551|i82557b|i82559er|rtl8139|e1000|pcnet|virtio$",
"error": "KCHVMIF0006E"
},
"mac": {
"description": "Network Interface Card MAC address",
"type": "string",
"pattern": "(^$)|^(([0-9a-fA-F]{2}:){5}[0-9a-fA-F]{2}$)",
"error": "KCHVMIF0010E"
}
}
},
"vmiface_update": {
"type": "object",
"error": "KCHVMIF0008E",
"properties": {
"mac": {
"description": "Network Interface Card MAC address",
"type": "string",
"pattern": "^([0-9a-fA-F]{2}:){5}[0-9a-fA-F]{2}$",
"error": "KCHVMIF0010E"
}
}
},
"templates_create": {
"type": "object",
"error": "KCHTMPL0016E",
"properties": {
"name": {
"description": "The name of the template",
"type": "string",
"pattern": "^[^ ]+( +[^ ]+)*$",
"minLength": 1,
"error": "KCHTMPL0008E"
},
"icon": {
"description": "The template icon path",
"type": "string",
"pattern": "^plugins/kimchi/images/",
"error": "KCHTMPL0009E"
},
"os_distro": {
"description": "Distribution name of the Operating System",
"type": "string",
"minLength": 1,
"error": "KCHTMPL0010E"
},
"os_version": {
"description": "Version of the Operating System",
"type": "string",
"minLength": 1,
"error": "KCHTMPL0011E"
},
"memory": { "$ref": "#/kimchitype/memory" },
"source_media": {
"type" : "object",
"required": true,
"properties" : {
"type": {
"description": "Type of source media: disk or netboot",
"required": true,
"type": "string",
"pattern": "^disk|netboot$"
},
"path": {
"description": "Path for installation media (ISO, disk, remote ISO)",
"type": "string",
"pattern" : "^((/)|(http)[s]?:|[t]?(ftp)[s]?:)+.*$"
}
},
"additionalProperties": false
},
"disks": {
"description": "List of disks",
"type": "array",
"items": {
"type": "object",
"properties": {
"index": {
"description": "Index of the disk",
"type": "integer",
"minimum": 0
},
"format": {
"description": "Type of the image of the disk",
"type": "string",
"pattern": "^(qcow|qcow2|qed|raw|vmdk|vpc)$",
"error": "KCHTMPL0027E"
},
"size": {
"description": "Size (GB) of the disk",
"type": "number",
"minimum": 1,
"error": "KCHTMPL0022E"
},
"pool": {
"description": "Storage pool information",
"type": "object",
"properties": {
"name": {
"description": "Location (URI) of the storage pool",
"type": "string",
"pattern": "^/plugins/kimchi/storagepools/[^/]+/?$",
"error": "KCHTMPL0015E"
}
}
}
}
},
"minItems": 1,
"uniqueItems": true
},
"networks": {
"description": "list of which networks will be assigned to the new VM.",
"type": "array",
"items": { "type": "string" },
"error": "KCHTMPL0017E"
},
"interfaces": {
"description": "list of host interfaces to be assigned to new VM",
"type": "array",
"items": { "ref": "#/kimchitype/interface"},
"error": "KCHTMPL0037E"
},
"folder": {
"description": "Folder",
"type": "array",
"items": { "type": "string" }
},
"graphics": { "$ref": "#/kimchitype/graphics" },
"cpu_info": { "$ref": "#/kimchitype/cpu_info" },
"console": {
"description": "type of the console attached to the guest in s390x architecture",
"type": "string",
"pattern": "^sclp|virtio$",
"error": "KCHTMPL0044E"
}
},
"additionalProperties": false,
"error": "KCHAPI0001E"
},
"storageservers_get_list": {
"type": "object",
"properties": {
"_target_type": {
"description": "List storage servers of given type",
"type": "string",
"pattern": "^netfs|iscsi$"
}
},
"additionalProperties": false,
"error": "KCHAPI0001E"
},
"storagetargets_get_list": {
"type": "object",
"properties": {
"_target_type": {
"description": "List storage servers of given type",
"type": "string",
"pattern": "^netfs|iscsi$"
},
"_server_port": {
"description": "the port of iscsi storage servers",
"type": "string",
"pattern": "^[0-9]{1,5}$"
}
},
"additionalProperties": false,
"error": "KCHAPI0001E"
},
"vmstorages_create": {
"type": "object",
"error": "KCHVMSTOR0012E",
"properties": {
"type": {
"description": "The storage type",
"type": "string",
"pattern": "^cdrom|disk$",
"required": true,
"error": "KCHVMSTOR0002E"
},
"pool": {
"description": "Storage pool name disk image locate in",
"type": "string",
"minLength": 1,
"error": "KCHVMSTOR0012E"
},
"vol": {
"description": "Storage volume name of disk image",
"type": "string",
"minLength": 1,
"error": "KCHVMSTOR0012E"
},
"path": {
"description": "Path of iso image file or disk mount point",
"type": "string",
"pattern": "^((/)|(http)[s]?:|[t]?(ftp)[s]?:)+.*$",
"error": "KCHVMSTOR0003E"
}
}
},
"vmstorage_update": {
"type": "object",
"error": "KCHVMSTOR0013E",
"properties": {
"path": {
"description": "Path of iso image file or disk mount point",
"type": "string",
"required": true,
"pattern": "^(|(/)|(http)[s]?:|[t]?(ftp)[s]?:)+.*$",
"error": "KCHVMSTOR0003E"
}
},
"additionalProperties": false
},
"template_update": {
"type": "object",
"properties": {
"name": {
"description": "The name of the template",
"type": "string",
"pattern": "^[^ ]+( +[^ ]+)*$",
"minLength": 1,
"error": "KCHTMPL0008E"
},
"icon": {
"description": "The template icon path",
"type": "string",
"pattern": "^plugins/kimchi/images/",
"error": "KCHTMPL0009E"
},
"os_distro": {
"description": "Distribution name of the Operating System",
"type": "string",
"minLength": 1,
"error": "KCHTMPL0010E"
},
"os_version": {
"description": "Version of the Operating System",
"type": "string",
"minLength": 1,
"error": "KCHTMPL0011E"
},
"memory": { "$ref": "#/kimchitype/memory" },
"cdrom": {
"description": "Path for cdrom",
"type": "string",
"pattern": "^((/)|(http)[s]?:|[t]?(ftp)[s]?:)+.*$",
"error": "KCHTMPL0014E"
},
"disks": {
"description": "List of disks",
"type": "array",
"items": {
"type": "object",
"properties": {
"index": {
"description": "Index of the disk",
"type": "integer",
"minimum": 0
},
"size": {
"description": "Size (GB) of the disk",
"type": "integer",
"minimum": 1,
"error": "KCHTMPL0022E"
},
"format": {
"description": "Type of the image of the disk",
"type": "string",
"pattern": "^(qcow|qcow2|qed|raw|vmdk|vpc)$",
"error": "KCHTMPL0027E"
},
"pool": {
"description": "Storage pool information",
"type": "object",
"properties": {
"name": {
"description": "Location (URI) of the storage pool",
"type": "string",
"pattern": "^/plugins/kimchi/storagepools/[^/]+/?$",
"error": "KCHTMPL0015E"
}
}
}
}
},
"minItems": 1,
"uniqueItems": true,
"error": "KCHTMPL0033E"
},
"networks": {
"description": "list of which networks will be assigned to the new VM.",
"type": "array",
"items": { "type": "string" },
"error": "KCHTMPL0017E"
},
"interfaces": {
"description": "list of host interfaces to be assigned to new VM",
"type": "array",
"items": { "ref": "#/kimchitype/interface"},
"error": "KCHTMPL0037E"
},
"folder": {
"description": "Folder",
"type": "array",
"items": { "type": "string" }
},
"graphics": { "$ref": "#/kimchitype/graphics" },
"cpu_info": { "$ref": "#/kimchitype/cpu_info" },
"console": {
"description": "type of the console attached to the guest in s390x architecture",
"type": "string",
"pattern": "^sclp|virtio$",
"error": "KCHTMPL0044E"
}
},
"additionalProperties": false,
"error": "KCHAPI0001E"
},
"devices_get_list": {
"type": "object",
"properties": {
"_cap": {
"description": "List specific type of device",
"type": "string",
"pattern": "^fc_host|net|pci|scsi|scsi_host|storage|system|usb|usb_device$",
"error": "KCHDEVS0001E"
},
"_passthrough": {
"description": "List only devices eligible to be assigned to guest",
"type": "string",
"pattern": "^true|false$",
"error": "KCHDEVS0002E"
},
"_passthrough_affected_by": {
"description": "List the affected devices in the same group of a certain device to be assigned to guest",
"type": "string",
"pattern": "^[_A-Za-z0-9-]+$",
"error": "KCHDEVS0003E"
},
"_available_only": {
"description": "List only devices that are not being used by any other VM",
"type": "string",
"pattern": "^true|false$",
"error": "KCHDEVS0004E"
}
},
"additionalProperties": false,
"error": "KCHAPI0001E"
},
"vmhostdevs_create": {
"type": "object",
"properties": {
"name": {
"description": "Then name of the device to assign to VM",
"type": "string",
"required": true,
"pattern": "^[_A-Za-z0-9-]+$",
"error": "KCHVMHDEV0004E"
}
},
"error": "KCHAPI0001E"
}
}
}
================================================
FILE: AUTHORS
================================================
Adam King
Adam Litke
Adam
Adriano Botega
Alan Jenkins
Alexandre Tanaka Hirata
Aline Manera
Andre Teodoro
Anthony Liguori
apporc
Archana Singh
Atreyee Mukhopadhyay
Bing Bu Cao
Brent Baude
Cédric Bosdonnat
Chandra Shekhar Reddy Potula
Christy Perez
Cole Robinson
Crístian Deives
Daniel Henrique Barboza
Daniel Henrique Barboza
Dinar Valeev
Eduardo Elias Ferreira
Eli Qiao
Frederic Bonnard
Hongliang Wang
Jose Ricardo Ziviani
Julien Goodwin
Kersten Richter
Leonardo Garcia
Lucio Correia
malcolm yu
Mark Wu
Paulo Vital
Pooja Kulkarni
Pradeep K Surisetty
Ramon Medeiros
Rodrigo Trujillo
Royce Lv
samhenri
ShaoHe Feng
Shu Ming
Simon Jin
Socorro Stoppler
ssdxiao
Stephan Conrad
Suresh Babu Angadi
Thierry Fauck
Tony Breeds
Tulio Magno Quites Machado Filho
Wen Wang
Xin Ding
Yu Xin Huo
Zhou Zheng Sheng
Zongmei Gou
================================================
FILE: CONTRIBUTE.md
================================================
How to Contribute
=================
All development discussion happens on the mailing list. All development is done
using the `git` SCM. Patches should be sent using the `git send-email` command
to the kimchi-devel@ovirt.org mailing list.
Good examples of how to send patches are included in
[QEMU SubmitAPatch](http://wiki.qemu.org/Contribute/SubmitAPatch) and
[Linux SubmittingPatches](https://www.kernel.org/doc/Documentation/SubmittingPatches).
All documentation and READMEs are written using
[Markdown](http://daringfireball.net/projects/markdown/).
For a patch to be committed, it must receive at least one "Reviewed-by" on the
mailing list.
================================================
FILE: COPYING
================================================
Kimchi is distributed pursuant to the terms of two different licenses.
The user interface (located in ui/ in this distribution) is governed by the
Apache License version 2.0.
Kimchi makes use of different projects and they are placed as below:
- the code under ui/spice-html5 is imported from spice-html5 project
(http://cgit.freedesktop.org/spice/spice-html5);
- the code under ui/serial/libs is imported from term.js project
(https://github.com/chjj/term.js) under MIT license;
The rest of this distribution is governed by the GNU Lesser General Public
License version 2.1.
See COPYING.LGPL and COPYING.ASL2.
The name "Gentoo" and the "g" logo are trademarks of Gentoo Foundation, Inc.
The content, project, site, product or any other type of item with which the
"Gentoo" name is associated is not part of the Gentoo project and is not
directed or managed by Gentoo Foundation, Inc.
Kimchi has a written consent to use SUSE logo as a open source project.
"SUSE" and the SUSE logo are trademarks of SUSE LLC or its subsidiaries or affiliates.
All other trademarks, trade names, or company names referenced herein are used for
identification only and are the property of their respective owners, it should not be
used by commercial means.
================================================
FILE: COPYING.ASL2
================================================
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
================================================
FILE: COPYING.LGPL
================================================
GNU LESSER GENERAL PUBLIC LICENSE
Version 2.1, February 1999
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
[This is the first released version of the Lesser GPL. It also counts
as the successor of the GNU Library Public License, version 2, hence
the version number 2.1.]
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
Licenses are intended to guarantee your freedom to share and change
free software--to make sure the software is free for all its users.
This license, the Lesser General Public License, applies to some
specially designated software packages--typically libraries--of the
Free Software Foundation and other authors who decide to use it. You
can use it too, but we suggest you first think carefully about whether
this license or the ordinary General Public License is the better
strategy to use in any particular case, based on the explanations below.
When we speak of free software, we are referring to freedom of use,
not price. Our General Public Licenses are designed to make sure that
you have the freedom to distribute copies of free software (and charge
for this service if you wish); that you receive source code or can get
it if you want it; that you can change the software and use pieces of
it in new free programs; and that you are informed that you can do
these things.
To protect your rights, we need to make restrictions that forbid
distributors to deny you these rights or to ask you to surrender these
rights. These restrictions translate to certain responsibilities for
you if you distribute copies of the library or if you modify it.
For example, if you distribute copies of the library, whether gratis
or for a fee, you must give the recipients all the rights that we gave
you. You must make sure that they, too, receive or can get the source
code. If you link other code with the library, you must provide
complete object files to the recipients, so that they can relink them
with the library after making changes to the library and recompiling
it. And you must show them these terms so they know their rights.
We protect your rights with a two-step method: (1) we copyright the
library, and (2) we offer you this license, which gives you legal
permission to copy, distribute and/or modify the library.
To protect each distributor, we want to make it very clear that
there is no warranty for the free library. Also, if the library is
modified by someone else and passed on, the recipients should know
that what they have is not the original version, so that the original
author's reputation will not be affected by problems that might be
introduced by others.
Finally, software patents pose a constant threat to the existence of
any free program. We wish to make sure that a company cannot
effectively restrict the users of a free program by obtaining a
restrictive license from a patent holder. Therefore, we insist that
any patent license obtained for a version of the library must be
consistent with the full freedom of use specified in this license.
Most GNU software, including some libraries, is covered by the
ordinary GNU General Public License. This license, the GNU Lesser
General Public License, applies to certain designated libraries, and
is quite different from the ordinary General Public License. We use
this license for certain libraries in order to permit linking those
libraries into non-free programs.
When a program is linked with a library, whether statically or using
a shared library, the combination of the two is legally speaking a
combined work, a derivative of the original library. The ordinary
General Public License therefore permits such linking only if the
entire combination fits its criteria of freedom. The Lesser General
Public License permits more lax criteria for linking other code with
the library.
We call this license the "Lesser" General Public License because it
does Less to protect the user's freedom than the ordinary General
Public License. It also provides other free software developers Less
of an advantage over competing non-free programs. These disadvantages
are the reason we use the ordinary General Public License for many
libraries. However, the Lesser license provides advantages in certain
special circumstances.
For example, on rare occasions, there may be a special need to
encourage the widest possible use of a certain library, so that it becomes
a de-facto standard. To achieve this, non-free programs must be
allowed to use the library. A more frequent case is that a free
library does the same job as widely used non-free libraries. In this
case, there is little to gain by limiting the free library to free
software only, so we use the Lesser General Public License.
In other cases, permission to use a particular library in non-free
programs enables a greater number of people to use a large body of
free software. For example, permission to use the GNU C Library in
non-free programs enables many more people to use the whole GNU
operating system, as well as its variant, the GNU/Linux operating
system.
Although the Lesser General Public License is Less protective of the
users' freedom, it does ensure that the user of a program that is
linked with the Library has the freedom and the wherewithal to run
that program using a modified version of the Library.
The precise terms and conditions for copying, distribution and
modification follow. Pay close attention to the difference between a
"work based on the library" and a "work that uses the library". The
former contains code derived from the library, whereas the latter must
be combined with the library in order to run.
GNU LESSER GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License Agreement applies to any software library or other
program which contains a notice placed by the copyright holder or
other authorized party saying it may be distributed under the terms of
this Lesser General Public License (also called "this License").
Each licensee is addressed as "you".
A "library" means a collection of software functions and/or data
prepared so as to be conveniently linked with application programs
(which use some of those functions and data) to form executables.
The "Library", below, refers to any such software library or work
which has been distributed under these terms. A "work based on the
Library" means either the Library or any derivative work under
copyright law: that is to say, a work containing the Library or a
portion of it, either verbatim or with modifications and/or translated
straightforwardly into another language. (Hereinafter, translation is
included without limitation in the term "modification".)
"Source code" for a work means the preferred form of the work for
making modifications to it. For a library, complete source code means
all the source code for all modules it contains, plus any associated
interface definition files, plus the scripts used to control compilation
and installation of the library.
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running a program using the Library is not restricted, and output from
such a program is covered only if its contents constitute a work based
on the Library (independent of the use of the Library in a tool for
writing it). Whether that is true depends on what the Library does
and what the program that uses the Library does.
1. You may copy and distribute verbatim copies of the Library's
complete source code as you receive it, in any medium, provided that
you conspicuously and appropriately publish on each copy an
appropriate copyright notice and disclaimer of warranty; keep intact
all the notices that refer to this License and to the absence of any
warranty; and distribute a copy of this License along with the
Library.
You may charge a fee for the physical act of transferring a copy,
and you may at your option offer warranty protection in exchange for a
fee.
2. You may modify your copy or copies of the Library or any portion
of it, thus forming a work based on the Library, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) The modified work must itself be a software library.
b) You must cause the files modified to carry prominent notices
stating that you changed the files and the date of any change.
c) You must cause the whole of the work to be licensed at no
charge to all third parties under the terms of this License.
d) If a facility in the modified Library refers to a function or a
table of data to be supplied by an application program that uses
the facility, other than as an argument passed when the facility
is invoked, then you must make a good faith effort to ensure that,
in the event an application does not supply such function or
table, the facility still operates, and performs whatever part of
its purpose remains meaningful.
(For example, a function in a library to compute square roots has
a purpose that is entirely well-defined independent of the
application. Therefore, Subsection 2d requires that any
application-supplied function or table used by this function must
be optional: if the application does not supply it, the square
root function must still compute square roots.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Library,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Library, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote
it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Library.
In addition, mere aggregation of another work not based on the Library
with the Library (or with a work based on the Library) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may opt to apply the terms of the ordinary GNU General Public
License instead of this License to a given copy of the Library. To do
this, you must alter all the notices that refer to this License, so
that they refer to the ordinary GNU General Public License, version 2,
instead of to this License. (If a newer version than version 2 of the
ordinary GNU General Public License has appeared, then you can specify
that version instead if you wish.) Do not make any other change in
these notices.
Once this change is made in a given copy, it is irreversible for
that copy, so the ordinary GNU General Public License applies to all
subsequent copies and derivative works made from that copy.
This option is useful when you wish to copy part of the code of
the Library into a program that is not a library.
4. You may copy and distribute the Library (or a portion or
derivative of it, under Section 2) in object code or executable form
under the terms of Sections 1 and 2 above provided that you accompany
it with the complete corresponding machine-readable source code, which
must be distributed under the terms of Sections 1 and 2 above on a
medium customarily used for software interchange.
If distribution of object code is made by offering access to copy
from a designated place, then offering equivalent access to copy the
source code from the same place satisfies the requirement to
distribute the source code, even though third parties are not
compelled to copy the source along with the object code.
5. A program that contains no derivative of any portion of the
Library, but is designed to work with the Library by being compiled or
linked with it, is called a "work that uses the Library". Such a
work, in isolation, is not a derivative work of the Library, and
therefore falls outside the scope of this License.
However, linking a "work that uses the Library" with the Library
creates an executable that is a derivative of the Library (because it
contains portions of the Library), rather than a "work that uses the
library". The executable is therefore covered by this License.
Section 6 states terms for distribution of such executables.
When a "work that uses the Library" uses material from a header file
that is part of the Library, the object code for the work may be a
derivative work of the Library even though the source code is not.
Whether this is true is especially significant if the work can be
linked without the Library, or if the work is itself a library. The
threshold for this to be true is not precisely defined by law.
If such an object file uses only numerical parameters, data
structure layouts and accessors, and small macros and small inline
functions (ten lines or less in length), then the use of the object
file is unrestricted, regardless of whether it is legally a derivative
work. (Executables containing this object code plus portions of the
Library will still fall under Section 6.)
Otherwise, if the work is a derivative of the Library, you may
distribute the object code for the work under the terms of Section 6.
Any executables containing that work also fall under Section 6,
whether or not they are linked directly with the Library itself.
6. As an exception to the Sections above, you may also combine or
link a "work that uses the Library" with the Library to produce a
work containing portions of the Library, and distribute that work
under terms of your choice, provided that the terms permit
modification of the work for the customer's own use and reverse
engineering for debugging such modifications.
You must give prominent notice with each copy of the work that the
Library is used in it and that the Library and its use are covered by
this License. You must supply a copy of this License. If the work
during execution displays copyright notices, you must include the
copyright notice for the Library among them, as well as a reference
directing the user to the copy of this License. Also, you must do one
of these things:
a) Accompany the work with the complete corresponding
machine-readable source code for the Library including whatever
changes were used in the work (which must be distributed under
Sections 1 and 2 above); and, if the work is an executable linked
with the Library, with the complete machine-readable "work that
uses the Library", as object code and/or source code, so that the
user can modify the Library and then relink to produce a modified
executable containing the modified Library. (It is understood
that the user who changes the contents of definitions files in the
Library will not necessarily be able to recompile the application
to use the modified definitions.)
b) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (1) uses at run time a
copy of the library already present on the user's computer system,
rather than copying library functions into the executable, and (2)
will operate properly with a modified version of the library, if
the user installs one, as long as the modified version is
interface-compatible with the version that the work was made with.
c) Accompany the work with a written offer, valid for at
least three years, to give the same user the materials
specified in Subsection 6a, above, for a charge no more
than the cost of performing this distribution.
d) If distribution of the work is made by offering access to copy
from a designated place, offer equivalent access to copy the above
specified materials from the same place.
e) Verify that the user has already received a copy of these
materials or that you have already sent this user a copy.
For an executable, the required form of the "work that uses the
Library" must include any data and utility programs needed for
reproducing the executable from it. However, as a special exception,
the materials to be distributed need not include anything that is
normally distributed (in either source or binary form) with the major
components (compiler, kernel, and so on) of the operating system on
which the executable runs, unless that component itself accompanies
the executable.
It may happen that this requirement contradicts the license
restrictions of other proprietary libraries that do not normally
accompany the operating system. Such a contradiction means you cannot
use both them and the Library together in an executable that you
distribute.
7. You may place library facilities that are a work based on the
Library side-by-side in a single library together with other library
facilities not covered by this License, and distribute such a combined
library, provided that the separate distribution of the work based on
the Library and of the other library facilities is otherwise
permitted, and provided that you do these two things:
a) Accompany the combined library with a copy of the same work
based on the Library, uncombined with any other library
facilities. This must be distributed under the terms of the
Sections above.
b) Give prominent notice with the combined library of the fact
that part of it is a work based on the Library, and explaining
where to find the accompanying uncombined form of the same work.
8. You may not copy, modify, sublicense, link with, or distribute
the Library except as expressly provided under this License. Any
attempt otherwise to copy, modify, sublicense, link with, or
distribute the Library is void, and will automatically terminate your
rights under this License. However, parties who have received copies,
or rights, from you under this License will not have their licenses
terminated so long as such parties remain in full compliance.
9. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Library or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Library (or any work based on the
Library), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Library or works based on it.
10. Each time you redistribute the Library (or any work based on the
Library), the recipient automatically receives a license from the
original licensor to copy, distribute, link with or modify the Library
subject to these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties with
this License.
11. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Library at all. For example, if a patent
license would not permit royalty-free redistribution of the Library by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Library.
If any portion of this section is held invalid or unenforceable under any
particular circumstance, the balance of the section is intended to apply,
and the section as a whole is intended to apply in other circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
12. If the distribution and/or use of the Library is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Library under this License may add
an explicit geographical distribution limitation excluding those countries,
so that distribution is permitted only in or among countries not thus
excluded. In such case, this License incorporates the limitation as if
written in the body of this License.
13. The Free Software Foundation may publish revised and/or new
versions of the Lesser General Public License from time to time.
Such new versions will be similar in spirit to the present version,
but may differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the Library
specifies a version number of this License which applies to it and
"any later version", you have the option of following the terms and
conditions either of that version or of any later version published by
the Free Software Foundation. If the Library does not specify a
license version number, you may choose any version ever published by
the Free Software Foundation.
14. If you wish to incorporate parts of the Library into other free
programs whose distribution conditions are incompatible with these,
write to the author to ask for permission. For software which is
copyrighted by the Free Software Foundation, write to the Free
Software Foundation; we sometimes make exceptions for this. Our
decision will be guided by the two goals of preserving the free status
of all derivatives of our free software and of promoting the sharing
and reuse of software generally.
NO WARRANTY
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Libraries
If you develop a new library, and you want it to be of the greatest
possible use to the public, we recommend making it free software that
everyone can redistribute and change. You can do so by permitting
redistribution under these terms (or, alternatively, under the terms of the
ordinary General Public License).
To apply these terms, attach the following notices to the library. It is
safest to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least the
"copyright" line and a pointer to where the full notice is found.
Copyright (C)
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Also add information on how to contact you by electronic and paper mail.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the library, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the
library `Frob' (a library for tweaking knobs) written by James Random Hacker.
, 1 April 1990
Ty Coon, President of Vice
That's all there is to it!
================================================
FILE: ChangeLog
================================================
CHANGELOG
=========
#### [3.0.0] ####
* [a6574995] Update remote ISOs URLs (Aline Manera)
* [b04c5e3a] OpenSUSE 15.1: Use localstatedir when runstatedir is not available (Aline Manera)
* [bb254866] OpenSUSE 15.1: Install pyparted via pip (Aline Manera)
* [e08abf34] Issue #1224 : kvmusertest.py: hardcoded path prevents kimchi module from loa.. (Renata Ravanelli)
* [bc8f14e9] Issue #1264 : Libvirt check should only look for socket (Renata Ravanelli)
* [68237118] Remove python3-pam as Kimchi dependency (Aline Manera)
* [c47a9c00] Use jsonschema Draft3Validator (Aline Manera)
* [e7c5fca8] Bug fix: Proper set python3 on RPM build (Aline Manera)
* [1dadcdae] Bug fix: Detect CentOS 8 ISO (Aline Manera)
* [daa803dd] Add pull request template (Aline Manera)
* [77dcf86d] Create issue templates (Aline Manera)
* [d3c54092] Update docs (Aline Manera)
* [9ff17b2f] Remove *deps.list files as they are auto generated on build (Aline Manera)
* [4631a0a6] Ubuntu 19.10: Set dependencies properly (Aline Manera)
* [b35d21be] Use the correct python lib directory to install python libraries (Aline Manera)
* [28384e43] Fix build: Add new files to Makefile (Aline Manera)
* [37f2e983] Python3: Use python3-pep8 on Fedora (Aline Manera)
* [68d136a1] Fix #1285: Use distro.linux_distribution (python3) (Aline Manera)
* [203ddc43] Fix #1179: Proper set cpu mode for PPC and Aarch64 (Aline Manera)
* [ec9b4d31] Fix #1281: Only listen to VIR_STORAGE_POOL_EVENT_ID_LIFECYCLE events (Aline Manera)
* [832a2d3c] Fix #1228: Proper set storage volume capacity unit (Aline Manera)
* [14f5e308] Bug fix: Update config tests due to 'take_screenshot' option (Aline Manera)
* [8189398f] Bug fix: Set PYTHONPATH to while running target (Aline Manera)
* [6d91c39b] Bug fix: Update config tests due to /spice-web-client (Aline Manera)
* [f72d0ef7] Bug fix: Use encoding option of ET.tostring() to get XML as string (Aline Manera)
* [0b09900c] Bug fix: Update tests as the default amount of memory was increased to 2048M (Aline Manera)
* [f3fd4563] Fix #1275: Update README with Kimchi dependencies (Aline Manera)
* [74333089] Bug fix: Remove blank line from dependencies.yaml (Aline Manera)
* [4f848586] Issue #1256: Always show the link to access guest via VNC or Spice (Manassé Ngudia)
* [3b70de3c] comma expected (kattil3)
* [c26d35d8] Python3: Update package dependencies (Aline Manera)
* [2ca10671] Increase default virtual machine memory to 2048Mb (Aline Manera)
* [0c0d76aa] flipping problem fix (Pavel Gurenko)
* [1ab22ad3] removed unneeded index.html static map (Pavel Gurenko)
* [5b29ccfd] added with_spice_web_client to config (Pavel Gurenko)
* [45a4ef55] api changes to support spice-web-client (Pavel Gurenko)
* [b27e60df] adds automakes for spice-web-client (Pavel Gurenko)
* [620d9a07] adds spice-web-client (Pavel Gurenko)
* [9d1dee76] fix broken links (Invch)
* [230b53e9] Bug fix: Proper get 'take_screenshot' parameter from kimchi config (Aline Manera)
* [cc4c9095] Use importlib module instead of imp (Aline Manera)
* [3d523cdb] Remove IBM license checker (Aline Manera)
* [57f9f526] Add pre-commit configuration (Aline Manera)
* [8334268a] Switch to Python 3 (Aline Manera)
* [c9068602] Add a configuration option for disabling taking a screenshot (ss23)
* [c56b06db] stop testing symlinks/blockdevices against VALID_RAW_CONTENT (a-a)
* [bc66961b] Issue 1242: Allow either python-imaging or python-pil in installer (Ian Otto)
* [c775ab5b] Issue #1215: Wrong tab into Storage section (Cyrille Gindreau)
* [382771e1] Update Ubuntu deps. (#1192) (dumol)
* [0afbd77d] Guest autostart (#1163) (Galen Pospisil)
* [5a38b72c] Fix error handler on $.ajax() function (Aline Manera)
* [bf9097dd] Fix issue #1165: Use relative path to access websockify (Aline Manera)
* [9e85926c] Fix issue #1157: Consider DOS/MBR mime type as ISO file (Aline Manera)
* [18e9257e] Use fontawesome spinner icon instead of external image (Aline Manera)
* [e29d0463] Use fontawesome icon instead of external image (Aline Manera)
* [34aaaf7b] Use distro icons exposed by Kimchi URIs (Aline Manera)
* [93befdb5] Remove kimchi.setListVMAuto call function (Aline Manera)
* [0928eff5] .size() is deprecated on JQuery 3.2.1 (Aline Manera)
* [2618d991] Remove alert-container as it is being provided by Wok basic-template (Aline Manera)
* [2dd489a7] Update README as http://kimchi-project.github.io/kimchi/downloads/ is no lon.. (Aline Manera)
* [6fa2dda5] Add Domain listeners to update page according to user interations (Aline Manera)
* [6189310b] Register for libvirt domain events to update the UI accordindly (Aline Manera)
* [33857406] Add Network listeners to update page according to user interations (Aline Manera)
* [ad43cf49] Register for libvirt network events to update the UI accordindly (Aline Manera)
* [b4b48184] Add Storage Pools listeners to update page according to user interations (Aline Manera)
* [3c76dd2d] Register for libvirt storage pools events to update the UI accordindly (Aline Manera)
* [48d03e07] Add Template listeners to update page according to user interations (Aline Manera)
* [3803fece] Update po files (Aline Manera)
* [810ad2e0] Change VNC & Spice console URLs to reference web interface port (Galen Pospisil)
* [f859a7aa] Issue #1155: enhancement (Joni Orponen)
#### [2.5.0] ####
* [bd3a102a] Update VERSION, ChangeLog and .po files for 2.5 release (Aline Manera)
* [0f3c23ce] Remove ginger-base as Kimchi dependency (Aline Manera)
* [6251e083] Remove federation feature from Kimchi as it is now on Wok (Aline Manera)
* [fb99e655] Add server arch from /host API instead of relying on Ginger Base (Aline Manera)
* [4fae03c7] Move Kimchi specific functions from gingerbase.disks to Kimchi (Aline Manera)
* [ed61aeff] Move Kimchi specific functions from gingerbase.netinfo to Kimchi (Aline Manera)
* [3653a56a] Remove Open Sans font requirement (Aline Manera)
* [330995a5] Bug fix: Let Wok specify UI configuration on cherrypy settings (Aline Manera)
* [e236d110] Updated PO files (Rajat Gupta)
* [33a6cd63] Update Copyright date on po files (Aline Manera)
#### [2.4.0] ####
* [856b1570] Update VERSION, ChangeLog and po files for 2.4.0 release (Aline Manera)
* [c49cbb57] Bug fix: Set original VLAN device to network parameters to be updated (Aline Manera)
* [62cb5803] Bug fix 1119: Proper check NetworkManager is running when creating new network (Aline Manera)
* [a4a5472b] Bug fix: Inform user there is no interface available when creating a network (Aline Manera)
* [1709bcf7] Bug fix: Proper display storage volume content on gallery view (Aline Manera)
* [5f79fca4] Bug fix: Display full Volume dropdown menu content even when pool has few vo.. (Aline Manera)
* [4b301157] Bug fix: Preserve "View Gallery" button location when opening Storage Volume.. (Aline Manera)
* [04a2a9a0] Bug fix #1123: Do not rely on Wok configuration to get host information (Aline Manera)
#### [2.4.0-rc1] ####
* [61537e95] Bug fix #1107: Only set cache=none to disks that support direct IO (Aline Manera)
* [eb4dfde0] Use Websocket facilities from WoK (Daniel Henrique Barboza)
* [09d9a398] Update copyright date according commit 3195f7b1 (Aline Manera)
* [2b3a7219] Fix typo (Lucio Correia)
* [9f0cf4a7] fix wrong tab enumeration (fritz-net)
* [a20b8a55] Fix storage volume test to run without nginx (Lucio Correia)
* [39bd67b6] Fix tests to run without proxy (Lucio Correia)
* [fb6ba234] Fix patch_auth() call according to Wok changes (Aline Manera)
* [459d3f03] Improve logic to identify if a network is in use or not (Aline Manera)
* [abe36bb5] Fix memory hotplug test case (Aline Manera)
* [09a380c1] Fix snapshots test case (Aline Manera)
* [952c029b] Bug fix: Set default host value while generating the virt-viewer config file (Aline Manera)
* [d95ed9dc] Update run_server() calls to do not pass model instance (Aline Manera)
* [0758c189] Specify objectstore location when running on test mode (Aline Manera)
* [a743f930] Bug Fix #979 - Change boot order UI (Bianca Carvalho)
* [049a9c9c] Update copyright date for root.py file (Aline Manera)
* [05af594c] Bug fix #1089: osinfo.py tablet_bus='usb' for x86 modern (Ramon Medeiros)
* [a386a29e] Adding 'self.depends' option in root.py (Daniel Henrique Barboza)
* [90e37cf9] Fix for the kimchi #1102 (Jayavardhan Katta)
* [d59f5ff0] Fixed truncation for Guest Interface GUI OVS network/interface scroll bar (Rajat Gupta)
* [94bc11d8] Fixed Truncation appeared on Virtualization->add network of Japanese language (Rajat Gupta)
* [9a088014] Fixed for Truncation occurs in edit a guest panel console row (Rajat Gupta)
* [08571fed] Bug fix #1096 - Prevent mass detach based on source PCI address (Daniel Henrique Barboza)
* [e24dfb5f] Remove role_key parameter (Aline Manera)
* [649621f6] Remove whitespaces (Aline Manera)
* [ed83a269] Add test to live snapshot (Ramon Medeiros)
* [aa069381] Bug fix #1029: Unable to create a snapshot on a running guest (Ramon Medeiros)
* [f5e7c699] Live migration RDMA support: mockmodel changes (Daniel Henrique Barboza)
* [9927cfb6] Live migration RDMA support: test changes (Daniel Henrique Barboza)
* [cda5bd13] Live migration RDMA support: ui changes (Daniel Henrique Barboza)
* [29b237aa] Live migration RDMA support: model changes (Daniel Henrique Barboza)
* [2b42c4ca] Live migration RDMA support: doc changes (Daniel Henrique Barboza)
* [64ffba7e] Bug fix #1016: Display current storage volume size on resize dialog (Ramon Medeiros)
* [b688fa49] VEPA interface not listed with VM running (Ramon Medeiros)
* [eaaea97b] Fix issue #1069: Allow user specifies the Template name when creating it (Aline Manera)
* [d0f1467e] Update copyright date (Aline Manera)
* [8fce3b18] Bug fix #1073: Re-attach device to host when detaching it from guest (Aline Manera)
* [6288c73d] mockmodel.py: unsubscribing from 'exit' channel on cleanup (Daniel Henrique Barboza)
* [d6c39766] Multi-culture UI issues for kimchi plugin Guest module (Rajat Gupta)
* [9e6c5b93] Multi-culture UI issues for kimchi plugin Storage module (Rajat Gupta)
* [5d478e30] Corrected position of close icon for create a network pop up alert (Rajat Gupta)
* [43948dc2] Multi-culture UI issues for kimchi plugin template module (Rajat Gupta)
* [467afa2e] Bug fix #1064: In Migrate guest window, text boxes are not taking input prop.. (Bianca Carvalho)
* [060a5bd3] Update README file to point to http://kimchi-project.github.io/kimchi/downlo.. (Aline Manera)
* [86e75b00] Use libvirtd service in Ubuntu (Lucio Correia)
* [1b2b8546] Bug fix #1026: CentOS: Unable to get and update memory values for a powered .. (Ramon Medeiros)
* [03c5b000] Bug fix #1057: Failed to import kimchi (Bianca Carvalho)
* [0e2a8f3e] Add more details to error message when probing image (Lucio Correia)
* [ebc2ebb3] Add missing dependency to documentation (Lucio Correia)
* [a9e2808e] Bug fix #1066: Do not stora guest storage volume information on objectstore (Aline Manera)
* [9314ab37] Bug fix #1015: Rename "Guest Name ID" header to "Guest Name" (Aline Manera)
* [729aaf48] Fix checking for libvirt daemon on Ubuntu (Lucio Correia)
* [4e4ec433] Fixed resize volume click input number in virtualization->storag (Rajat Gupta)
* [06c52e95] Recognize openSUSE 42.2 ISO (Aline Manera)
* [eb8684ad] CPU Hot plug/unplug: test_rest.py changes (Daniel Henrique Barboza)
* [ecb5fdcb] CPU Hot plug/unplug: ui changes (Daniel Henrique Barboza)
* [1c11e086] CPU Hot plug/unplug: test changes (Daniel Henrique Barboza)
* [6c2e9176] CPU Hot plug/unplug: model changes (Daniel Henrique Barboza)
* [2943a04e] CPU Hot plug/unplug: i18n changes (Daniel Henrique Barboza)
* [66da0a5e] Changing 'threads' to be a free number field (Daniel Henrique Barboza)
* [035b6dfa] Edit Guest dialog: fixing 'Save' button on Processor tab (Daniel Henrique Barboza)
* [52e93961] Adding CPU setup help text in Edit Guest/Template (Daniel Henrique Barboza)
* [feb5f889] CPU configuration UI: several improvements (Daniel Henrique Barboza)
* [4ebe1df5] Adding 'Processor' tab in Edit Guest dialog (Daniel Henrique Barboza)
* [b5070c8e] template_edit_main.js: initProcessor now a global function (Daniel Henrique Barboza)
* [51c5c300] Adding 'sockets' field in the topology of Templates (Daniel Henrique Barboza)
* [21e2608b] Bug fix #1072 - changing vpus verification (Daniel Henrique Barboza)
* [3431536f] Fix pep8 issue (Aline Manera)
* [549177a0] Fixed issue #1076 s390x : n/w shows twice same interface while adding for te.. (Rajat Gupta)
* [0571b300] Fixed issue #1075 s390x : Edit Template storage tab Storage dropdown shows ".. (Rajat Gupta)
* [7f6c6523] Fixed issue #1062 Disk path not taking input properly (Rajat Gupta)
* [ca013f28] Update Kimchi code due chnages on Wok configuration parameters (Aline Manera)
* [920da4fd] po/ja_JP.po: fix trailing whitespace (Daniel Henrique Barboza)
* [73c29d29] rpmlint fixes on Fedora and Suse specs (Daniel Henrique Barboza)
* [a3135122] Issue #1050: Rename template with existing template name (Archana Singh)
* [9c6d48ab] s390x specific changes to support storage path and storage pool as disk. (Archana Singh)
* [9764bdb2] Edit template storage path should start with "/" (Rajat Gupta)
* [2e1089ea] Fixed issue #1074 IP address for the guest under Interfaces tab is blank (Rajat Gupta)
* [f70c9808] Issue #998 Updated .pot and .po files (Pooja Kulkarni)
* [70a15b92] Issue #998 Not all static strings are externalized (Pooja Kulkarni)
* [f8400f92] Remove URI configuration from kimchi.conf file (Aline Manera)
* [951c8bdf] Issue #1061: For s390x, in edit template add storage path, even after changi.. (Archana Singh)
* [26560667] Issue #1060: Edit template/Guest for s390x, console drop down shows empty bo.. (Archana Singh)
* [54ac56bc] Issue #1059: Not able to save corrected img path after editing img based tem.. (Archana Singh)
* [1c0d3534] Wok issue #173: Set tab color on tab-ext.xml and update SCSS files (Aline Manera)
* [037cf5a9] Wok issue #174: Let Wok create the whole navigation bar (Aline Manera)
* [8ca2eafb] Issue: #1008 Issues while editing a VEPA network (Ramon Medeiros)
* [96d5b2f9] PCI hotplug: Check USB controller, define in template, add test in Power (Lucio Correia)
* [27c23dd3] Issue #651: Windows guests - default mouse type causing problems (Ramon Medeiros)
* [0a5a4d29] Improve multifunction attach/detach operations (Lucio Correia)
* [36b1398d] Improve Fedora 24 identification (Lucio Correia)
* [f4bbf64d] Adding libvirt remote connection verification (Daniel Henrique Barboza)
* [f42d8b54] Github #1007: Fixing non-root ssh key generation (Daniel Henrique Barboza)
* [c9e50d4e] Github #1007: use provided user for password-less setup (Daniel Henrique Barboza)
* [8847bbb9] For s390x virtualization edit template display "Storage" as header (Rajat Gupta)
* [9896df85] Added UI validation for s390x Virtualization Template Edit Add Storage module (Rajat Gupta)
* [1d0f9e04] Added UI validation for s390x Virtualization Guest Edit Add Storage module (Rajat Gupta)
* [a3c1ea01] Remove PowerKVM checks from memory alignment code (Lucio Correia)
* [8421bae4] Use tablet_bus for tablet input instead of kbd_bus (Ramon Medeiros)
* [38b9813b] Issue #733: CSS updates to handle relative path support. (Paulo Vital)
* [664411fd] Issue #733: Fix UI to handle relative paths. (Paulo Vital)
* [d6959a82] Issue #1006: Invalid subnet value when editing a network raise an error (Ramon Medeiros)
* [4ed2242f] fix for issue #1049 (Suresh Babu Angadi)
* [93735c22] Issue #1048 : disable DASD disks without partitions on s390x (Harshal Patil)
* [11f16c02] Issue #962: Suggestion to check spec guidelines (Ramon Medeiros)
* [9873c493] For s390x hide Netboot template for Virtualization Add Template (Rajat Gupta)
* [42b48bde] Issue #1047: In xmlutils/interface.py --> get_iface_xml returns none for typ.. (Archana Singh)
* [6cd7db74] Merge branch 'next' (Aline Manera)
* [0268810c] Modified unit test cases to include new s390x specific features (Pooja Kulkarni)
* [ffb429e1] For s390x hide VNC, PCI, Snapshot, Graphics and clone options (Rajat Gupta)
* [197b0c01] Issue #999 : Attach storage to guest on s390x without libvirt (Harshal Patil)
* [33fd64ab] Issue #1045 : boot order fix for guest edit (Harshal Patil)
* [d5b62118] Introducing s390x UI Interfaces module for Edit Template under virtualization (Rajat Gupta)
* [bc0315a9] Introducing Console for edit Guest module under virtualization (Rajat Gupta)
* [84667a91] Introducing Console for edit template module under virtualization (Rajat Gupta)
* [1d17195a] added 'console' parameter to vms api for s390x (Suresh Babu Angadi)
* [2760baa5] added 'console' parameter to templates api for s390x (Suresh Babu Angadi)
* [a8f17b8d] Introducing s390x UI Storage module for Edit Guest under virtualization (Rajat Gupta)
* [794b6125] Introducing s390x UI Storage module for Edit Template under virtualization (Rajat Gupta)
* [800b30ab] Fix for Issue #1000 : Make Check fails on s390x environment (Pooja Kulkarni)
* [b259b1da] Issue #992 : Create template on s390x without libvirt storage. (Harshal Patil)
* [6652b317] Introducing s390x UI Interfaces module for Edit Guest under virtualization (Rajat Gupta)
#### [2.3.1] ####
* [4d690f76] Updates for 2.3.1 release (Aline Manera)
* [ec5658e3] Use libvirtd service in Ubuntu (Lucio Correia)
* [e4fb62dd] Bug fix #1057: Failed to import kimchi (Bianca Carvalho)
* [a5497c2d] Bug fix #1026: CentOS: Unable to get and update memory values for a powered .. (Ramon Medeiros)
* [6757a209] Add more details to error message when probing image (Lucio Correia)
* [3d1fc459] Add missing dependency to documentation (Lucio Correia)
* [dee34f1a] Bug fix #1066: Do not stora guest storage volume information on objectstore (Aline Manera)
* [5c520740] Bug fix #1015: Rename "Guest Name ID" header to "Guest Name" (Aline Manera)
* [9e63b30a] Fix checking for libvirt daemon on Ubuntu (Lucio Correia)
* [44484b4c] Fixed resize volume click input number in virtualization->storag (Rajat Gupta)
* [627ded4d] Recognize openSUSE 42.2 ISO (Aline Manera)
* [17e54c23] Edit Guest: block CPU settings when guest is running or paused (Daniel Henrique Barboza)
* [0fb58402] Changing 'threads' to be a free number field (Daniel Henrique Barboza)
* [72276c29] Edit Guest dialog: fixing 'Save' button on Processor tab (Daniel Henrique Barboza)
* [087eeeae] Adding CPU setup help text in Edit Guest/Template (Daniel Henrique Barboza)
* [1f661880] CPU configuration UI: several improvements (Daniel Henrique Barboza)
* [dbd0be5c] Adding 'Processor' tab in Edit Guest dialog (Daniel Henrique Barboza)
* [cc171721] template_edit_main.js: initProcessor now a global function (Daniel Henrique Barboza)
* [58d7dfa3] Adding 'sockets' field in the topology of Templates (Daniel Henrique Barboza)
* [dcad16ac] Bug fix #1072 - changing vpus verification (Daniel Henrique Barboza)
* [2d1754e1] rpmlint fixes on Fedora and Suse specs (Daniel Henrique Barboza)
* [3c5858c8] Issue #1050: Rename template with existing template name (Archana Singh)
* [a79b8421] Fixed issue #1074 IP address for the guest under Interfaces tab is blank (Rajat Gupta)
* [34731ea8] Remove URI configuration from kimchi.conf file (Aline Manera)
* [6645190d] Issue #1059: Not able to save corrected img path after editing img based tem.. (Archana Singh)
* [f07434ea] Wok issue #173: Set tab color on tab-ext.xml and update SCSS files (Aline Manera)
* [6be9c5a6] Wok issue #174: Let Wok create the whole navigation bar (Aline Manera)
* [78234e8d] Issue: #1008 Issues while editing a VEPA network (Ramon Medeiros)
* [1cb0fb79] PCI hotplug: Check USB controller, define in template, add test in Power (Lucio Correia)
* [22dcbcc3] Issue #651: Windows guests - default mouse type causing problems (Ramon Medeiros)
* [a12707e8] Improve multifunction attach/detach operations (Lucio Correia)
* [c7ae10d9] Improve Fedora 24 identification (Lucio Correia)
* [1e34ce36] Adding libvirt remote connection verification (Daniel Henrique Barboza)
* [241ce3dd] Github #1007: Fixing non-root ssh key generation (Daniel Henrique Barboza)
* [0c05aa1e] Github #1007: use provided user for password-less setup (Daniel Henrique Barboza)
* [41c669ff] Remove PowerKVM checks from memory alignment code (Lucio Correia)
* [a9385512] Use tablet_bus for tablet input instead of kbd_bus (Ramon Medeiros)
* [237705f8] Issue #1006: Invalid subnet value when editing a network raise an error (Ramon Medeiros)
#### [2.3.0] ####
* [337f2b26] Update ChangeLog, VERSION and po files to 2.3 release (Aline Manera)
* [2156589e] Improve storage volume creation of XML (Paulo Vital)
* [55247e61] Fixed noTemplate message display (Rajat Gupta)
* [136b3355] Fix make-rpm target (Aline Manera)
* [e5e65f36] Issue #1018 - Disable volume resize option on logical pool. (Paulo Vital)
* [bef852c5] Fix max number of memory slots for Ubuntu on Power (Lucio Correia)
* [ef53757d] Issue #1017: Fix upload file to logical storage pool. (Paulo Vital)
* [b953abe7] Fix issue #1019: Hide storage volume actions menu for iSCSI/SCSI pools (Aline Manera)
* [74d22c60] Bug fix #521: Extend logical pool (Aline Manera)
* [4e048f09] Fix issue #1022: Remove 'Clone' option for running guests (Aline Manera)
* [c5dd8ac1] Bug fix: Recognize Fedora 24 ISO (Aline Manera)
* [e7fa5501] Fix issue #1005: Proper display paused guests on Gallery View (Aline Manera)
* [9c1e2769] Bug fix: Disable "Search More ISOs" button on create Template dialog when th.. (Aline Manera)
* [5a885b04] Fix issue #1020: Fix alert icon position to do not overlay img/iso icon (Aline Manera)
* [460aa9ea] Fix issue #1020: Verify libvirt access on real file path instead of symlink (Aline Manera)
* [f6c53ad8] Remove legacy check_files on Makefile (Aline Manera)
* [905d7416] Issue #1012: Boot order gets reset to only one entry after editing a VM (Ramon Medeiros)
* [4182a245] Issue #585: 'make clean' does not revert its changes from 'make rpm' (Bianca Carvalho)
* [35548598] Fix issue #1010: Convert disk size to bytes while attaching new disk to guest (Aline Manera)
* [e1d75161] remote iso listing for s390x (Suresh Babu Angadi)
* [2b7becb1] Storagebuttons not behaving properly (Socorro)
* [5b50ff81] Create test to verify graphics type change (Ramon Medeiros)
* [68914bbf] Issue #836: Allow user change guest graphics type (Ramon Medeiros)
* [17a0895c] Issue #994: SPICE graphics does not need tag (Ramon Medeiros)
* [ce832419] For s390x architecture, serial type is not validated in vm xml as as not sup.. (Archana Singh)
* [bde5a6fc] Issue# 973 Emphasize resource name in dlg (Socorro)
* [f62f79fd] Updated API.md for addition paramters support for VM ifaces API on s390x/s39.. (Archana Singh)
* [6f1b3030] Updated code to support VM ifaces on s390x/s390 architecture. (Archana Singh)
* [e54afa3a] Updated API.md for addition interfaces paramter in template API. (Archana Singh)
* [bf08ecda] Updated code to support 'interfaces' parameter to template API only on s390x.. (Archana Singh)
* [e5a54e96] /plugins/kimchi/ovsbridges API (Suresh Babu Angadi)
* [19bcfe4f] Issue #606: Change icon to distinguish image generated template and iso gene.. (Samuel Guimarães)
* [38bbef00] Issue #939: [UI] Guest tab is not rendered correctly if guests are not in 'r.. (Samuel Guimarães)
* [59d6d1f7] Issue #921: Peers button disappears (Samuel Guimarães)
* [ad1aa1bf] Enhancement to /plugins/kimchi/interfaces (Suresh Babu Angadi)
* [02eaa0af] Enhancement to /plugins/kimchi/interfaces (Suresh Babu Angadi)
* [8169f9ab] Issue #626: Snapshot revert does not release storage volume (Bianca Carvalho)
* [71fb00d6] Update tests (Ramon Medeiros)
* [381232c0] Do not remove storagepools linked to guests (Ramon Medeiros)
* [7bd7a398] mockmodel.py: fixing virtviewerfile_tmp path (Daniel Henrique Barboza)
* [37e038d6] Only on s390x add default networks to template if template.conf has default .. (Archana Singh)
* [5df29fd0] Update usage of add_task() method. (Paulo Vital)
* [174ee3f7] Check if VM is off before detaching multifn PCI (Jose Ricardo Ziviani)
* [5cec2dc0] Github #986: create '/data/virtviewerfiles' dir automatically (Daniel Henrique Barboza)
* [4e0b34f3] Revert "Fix frontend vcpu hotplug" (Jose Ricardo Ziviani)
* [1a2dd0d0] Fix when calling error message in storagepool (Ramon Medeiros)
* [fbdc2380] Issue #933: Invalid image path not marking template as "invalid" (back-end) (Ramon Medeiros)
* [c08ee489] test/test_model.py pep8 1.5.7 fix (Ramon Medeiros)
* [f44ae6ba] Issue #982 - Fix broken testcases. (Paulo Vital)
* [036feb4f] Update docs (Ramon Medeiros)
* [ffed3ff2] Update tests (Ramon Medeiros)
* [3038958d] Issue #857: Support VM description (Ramon Medeiros)
* [ea0c25d3] Issue #317 Inconsistent button status when adding or creating new resources (Socorro)
* [47492402] Prevents pci passthrough double click (Jose Ricardo Ziviani)
* [14c73318] Fix frontend vcpu hotplug (Jose Ricardo Ziviani)
* [14ebd3a7] Issue #585: 'make clean' does not revert its changes from 'make rpm' (Bianca Carvalho)
* [7fb936a8] model.py: use the new 'get_all_model_instances' utils function (Daniel Henrique Barboza)
* [fd1a6fb7] Modified code, to return distro and version as unknown, if guestfs import fa.. (Archana Singh)
* [2ceda61a] Added s390x architecture support in osinfo params. (Archana Singh)
* [4839a5a4] Added on_poweroff, on_reboot, on_crash tag to also support s390x architecture. (Archana Singh)
* [5f036f48] Added method for implementation of s390x boot detection. (Archana Singh)
* [04cca253] Added check for s390x architecture to not add graphics in params as not supp.. (Archana Singh)
* [94c84a36] Issue #604: Windows XP: Kimchi should set the right NIC Type in Templates (Ramon Medeiros)
* [ca99bda1] Revert "Use verbs in the past" (Lucio Correia)
* [21437ef1] Updated serial console to support s390x architecture. (Archana Singh)
* [75fafad4] Validate passthrough inside the task (Jose Ricardo Ziviani)
* [bd946a22] Replace device companion check before the passthrough (Jose Ricardo Ziviani)
* [ec8dad4a] Improve PCI passthrough performance (Jose Ricardo Ziviani)
* [72a97ac4] Add test to verify bootmenu and update old tests (Ramon Medeiros)
* [b9fe3170] Allow guest to enable bootmenu on startup (Ramon Medeiros)
* [e5095568] Disable vm statistics/screenshots in edit guest (Jose Ricardo Ziviani)
* [6d0f5fb1] Issue #968: Kimchi is searching for 'undefined' VM (Samuel Guimarães)
* [40a3e430] Add test to check bootorder (Ramon Medeiros)
* [18d71642] Add function to retrieve bootorder on vm lookup (Ramon Medeiros)
* [88f48064] Update REST API (Ramon Medeiros)
* [eef289c5] Update documentation about bootorder on vm update (Ramon Medeiros)
* [755ded20] Create method to change bootorder of a guest (Ramon Medeiros)
* [d0595d91] Add function get_bootorder_node (Ramon Medeiros)
* [2fd0d584] Virt-Viewer launcher: mockmodel changes (Daniel Henrique Barboza)
* [ec34b6e3] Virt-Viewer launcher: changes after adding libvirt event listening (Daniel Henrique Barboza)
* [c9725854] Virt-Viewer launcher: libvirt events to control firewall (Daniel Henrique Barboza)
* [f746c9e9] Virt-Viewer launcher: test changes for firewall manager (Daniel Henrique Barboza)
* [e515b96d] Virt-Viewer launcher: adding FirewallManager class (Daniel Henrique Barboza)
* [90e7b2f9] Virt-Viewer launcher: test changes (Daniel Henrique Barboza)
* [e2aafc6c] Virt-Viewer launcher: virtviewerfile module (Daniel Henrique Barboza)
* [260d0e40] Virt-Viewer launcher: control/vms.py and model/vms.py changes (Daniel Henrique Barboza)
* [ae7fd9fb] Virt-Viewer launcher: Makefile and config changes (Daniel Henrique Barboza)
* [b70a7e0a] Virt-Viewer launcher: docs and i18n changes (Daniel Henrique Barboza)
* [ccc004ee] Kimchi kills Wokd due to sys.exit() calls in files networks.py and storagepo.. (Bianca Carvalho)
* [f41762de] Issue #969: Error message showing up in parent panel rather than modal windo.. (Samuel Guimarães)
* [9fbee80d] Send (de)attach fail messages to tasks (Jose Ricardo Ziviani)
* [cd670a43] Handle libvirt events for device attachment/detachment (Jose Ricardo Ziviani)
* [b915380b] Issue #956: Unable to assign pci passthrough devices through kimchi (Samuel Guimarães)
* [64f348bd] Added cursor for tasks in progress (Samuel Guimarães)
* [57012d73] Add UI netboot support for adding templates; add loading icon when switching.. (Socorro Stoppler)
* [e54745aa] Show error message for untracked and failed cloning tasks (Lucio Correia)
* [3da920f6] Disable ISOs templates with wrong permission (peterpennings)
* [4c269c63] Save last view for templates - fix for issue# 799 (Socorro Stoppler)
* [c202b8cd] model/vms.py: changing all interfaces VM (Daniel Henrique Barboza)
* [d82768e8] Github #972: spice-html5 dir incorrect (Daniel Henrique Barboza)
* [de78b0df] Update unit tests to changes in Remote links. (Paulo Vital)
* [fb7adc17] Update Ubuntu remote images. (Paulo Vital)
* [48a31d16] Update OpenSUSE remote images. (Paulo Vital)
* [2bb59c6c] Update Gentoo remote images. (Paulo Vital)
* [70f37927] Update Debian remote images. (Paulo Vital)
* [306517ec] Update Fedora remote images. (Paulo Vital)
* [e0150151] Issue #965: Recognize Fedora 24 ISO image. (Paulo Vital)
* [442555de] Issue #948: Kimchi not throwing errors when migration is performed and gives.. (Samuel Guimarães)
* [8e5448f6] Make sure all log messages have required parameters (Lucio Correia)
* [175babf4] VM migrate: generic remote path check (Daniel Henrique Barboza)
* [a894fc35] Avoid break Wok when register events, if Libvirt is down (Rodrigo Trujillo)
* [90d99f9b] Do not break the logging of failed requests (Lucio Correia)
#### [2.2.0] ####
* [9751cbcb] Update ChangeLog, VERSION and .po files for 2.2 release (Aline Manera)
* [b69bec63] Fixing Opensuse Leap package name (Daniel Henrique Barboza)
* [329545ef] Handle URLError exception when creating Template. (Paulo Vital)
* [4150bb81] Use qxl driver only for x86 (Lucio Correia)
* [bcef66f8] Fix typo in API.md (Rodrigo Trujillo)
* [a8331d1d] Update tests to reflect new behavior (Lucio Correia)
* [c87d06c9] Use ASCII name in XML (Lucio Correia)
* [b47f1fd6] Always update snapshot XML with new name and UUID (Lucio Correia)
* [5f9e9368] Add loading icon for guests tab (Socorro Stoppler)
* [08b91af3] Save view for Guests tab (Socorro Stoppler)
* [d20a0692] Improve UI error codes checking (Ramon Medeiros)
* [9feaa044] Fix storage volume clone test case (Aline Manera)
* [1cc9a2c7] Change PPC memory slots to 256 (Rodrigo Trujillo)
* [7a5e9507] Pass only those fields that have been modified in Edit Guest; Match maxmem t.. (Socorro Stoppler)
* [53233722] Fixed Storage Volume upload error message when switching tabs (Samuel Guimarães)
* [095eb5bd] Do not use default value when declare a function (Ramon Medeiros)
* [d9150424] Clean FEATURETEST_VM effectively. (Paulo Vital)
* [345f1420] Substitute quotes by apostrophe in configuration file (Rodrigo Trujillo)
* [e7f2f965] Github #934: fix storage pool name in template-edit.html.tmpl (Daniel Henrique Barboza)
* [e9d54d1f] Properly display network interfaces when more than one exists (Socorro Stoppler)
* [26b4a39a] Storage Volume management (Samuel Guimarães)
* [5d790a2d] Add missing test dependency: bc (Lucio Correia)
* [01bf4c1c] Use Wok session timeout value to configure serial console (Aline Manera)
* [bb66a06a] Implement multi-function pci hotplug support (Jose Ricardo Ziviani)
* [8232b650] Enable hot-plug multi-function pci on front-end (Jose Ricardo Ziviani)
* [b6c7a5eb] Load Kimchi when started by command line and libvirt is not running (Rodrigo Trujillo)
* [25f2d72c] Remove notification message if Libvirt is back (Rodrigo Trujillo)
* [e842ce02] Improve Kimchi feature tests output (Rodrigo Trujillo)
* [8db0f919] Fixed Clone Guest modal window (Samuel Guimarães)
* [c2c04c52] Handle Libvirt host ENOSPC event (Lucio Correia)
* [ac18b506] Decrease the sleep time for libvirt event timout (Jose Ricardo Ziviani)
* [4ab1dc13] Add support to Libvirt Events. (Paulo Vital)
* [b846128c] Isolate unit tests execution. (Paulo Vital)
* [98fe8623] UI fixes for edit virtual network (Aline Manera)
* [57846a1f] Edit Virtual Network with passthrough support (Socorro Stoppler)
* [da5d85d0] Add test case to test new slots value implementation (Rodrigo Trujillo)
* [1eb42f8d] Modify max memory slots default numbers (Rodrigo Trujillo)
* [52659714] Passthrough macvtap network support: UI changes (Daniel Henrique Barboza)
* [fdacdf13] Passthrough macvtap network support: model and test changes (Daniel Henrique Barboza)
* [aca5dfb6] Passthrough macvtap network support: doc changes (Daniel Henrique Barboza)
* [d1074dfa] Make static and live update functions independent (Rodrigo Trujillo)
* [cc1b8357] Modify mockmodel to support memory devices (Rodrigo Trujillo)
* [46a53660] Modify tests to support mem devs with different sizes (Rodrigo Trujillo)
* [e507d5ed] Change memory hotplug to support more than 32GB (Rodrigo Trujillo)
* [4b578d45] Update Fedora iso url to fix test (Rodrigo Trujillo)
* [a53905b5] Use verbs in the past (Lucio Correia)
* [a68af30e] Add translation to user log messages (Lucio Correia)
* [7de77c7e] Fix issue on network update (Lucio Correia)
* [1bd17be6] Add support to check if libvirtd is running. (Paulo Vital)
* [0a30faa1] Make Cheerypy up if not able to connect to libvirt (Paulo Vital)
* [5368b34a] Update Kimchi config file for Systemd service (Paulo Vital)
* [74373506] Check if qemu/libvirt user has permission to use the image (Jose Ricardo Ziviani)
* [fa90297d] Add new unit test for memory hotplug in PowerPC (Rodrigo Trujillo)
* [3c760b68] Implements support to memory hotplug in non-NUMA guests (Rodrigo Trujillo)
* [c91eab69] Filter VEPA interfaces: JS changes (Daniel Henrique Barboza)
* [3135f021] Filter VEPA interfaces: adding 'module' to interfaces API (Daniel Henrique Barboza)
* [739b6415] Fix memory return in vm with memory devices hotplugged (Rodrigo Trujillo)
* [73494572] Does not use slot in memory device removal (Rodrigo Trujillo)
* [a83a70bf] Added loading icon and 'Creating' for create template (Socorro Stoppler)
* [b17ba052] Fixed "Add Template" modal window alignment (Samuel Guimarães)
* [0e28c09e] Adding 'source_media' docs in docs/API.md (Daniel Henrique Barboza)
* [8fbad6d5] Bug fix: Do not allow user selects invalid volume format to create a new vol.. (Aline Manera)
* [feaf3301] Bug fix: Display error when creating new disk to attach to guest (Aline Manera)
* [1403939b] Bug fix: Allow creating network with XML special characters (Aline Manera)
* [56f79e94] Create template error message not being displayed in panel (Socorro Stoppler)
* [5566b943] Bug fix: Create VM based on Remote ISO Template (Aline Manera)
* [f33728a8] Migration to Gingerbase netinfo: removing netinfo.py (Daniel Henrique Barboza)
* [48e7e3e4] Migration to Gingerbase netinfo: import changes (Daniel Henrique Barboza)
* [70682383] VEPA network UI: fixing network creation (Daniel Henrique Barboza)
* [9e7ba41b] Remove cherrypy configuration from kimchi.conf file (Aline Manera)
* [9f28117b] Disable Template when it has invalid parameters (Samuel Guimarães)
* [00ce7d57] Fix logging and error messages in objectstore upgrade (Rodrigo Trujillo)
* [81e0429b] Update UI to reflect modifications in template API (Paulo Vital)
* [fec9dff3] Update test cases to support netboot. (Paulo Vital)
* [2cdbd12f] Add support to create guests to netboot. (Paulo Vital)
* [696cacfb] Add support to create netboot templates. (Paulo Vital)
* [45627aa5] Do not use systemd private tmp dir (Jose Ricardo Ziviani)
* [89ccfede] Issue #931 Error when editing a template created using a disk image (Ramon Medeiros)
* [24479725] Fix typo and integer values validation in Guest edit UI (Rodrigo Trujillo)
* [e045477d] Add error message when empty disks list is passed in Template edit API (Rodrigo Trujillo)
* [d3620839] Move capabilities to model constructor (Jose Ricardo Ziviani)
* [14cb6bc4] Change nfs host from localhost to 127.0.0.1 (Jose Ricardo Ziviani)
* [bc3af2d7] Avoid race condition in vm lookup (Rodrigo Trujillo)
* [9b8f7cf5] Create Template UI adjustments based latest API changes (Socorro Stoppler)
* [b9acc9c4] Issue #920: Template is removed if an ISO doesn't exist (Jose Ricardo Ziviani)
* [d929807c] Make detach device return an AsyncTask (Paulo Vital)
* [a6d74aee] Make attach device return an AsyncTask (Paulo Vital)
* [a1c4dd12] Issue #924: Update test case with new storage pool field (Jose Ricardo Ziviani)
* [40afe5c0] Issue #924: Disable deactivate/delete buttons if storage is in use (Jose Ricardo Ziviani)
* [6a958b69] Issue #924: Add field to inform front-end if storage is in use (Jose Ricardo Ziviani)
* [13bbaa0d] Add network update tests (Lucio Correia)
* [93ce78e6] Add backend support for editing virtual networks (Lucio Correia)
* [3f83dc29] Improve checking of cpu_info API (json schema) (Rodrigo Trujillo)
* [f88956c9] Fixed some issues with SCSS after adding compact() mixin to Wok (Samuel Guimarães)
* [cc0036c4] Issue #924: Before deleting a storagepool, kimchi should check if any templa.. (Jose Ricardo Ziviani)
* [b5f5f419] Issue #919: Deactivate a storagepool makes the list of templates blank (Jose Ricardo Ziviani)
* [d2bb62ad] Adjust UI to create Template according to the latest API changes (Aline Manera)
* [150091e7] Change "Memory Available" by "Memory Utilization" (Rodrigo Trujillo)
* [668b9046] Issue #923: Template always shows VNC, even if I save Spice in my template (Jose Ricardo Ziviani)
* [f5cebc0e] Add new tests to verify source_media feature (Ramon Medeiros)
* [c508d1cb] Update tests (Ramon Medeiros)
* [4e28b854] Identify installation media while creating template (Ramon Medeiros)
* [5c6f88ec] Create a single field to pass the installation media (Ramon Medeiros)
* [1bb5a717] Fix template creation from image file (Jose Ricardo Ziviani)
* [f0b83456] Test if CPU value is higher than Max CPU before request (Rodrigo Trujillo)
* [74203a34] Bug fix: Use 256MB of memory on feature tests due restriction on Power machi.. (Aline Manera)
* [0590e385] Add support to recognize latest CentOS version (Rodrigo Trujillo)
* [46473b64] Check memory values in UI before submit request (Rodrigo Trujillo)
* [8e1880a3] Fix memory value return when hotplug memory devs (Rodrigo Trujillo)
* [f0673281] Enabling multiselect for VEPA networks (Samuel Guimarães)
* [df0091c8] Remove View Console link from guests that doesn't support vnc/spice (Jose Ricardo Ziviani)
* [d3a1ea20] Change CPU Number/CPUs to Current CPU Number/Current (Socorro Stoppler)
* [66f36078] Add UI support to clone a guest multiple times (Rodrigo Trujillo)
* [adfec892] Fix issue when clone a vm multiple times (Rodrigo Trujillo)
* [f3014684] Add function 'get_next_clone_name' (Rodrigo Trujillo)
#### [2.1.0] ####
* [ad5caec0] Update ChangeLog, VERSION and .po files for 2.1 release (Aline Manera)
* [b319d79e] Issue #838: UI - Blocks maxmemory input field (Rodrigo Trujillo)
* [d20ac598] Issue #838: Extend memory hotplug feature test (Rodrigo Trujillo)
* [dba63dcd] Adding wok version dependency (Daniel Henrique Barboza)
* [2a22d3a7] Update po files for 2.1 release (Aline Manera)
* [8bb0a5b5] Move 'template.conf' to /etc (Rodrigo Trujillo)
* [8986e073] Fix issue #840: Change distros.d internal path (Rodrigo Trujillo)
* [2f96e505] Issue #788: Network information mismatch in template creation (Samuel Guimarães)
* [80ab22db] Issue #818: Frontend doesn't update the PCI tab after a PCI attachment (Samuel Guimarães)
* [818f7c37] Issue #809: PCI filter does not seem to work (Samuel Guimarães)
* [0555dd4d] Fix problem when removing window size fo GPU (Jose Ricardo Ziviani)
* [9423c560] Issue 814: UI just show exported NFS path when clicked twice at field (Samuel Guimarães)
* [fc1306c9] Check if guest is listening to serial before connecting to it (Jose Ricardo Ziviani)
* [43dde741] Make serial console timeout configurable (Jose Ricardo Ziviani)
* [474353c5] Improve log messages printed by the serial console (Jose Ricardo Ziviani)
* [385acdd8] Move unix socket files from /tmp to /run (Jose Ricardo Ziviani)
* [bea47b08] Issue #847: Save button is having wrong behavior when edit a running Guest (Samuel Guimarães)
* [74bf39d6] Remove useless function 'validate_repo_url' from Kimchi (Rodrigo Trujillo)
* [82389e94] Fixed "Add a Storage Device to VM" modal behavior (Samuel Guimarães)
* [1e86c354] Fix showing of memory/cpu for guest and templates (Socorro Stoppler)
* [b178c020] Removing disks.py because it was moved to gingerbase (Jose Ricardo Ziviani)
* [67a8d320] Fix issue #849: Get network name for bridged networks (Aline Manera)
* [fa5a662b] Issue #859 - Fix error when adding new disk to VM. (Paulo Vital)
* [d17dbaff] Increase guest Max Memory limits (Rodrigo Trujillo)
* [ee648008] Bug fix: Remove storage volume file while removing the storage volume (Aline Manera)
* [64d3f30e] Customize user request log messages (Lucio Correia)
* [9c790baf] Fix minor issues in Kimchi UI: Template CPUs and Guest CPUs (Rodrigo Trujillo)
#### [2.1.0-rc1] ####
* [4092eccc] Multiple fixes in Gallery and List views for Templates and Guests tabs (Samuel Guimarães)
* [b5b737a0] Adding gallery view to guest tab and minor fixes to templates tab (peterpennings)
* [5985376a] Fix test case: Proper check memory and cpu_info information (Aline Manera)
* [5be0dac4] Fix pep8 1.6.2 error W503 in model/vms.py (Daniel Henrique Barboza)
* [27fe22b7] Create test cases for GPU attachment (Jose Ricardo Ziviani)
* [486d8757] Set mmio memory when GPU is attached (Jose Ricardo Ziviani)
* [4c0c7d04] Fixed navbar order (Samuel Guimarães)
* [3a1e8083] Fix memory values in guest with attached memory devices (Rodrigo Trujillo)
* [796fd446] Added Kimchi SVG logo for login page, footer and about window (Samuel Guimarães)
* [753b2f71] Update pkg-version script to work with submodules (Aline Manera)
* [56f99317] Add release number to Kimchi version (Aline Manera)
* [713bbf20] Adding maxmemory for guest and templates (Samuel Guimarães)
* [de111059] Changes and add tests to support new memory API (templates/guest) (Rodrigo Trujillo)
* [92fc1a09] Add support to edit max memory in Guest (Rodrigo Trujillo)
* [cb4fc7aa] Add function to update 'memory' in objectstore (Rodrigo Trujillo)
* [ab1475f8] Add support to edit max memory in Templates (Rodrigo Trujillo)
* [c8ddfd48] Update copyright according to make check-local result (Aline Manera)
* [7ab994f5] Verify IBM copyright on make check-local (Aline Manera)
* [bb628f58] Remove help and screenshot URI configuraton from kimchi.conf file (Aline Manera)
* [c2255212] Update the API document (Jose Ricardo Ziviani)
* [33d99bb0] Disable hotplug of graphic card devices in the frontend (Jose Ricardo Ziviani)
* [bf658f07] Disallow hotplug of graphic cards because it is no supported (Jose Ricardo Ziviani)
* [2e07f10e] Create logical pool from existing VG (peterpennings)
* [6ebd083c] Add maxvCpu support UI for guest and template (Socorro Stoppler)
* [e45f37f7] VEPA network support: UI changes (Daniel Henrique Barboza)
* [088debc7] VEPA network support: additional backend unit tests (Daniel Henrique Barboza)
* [e4aa225c] VEPA network support - models and xmlutils changes (Daniel Henrique Barboza)
* [947b2014] VEPA network support: API and i18n changes (Daniel Henrique Barboza)
* [57f9bf02] Changing network API: UI changes (Daniel Henrique Barboza)
* [c595590c] Changing network API: unit test changes (Daniel Henrique Barboza)
* [ca8bad37] Changing network API: control and model changes (Daniel Henrique Barboza)
* [9bb95b58] Changing network API 'interface' to array: docs and API (Daniel Henrique Barboza)
* [81819362] Bugfix 804: Disable connect vnc when VM is powered off (Jose Ricardo Ziviani)
* [b5c1ee16] Bugfix 843: Add sourceURL comment for kimchi.min.js (Jose Ricardo Ziviani)
* [5a9b3593] Add test case for the socket server (Jose Ricardo Ziviani)
* [036db7b7] Update the build system to make the serial console (Jose Ricardo Ziviani)
* [a789ecd4] Implement the Kimchi front-end for the web serial console (Jose Ricardo Ziviani)
* [d563214b] Implement the web serial console front-end (Jose Ricardo Ziviani)
* [2abd24b7] Import term.js to Kimchi project (Jose Ricardo Ziviani)
* [14b49749] Implement the backend to support web serial console (Jose Ricardo Ziviani)
* [ff56e7ab] Implement the web serial console server (Jose Ricardo Ziviani)
* [79348fa2] Rename vnc.py to websocket.py (Jose Ricardo Ziviani)
* [b8340346] Update tests (Lucio Correia)
* [5d13f6c4] Add graphics settings merge to template update (Lucio Correia)
* [c9a10e91] test_mock_network.py: fixes due to backend changes (Daniel Henrique Barboza)
* [dfcc4b41] Issue #791: New UI for adding network bridges (peterpennings)
* [3506b7f2] Fix handling of VLANs in backend (Lucio Correia)
* [0b51e568] Create new volume with .img extension and attach to VM (Socorro Stoppler)
* [7503b61c] Update tests (Lucio Correia)
* [8138df47] Do not break web UI (Lucio Correia)
* [f31d2c70] Add maxvcpus attribute to guests (Lucio Correia)
* [da8475b5] Add maxvcpus attribute to templates (Lucio Correia)
* [c3306480] Add python-pillow as RPM dependency. (Paulo Vital)
* [3e2a1c5b] Fix error message for IOMMU configuration. (Paulo Vital)
* [a7b57f3f] Remove hack that disables vhosts-net (Ramon Medeiros)
* [2af23fb4] Fix add storage device to VM using existing disk (Socorro Stoppler)
* [cb8e91e7] Whitespace fixes in existing code (Daniel Henrique Barboza)
* [9120a029] Makefile.am targets enhancements (Daniel Henrique Barboza)
* [3f20f358] Memory hot plug front-end (peterpennings)
* [08a91fa2] Implementing sort for Templates tab (Samuel Guimarães)
* [e891856a] Add federation and create_iso_pool options to Kimchi configuration file (Aline Manera)
* [9e7689a0] Use the cached values for wok config when required (Aline Manera)
* [31410ea9] Remove authentication method information from Kimchi (Aline Manera)
* [024f6e93] Update Kimchi configuration according to recent changes on Wok (Aline Manera)
* [26ea40c6] Live Migration front-end (samhenri)
* [686efbb8] Initial checkin for live migration UI support (Socorro Stoppler)
* [73dbf411] Add support for websockify 0.7 (Ramon Medeiros)
* [7cf68d5a] Start up websockify on localhost (Rob Lemley)
* [341b29d7] Update README (Aline Manera)
* [2745b545] Update /plugins/kimchi/config API to only return information related to Kimchi (Aline Manera)
* [7fd1bc2b] Add support to passtrhough 3D graphic controllers (Jose Ricardo Ziviani)
* [756b1154] Add opensuse LEAP to remote ISOs (Ramon Medeiros)
* [e51eca8b] Issue #816: kimchi.conf isn't pointing to libvirt service on ubuntu 15.10 (Ramon Medeiros)
* [c5d74065] Fix issue #810 (Lucio Correia)
* [e8eae7d4] Fixed minor UI issues when saving edited template (samhenri)
* [5197de6b] Supress HTTPS certification checking on tests (Ramon Medeiros)
* [39173db4] Identify opensuse-LEAP-42.1 ISO (Ramon Medeiros)
* [5bbcc1e3] Do not rely on python-pip to install build dependencies (Aline Manera)
* [26cc0325] Fix Portuguese translations for storage pool. (Leonardo Garcia)
* [d45e963e] Adding Gallery View at Templates screen (Andre Teodoro)
* [dabf9f04] Ignore pool.refresh if it cannot be called (Jose Ricardo Ziviani)
#### [2.0.0] ####
* [e65ca2aa] Update ChangeLog and po files for 2.0 release (Aline Manera)
* [e0bcb980] Add python-paramiko package as Kimchi dependency (Aline Manera)
* [058c5e43] Bug fix: Get the right guest name when creating/cloning a guest (Aline Manera)
* [1e5d1561] Fix and add tests to related to max memory in xml (Rodrigo Trujillo)
* [ccafde2e] Issue #753: Adds max_memory checkings and settings properly (Rodrigo Trujillo)
* [0bacfeac] Issue #753: Remove max memory settings from osinfo.py (Rodrigo Trujillo)
* [b91d9dba] Use always flag as a fallback (Lucio Correia)
* [43dc0a9a] Use correct gettext package for building (Lucio Correia)
* [88a49503] Issue 776: Adding filter on Guest screen (samhenri)
* [977c5a5c] Moved Kimchi SCSS files from Wok to Kimchi (samhenri)
* [07ca3c2a] Remove useless messages (Aline Manera)
* [bc994eee] Update Kimchi objectstore versioning. (Paulo Vital)
* [bc6e4bb5] Issue 784: Display a 'loading gif' when waiting for data (samhenri)
* [cd71a49b] Issue 777: Network tab not being updated after exclude a network (samhenri)
* [bc565ca3] New i18n strings in PT-BR (samhenri)
* [590758aa] Issue 776: Adding filter on Templates screen (samhenri)
* [9418b85c] Issue 783: Error message hidden by the modal window (samhenri)
* [43878152] Issue 773: Snapshot error message showed behind edit window (samhenri)
* [9e11fe7e] Issue 772: Template tab and Template edit window - Some problems (samhenri)
* [80000f16] Issue 770: New template is not shown right after creation (samhenri)
* [d625f64f] Removed theme-default.min.css reference (samhenri)
* [17cd24ab] Update openSUSE version in the README file (Aline Manera)
* [c76cef47] Add ginger-base as Kimchi dependency (Aline Manera)
* [5d55f476] Fix disk creation when pool is netfs (Ramon Medeiros)
* [a6428f2c] Fix screen freezing when upload file for storage volume (Socorro Stoppler)
* [383579f7] Disable hotplugging buttons of multi-function devices (Jose Ricardo Ziviani)
* [a5aa72cd] Add multi-function field in PCI information (Jose Ricardo Ziviani)
* [3d0bb0a4] Remove required authentication from / (Aline Manera)
* [e13c113b] Expose HTML tabs files in a specific /tabs URI (Aline Manera)
* [d32bc843] Multiple changes in guest maxMemory management (Rodrigo Trujillo)
* [01c18679] Fix test_async_tasks testcase. (Paulo Vital)
* [56510864] Fix range for network of NAT and isolated types. (Paulo Vital)
* [35d8c44c] Do not show OVS bridges for now (Lucio Correia)
* [8b7621c8] Fix ovs commands output handling (Lucio Correia)
* [6578bc73] Bugfix 786: Undefine button enabled for active storage pool (Socorro Stoppler)
* [4413d1c7] Use "macvtap" instead of "bridged" (Lucio Correia)
* [d43a3e56] Differentiate network lookup between macvtap and bridge (Lucio Correia)
* [71e29828] Restore control/config.py (Aline Manera)
* [0e01dcef] Bugfix 785: Create a template from an existing image (Socorro Stoppler)
* [a602f7d0] PATCH] Bugfix 782: Fix creating storage pools (Jose Ricardo Ziviani)
* [ac67aa63] bug fix: Update UI according to changes on /networks API (Aline Manera)
* [14304e3f] Change UI to support remotion of 'storagepool' from template backend (Rodrigo Trujillo)
* [59398626] Fix tests and backend after remove 'storagepool' from templates (Rodrigo Trujillo)
* [1623c153] Add script to upgrade objectstore to support new Template disks schema (Rodrigo Trujillo)
* [c1c59fa8] Remove 'stogarepool' referencies from Templates code backend (Rodrigo Trujillo)
* [a12766e0] Test: Fix and add test related to disks in templates (Rodrigo Trujillo)
* [bbfae4c4] Update VCPU by using libvirt function (Rodrigo Trujillo)
* [b45cd878] UI - Implement multiple disks support in Template edit window (Rodrigo Trujillo)
* [d93da9c9] Enable create guests with multiple disks from different pools (Rodrigo Trujillo)
* [94cb5640] Fix Template backend create/update for multiple disks (Rodrigo Trujillo)
* [fb8f54e0] PATCH] Bugfix 781: fix adding brigde network (Jose Ricardo Ziviani)
* [60aeceec] Reverting model/config.py deleted on last commit (Ramon Medeiros)
* [054e5198] Remove Wok code from Kimchi repository (Aline Manera)
* [48a799c8] Add Ginger Base as Wok submodule (Aline Manera)
* [d523ee0d] Remove Ginger Base from Kimchi repository (Aline Manera)
* [d0d10e67] Fix issue 766 - Define network interface in libvirt (Lucio Correia)
* [70afa669] Removed Administration / Ginger references from WOK ui assets (Andre Teodoro)
* [ab2954ba] Guests tab (samhenri)
* [be1cdb2d] Templates tab and modal windows bugfixes (samhenri)
* [ceec1507] Issue 728 : processor info displays blank for system z (Chandra Shekhar Reddy Potula)
* [26efbe5f] Ginger Base screen shot change to reflect new ui (Chandra Shekhar Reddy Potula)
* [3cfc67fa] Host tab functionality split into Dashboard and Updates (Chandra Shekhar Reddy Potula)
* [2fc0cdf8] Issue 728 - Processor Info in s390 architecture (Suresh Babu Angadi)
* [cd0bd2a3] Add checking for UI codes when running make check-local (Ramon Medeiros)
* [9e00ff5d] Fix WOK UI error messages (Ramon Medeiros)
* [8a027e32] Remove unused messages in Kimchi UI (Ramon Medeiros)
* [03299855] Edit Guests modal window (samhenri)
* [36880c4f] Add OVS bridges recognition support (Lucio Correia)
* [60510d11] Support Linux Bridge creation (Ramon Medeiros)
* [d211e07e] Add support for serial console (Ramon Medeiros)
* [a062d9c1] Add python-mock to README.md (Rodrigo Trujillo)
* [49b63356] Fix memory add aligment to 256 in PowerPC (Rodrigo Trujillo)
* [d67e7e3a] Create logical pool from existing VG (Aline Manera)
* [5aacaf21] Issue #746 : New navigation bar. (Atreyee Mukhopadhyay)
* [b4f02b24] Moved disks.py file from kimchi plugin to gingerbase plugin (Pooja Kulkarni)
* [71290f57] Issue #737: Wok base framework calls resource model's lookup twice (Archana Singh)
* [bb33c036] Gingerbase: adapting unit tests to use WoK /tests/utils.py (Daniel Henrique Barboza)
* [f9935dc9] Kimchi: updating unit tests to use WoK /test/utils.py (Daniel Henrique Barboza)
* [80d845fb] WoK: making /tests/utils.py available to all WoK plug-ins (Daniel Henrique Barboza)
* [23321ed6] Issue #755 : Action's states are showing in correctly for Repositories (Atreyee Mukhopadhyay)
* [33edb5a6] Change memory multipliers/divisors by bitwise operators (Rodrigo Trujillo)
* [9f912cde] Check and align number of memory slot to 32 in PowerPC (Rodrigo Trujillo)
* [e8ee482e] Check memory alignment in PowerPC to 256MiB (Rodrigo Trujillo)
* [21a5d03c] Live migration: unit tests for the new features (Daniel Henrique Barboza)
* [a58ee717] Live migration: model changes for the new features (Daniel Henrique Barboza)
* [45e89315] Live migration: new features changes in docs/API/i18n (Daniel Henrique Barboza)
* [485fe4f7] WoK: control/base.py: _generate_action_handler_base changes (Daniel Henrique Barboza)
* [8742922d] Add "io"="native" when creating a disk on Kimchi (Ramon Medeiros)
* [3f2b1c8e] Display guest IP address for each network interface (Socorro Stoppler)
* [176e34a7] shutdown and reboot actions on plain linux vs linux with KVM (chandrureddy)
* [f08bc9d9] Issue #757 : clean generated css files when 'make clean' executed (chandrureddy)
* [d61c3f59] Live migration backend: non-shared storage VM migration (Daniel Henrique Barboza)
* [d47ed663] Allow listStorageVolumes ajax call be synchronized (Rodrigo Trujillo)
* [4fdbb98e] Kimchi: Add m4/pkg.m4 to .gitignore (Aline Manera)
* [60c5fabc] Fix test case: Delete directory associated to the storage pool (Aline Manera)
* [a2c37b43] Fix issue #734: Update test case as libvirt issue was fixed (Aline Manera)
* [8fcb0ae7] Fix make check-local for Ginger Base (Aline Manera)
* [981b85c7] Update COPYING file for Ginger Base (Aline Manera)
* [a85905d6] Update gingerbase po files (Aline Manera)
* [85e31680] Remove Kimchi references from Ginger Base (Aline Manera)
* [8e5c2a09] Change Kimchi version. (Paulo Vital)
* [8a3d6bb5] Upgrade Kimchi objectstore content. (Paulo Vital)
* [345161d8] Add Kimchi version to objectstore entries. (Paulo Vital)
* [983c5721] Add version to objectstore information. (Paulo Vital)
* [94f263a0] Bug fix: Properly get the new guest name while creating or cloning a guest (Aline Manera)
* [e086fd65] Bug fix: Properly define kimchi.trackTask() (Aline Manera)
* [8f7aa139] Bug fix: Use qxl video model for Fedora 22+ guests (Aline Manera)
* [8e1b384d] Templates tab (samhenri)
* [df3f51b5] Storage tab (samhenri)
* [cf10e484] Network tab (samhenri)
* [79117428] Kimchi config and Guests tab (samhenri)
* [bcf97e94] Gingerbase / Hosts tab (samhenri)
* [0337d165] Base template files (samhenri)
* [6ba92c4c] Updated SCSS files (samhenri)
* [61301ae0] Updated images and distro icons (samhenri)
* [ea698d8b] Updated widgets (samhenri)
* [88e79a6e] Deleting unused files (samhenri)
* [3bae90ed] Issue #751: Fix guest memory utilization calculation. (Paulo Vital)
* [699ca69a] Ginger Base: Fix DEBIAN/control.in (Aline Manera)
* [04dd5871] Add support for displaying guest memory utilization (Socorro Stoppler)
* [4718e71b] Fix Issue #743 : gingerbase: fail to create RPM. (chandrureddy)
* [10139e39] Ginger Base : Plugin path changes (chandrureddy)
* [e1077b5a] Ginger Base : Fix Minor Issues with the test cases. (chandrureddy)
* [e5d6e9d2] Bug fix: Update Kimchi URL while checking ISO stream support (Aline Manera)
* [69a30c87] Fix issue 'unable to open database file' when run 'sudo src/wokd --environme.. (chandrureddy)
* [2d2fc4a3] Live migration backend: unit tests (Daniel Henrique Barboza)
* [5e2a1f8b] Live migration backend: control/vms and model/vms changes (Daniel Henrique Barboza)
* [0b777928] Live migration backend: API and messages (Daniel Henrique Barboza)
* [873b617d] Log any exception raised (Aline Manera)
* [64297ac0] Github #745: WoK: improve error message when importing plug-ins (Daniel Henrique Barboza)
* [595fe9f4] Guest memory utilization. (Paulo Vital)
* [5c12348c] Update README to recommend pkgconf installation in Ubuntu (Lucio Correia)
* [a57e6176] Bug fix: Display storage pool types properly (Aline Manera)
* [1c70986f] Fix make check-local for Kimchi (Aline Manera)
* [7306c310] Add .gitignore file to gingerbase directory (Aline Manera)
* [9cc0b8f9] Add src/wok/plugins directory to the Wok PEP8 backlist (Aline Manera)
* [4a6671b3] Remove Host Resource from Kimchi (Aline Manera)
* [7d8473e7] Keep /host/partitions on Kimchi (Aline Manera)
* [52bf10cd] Move host authorization tests from Kimchi to Ginger Base (Aline Manera)
* [0ed3da6e] Remove repositories tests from Kimchi (Aline Manera)
* [05790586] Fix Ginger Base tests (Aline Manera)
* [74803276] Get the right internal URI to Ginger Base plugin (Aline Manera)
* [5d367ecd] Fix PYTHONPATH to run tests for Ginger Base (Aline Manera)
* [9b19d45b] V7 Ginger Base : base plugin po files (chandrureddy)
* [6cd75482] V7 Ginger Base : base plugin ui make, images and config (chandrureddy)
* [c4da9919] V7 Ginger Base : base plugin ui/css files (chandrureddy)
* [b48bc9ae] V7 Ginger Base : base plugin ui/js files (chandrureddy)
* [1c8a6830] V7 Ginger Base : base plugin ui/pages files (chandrureddy)
* [67f67974] V7 Ginger Base : base plugin ui/pages/help files (chandrureddy)
* [c924db91] V7 Ginger Base : base plugin tests files (chandrureddy)
* [5d33017c] V7 Ginger Base : base plugin model files (chandrureddy)
* [e04498a9] V7 Ginger Base : control files (chandrureddy)
* [cfc34988] V7 Ginger Base : base plugin m4 files (chandrureddy)
* [3014c8fa] V7 Ginger Base : base plugin build-aix and contrib (chandrureddy)
* [71953527] V7 Ginger Base : base plugin docs files (chandrureddy)
* [bd69aab2] V7 Add License files to ginger base (chandrureddy)
* [92aa088a] V7 Ginger Base : base folder files part 3 (chandrureddy)
* [32cd0a35] V7 Ginger Base : base folder files part 2 (chandrureddy)
* [4a1d1a3b] V7 Ginger Base : base folder files part 1 (chandrureddy)
* [2b814b97] V7 Ginger Base : Taking off the host tab functionality (chandrureddy)
* [2d0f6ac5] Fix Kimchi RPM spec files (Paulo Vital)
* [4fc75872] Fix passthrough bugs (Jose Ricardo Ziviani)
* [a2207f32] Copy missing files to build Kimchi RPM. (Paulo Vital)
* [5535dd5d] Fix test cases to proper get the screenshot and debug report file (Aline Manera)
* [377499a4] Use right URI while doing internal redirection (Aline Manera)
* [0a68bf94] Update test case according to commit e9cd4666 (Aline Manera)
* [2e6212b0] Update test case to use the right Template URI while creating a guest (Aline Manera)
* [a859d03a] Make sure to use relative path when setting an icon to a guest (Aline Manera)
* [49de99de] Force a HTTP redirection when a resource has its ID changed after a PUT requ.. (Aline Manera)
* [6a0e66b1] Add correct package name for libxslt in Ubuntu (Socorro Stoppler)
* [70966562] Add correct name for libxslt for Kimchi plugin (Socorro Stoppler)
* [7821e2f2] Use absolute import path (Aline Manera)
* [e51d8135] Move validate_repo_url() and check_url_path() from Wok to Kimchi (Aline Manera)
* [ff14195e] Provide a meaningful message to WOKUTILS0001E (Aline Manera)
* [341d08d3] Remove any WOK error message from Kimchi (Aline Manera)
* [019bf262] Fix issue #738 - Part 2: Split Wok and Kimchi object stores (Lucio Correia)
* [726b96ae] Fix Kimchi model (Lucio Correia)
* [6e4cf3fa] bug fix: Allow user to get guest console (noVNC and spice) (Aline Manera)
* [64856ea5] Update the documentation (Jose Ricardo Ziviani)
* [a8c54c76] Implement the package manager monitor frontend (Jose Ricardo Ziviani)
* [4d5cb808] Implement the package manager monitor backend (Jose Ricardo Ziviani)
* [3810c26d] Add functions for package manager monitoring (Jose Ricardo Ziviani)
* [4b453585] Use absolute import path on root.py (Aline Manera)
* [e510700e] Set the right error messages for Kimchi (Aline Manera)
* [2752645a] Issue #742: Update Readme with missing dependencies. (Paulo Vital)
* [bb86df5e] Fix import path based on new plugin structure (Aline Manera)
* [b800c0e5] Update Wok and Kimchi systemd process. (Paulo Vital)
* [38a3409b] imageinfo.py: Don't fail template creation if unable to detect OS (Brent Baude)
* [3a960d18] Fix package name of some dependencies (Paulo Vital)
* [16ede117] Fix issue #738 - Use *lib/kimchi instead of *lib/wok/plugins/kimchi (Lucio Correia)
* [69c6c2da] Issue #740: Solving UI dependencies checking. (Paulo Vital)
* [4e659f82] Fix some test cases on test_config.py for Wok and Kimchi (Aline Manera)
* [4e028276] Adding new-ui src sass dependencies (samhenri)
* [128c05f1] Adding new-ui sass source files (samhenri)
* [556fa6c8] Adding python-dev, python-pip and cython & libsass libs to compile SCSS sour.. (samhenri)
* [8c68f291] Update README.md with submodules information. (Paulo Vital)
* [c9095925] Add Ginger as module (Paulo Vital)
* [87463bbc] Add Kimchi as module (Paulo Vital)
* [f0934302] Fix issue stopping nginx proxy (Rodrigo Trujillo)
* [06c81b05] Moving bootstrap-select js and css to separate folders (samhenri)
* [c46ce085] Add %Used back to the right of Name column in Storage tab (Socorro Stoppler)
* [2c1ecbd0] Add license files to Kimchi (Paulo Vital)
* [fd88eb08] Use locks to prevent concurrent updates to VMs (Crístian Deives)
* [ddc07c78] Update back-end license to LGPLv2.1 (Paulo Vital)
* [58ffd293] Configure deb package to use systemd service if needed (Jose Ricardo Ziviani)
* [68932442] Fix RuntimeWarning in check_i18n.py (Lucio Correia)
* [e29a63d9] Fix PEP8 issues (Lucio Correia)
* [945dd74a] Fix name mismatch with imported module (Lucio Correia)
* [6f6ce582] Update the header of all Wok front-end files (Paulo Vital)
* [07717289] Update the header of all Wok back-end files (Paulo Vital)
* [5efe8f08] Update README.md of Wok and Kimchi after slipt. (Paulo Vital)
* [bd88c879] Update gitignore after move of plugins structure (Paulo Vital)
* [1db98f67] Fix PYTHONPATH to be able to run "make check" (Aline Manera)
* [0bae086f] Wok tests (Paulo Vital)
* [b7cac1b1] Move KCHASYNC0003E to Wok and update code. (Paulo Vital)
* [6b0960ee] Update build and config files to new plugins path. (Paulo Vital)
* [6768e409] Change relative to absolute imports in Kimchi. (Paulo Vital)
* [4675caf9] Move plugins directory to src/wok structure. (Paulo Vital)
* [4f1a645a] Issue #704: page refreshing in Wok when no plugins installed (Atreyee)
* [926cb428] Set systemd KillMode to process (Jose Ricardo Ziviani)
* [d8482740] Make the package update process indendent of Kimchi (Jose Ricardo Ziviani)
* [730c66a5] Fix template default memory in hosts with few memory (Rodrigo Trujillo)
* [bd921f2f] Wok updates (Aline Manera)
* [43c86ef2] New UI updates (samhenri)
* [f103d9a4] New UI updates (Aline Manera)
* [2d5c9b9f] Wok updates (Paulo Vital)
* [5a79d132] Introduce Wok (Webserver Originated from Kimchi) (Lucio Correia)
* [01de1e0c] New UI: Add makefiles for fontello (Lucio Correia)
* [0da71e11] New UI (Wen Wang)
* [0578a58b] New UI (Yu Xin Huo)
* [0c1a09c3] New UI (Wen Wang)
* [e16ba085] Update copyright for src/kimchi/model/hostdev.py (Aline Manera)
* [85a134a6] Merge remote-tracking branch 'origin/next' into origin/master (Aline Manera)
* [b934901e] Patched kimchi for psutils 3.0.1 (Stephan Conrad)
* [9a41f0c6] Merge remote-tracking branch 'origin/master' into next (Aline Manera)
* [616ea4d2] List IPs of VM Ifaces (Christy Perez)
#### [1.5.1] ####
* [c424980b] Update ChangeLog and Version files for 1.5.1 release (Aline Manera)
* [396ee653] Update pt_BR translations (Aline Manera)
* [60615113] Raw volumes validation: update tests (Paulo Vital)
* [2feb8cc3] Raw volumes validation: back-end and front-end (Paulo Vital)
* [62964149] Raw volumes validation: update contrib and README (Paulo Vital)
* [f272e2ff] Add missing translations (Aline Manera)
* [4765f273] Add volume to storage pool label not formatted properly in some languages (Socorro Stoppler)
* [5cc46e17] Update help pages for ja_JP and pt_BR (Aline Manera)
* [3352b564] Isolate strings in guest-edit and template-add (Ramon Medeiros)
* [134527ec] PCI filter not in sync with device listing (Socorro Stoppler)
* [c45fe56d] Fix confirmation box for delete and clone (Socorro Stoppler)
* [49b87f34] Handles http redirection when checking url path (Jose Ricardo Ziviani)
* [52ca8827] Expands all possible variables in a repo url to validate it (Jose Ricardo Ziviani)
* [d846e260] Implement a method to expand variables in a url (Jose Ricardo Ziviani)
* [637b1445] Add translation for "Users" and "Groups" on guest edit (Ramon Medeiros)
* [86e66985] Update build process to include jquery.base64.js (Aline Manera)
* [b0f9b30c] Adds the new display_repo_name field in the JSON API (Jose Ricardo Ziviani)
* [d74f93b7] Display the expanded repo name instead of variables (Jose Ricardo Ziviani)
* [afdcb375] Implement a method to display the repo name expanding variables (Jose Ricardo Ziviani)
* [4237323d] Remove colon character from template cpu edit window (Rodrigo Trujillo)
* [76782b04] Add Fedora 22 as remote ISO option. (Paulo Vital)
* [8e8a6279] Add Fedora 21 as remote ISO option. (Paulo Vital)
* [b2a09e7e] Update Fedora Live 20 URL as remote ISO (Paulo Vital)
* [690b09ef] Add unity tests for start/shutdown/poweroff response commands (Ramon Medeiros)
* [ec4fe6d9] Issues #682/#684/#685: Change some code errors when start, shutdown or power.. (Ramon Medeiros)
* [05697000] Issue #667: Unable to rename guest when it is paused (Ramon Medeiros)
* [df21d34b] Bug fix: Access guest console when guest name has non-ASCII characters (Aline Manera)
* [cb5487fb] Update server configuration to expose jquery.base64.js (Aline Manera)
* [921876f3] Import Jquery Base64 code (Aline Manera)
* [e0e97f56] Fix bug #450: Allow creating guest with non-ASCII characters in name (Aline Manera)
* [e10e158c] Create helper method to remove metadata node (Aline Manera)
* [12ba7903] Allow setting multiple metadata nodes at once (Aline Manera)
* [6bdac405] Remove manual manupulation (Aline Manera)
* [f4941a26] Disallow storage format changes in UI for templates based on image file (Jose Ricardo Ziviani)
* [91b04075] Avoid show user/password in url browser (Rodrigo Trujillo)
* [9f9408ac] Add missing translations (Aline Manera)
* [b91891d5] Improve code to get default disk format for VMTemplate (Aline Manera)
* [16a7830d] Add m4/pkg.m4 to .gitignore (Aline Manera)
* [d52ce00f] Fix SLES 11 reg exp to recognize SLE-11-SP4-SAP-DVD-ppc64-GM-DVD1.iso (Ramon Medeiros)
* [d677b736] Set default VM template memory to 2048 in Power (Daniel Henrique Barboza)
* [b79f5b12] Improve code performance on UI (Ramon Medeiros)
* [83800932] PCI Node filtering (Socorro Stoppler)
* [1a01d8f0] Force qcow2 when creating a VM based on backing image (Jose Ricardo Ziviani)
* [95e36b33] vmHostDevModel: returning 'product' and 'vendor' in lookup (Daniel Henrique Barboza)
* [a2197098] Change getsebool to run silently. (Jose Ricardo Ziviani)
* [b83f8f1c] Add option 'silent' in run_command (Jose Ricardo Ziviani)
* [5de475f0] Fixing compilation problems with translation files (Daniel Henrique Barboza)
* [eed3d15a] Translation updates (Daniel Henrique Barboza)
* [d4537fb5] Template disk format test fixes (Daniel Henrique Barboza)
* [34b6e049] Remove unecessary call to node_dev.parent() (Ramon Medeiros)
* [1351729e] Update Fedora 20 ISO path to mirrors.kernel.org (Ramon Medeiros)
* [eb3b2bb0] Detach group of PCI Devices from host before attaching to guest (Jose Ricardo Ziviani)
* [356c95d8] New unit tests to check disk creation behavior (Daniel Henrique Barboza)
* [297ca7d3] Getting default disk format from template.conf (Daniel Henrique Barboza)
* [4676106b] Mockmodel and test changes for the new API (Daniel Henrique Barboza)
* [4a00ca0c] Adding new API in the UI APIs and docs (Daniel Henrique Barboza)
* [c1e7aad1] Get available host passthrough devices: model changes (Daniel Henrique Barboza)
* [b3cd034f] Fix displaying numerous error msgs when host is shut down (Socorro Stoppler)
* [1e6ac52f] Fix minus in manpage (Frederic Bonnard)
* [17df1627] Help updates for Kimchi (Kersten Richter)
* [152640a1] Issue #670: openSUSE: problem while building Kimchi (Ramon Medeiros)
* [520cfee3] Issue #670: openSUSE: problem while building Kimchi (Ramon Medeiros)
* [0ba085c4] Github 663: software update improvements (Daniel Henrique Barboza)
* [fc20b7a5] Bug fix: Allow creating a pool using an existing path (Aline Manera)
#### [1.5.0] ####
* [2f6ae8a1] Update ChangeLog, VERSION and .po files for 1.5 release (Aline Manera)
* [6520e58e] Prevent Kimchi against TLS Logjam attacks (Rodrigo Trujillo)
* [f101a12d] Issue #653: "make rpm" requests authentication with non-root (Ramon Medeiros)
* [5e831068] Bug fix: Use a temp directory under /var to avoid permission errors (Aline Manera)
* [fb5ef931] Bug fix: Detach host device prior to attach to guest (Aline Manera)
* [5ed39b3f] Gtihub #660 - Fixing .repo file with no repos handling (Daniel Henrique Barboza)
* [ae939e79] Support xorriso ISOs detection (Ramon Medeiros)
* [cec1b143] Github #657 - fixing yum check-update parsing (Daniel Henrique Barboza)
* [c3252ed8] Bug fix: Allow user creates multiple templates (Aline Manera)
* [ac646f41] Changing repositories and swupdate to use yumparser module (Daniel Henrique Barboza)
* [15e265ab] Unit tests for the yumparser module (Daniel Henrique Barboza)
* [dd3c2c77] Adding yumparser module (Daniel Henrique Barboza)
* [b7b86820] Fix bug #647: Properly set qxl as video model for Fedora 22 (Aline Manera)
* [7c9f261f] Update po files for 1.5 release (Aline Manera)
* [46fe795d] Change the width of Actions button (Socorro Stoppler)
* [970b7c0f] Fix tests, adds slot and memory hotplug tests (Rodrigo Trujillo)
* [4a0eb86d] Add maxMemory and numa configuration to guest xml (Rodrigo Trujillo)
* [f137f062] Add maxMemory into templates (Rodrigo Trujillo)
* [2bd729a5] Feature test to check support to memory devices (Rodrigo Trujillo)
* [c6952029] pep8 fixes (Daniel Henrique Barboza)
* [6ed39cf9] UI-Template Edit: Enable user to change disk format (Rodrigo Trujillo)
* [0b777284] Supress error messages while checking vm metadata (Ramon Medeiros)
* [9e4cc6ef] Add support for Pause/Resume UI (Socorro Stoppler)
* [8fdedc0c] Does not list non-bootable images (Ramon Medeiros)
* [c9937b84] Enable storage volume upload on UI (Aline Manera)
* [e261fc71] Storage volume upload: Let the 'format' parameter be an empty string (Aline Manera)
* [690c3641] Storage volume upload: Keep the task tracking to update the UI (Aline Manera)
* [08c4af01] Set 'used_by' to [] when creating some volumes (Crístian Deives)
* [1d23e60f] Replace storage volume 'ref_cnt' with 'used_by' (Crístian Deives)
* [3ce2c42f] Update test cases to reflect MAC address update changes (Jose Ricardo Ziviani)
* [591ac232] Implement frontend code to edit MAC address of a guest (Jose Ricardo Ziviani)
* [bf258030] Implement backend code to edit MAC address of a guest (Jose Ricardo Ziviani)
* [ec6bd25e] Add vfio driver as default for powerkvm systems. (Jose Ricardo Ziviani)
* [63725024] Removing the hardcoded version of kimchi and make it depend of PACKAGE_VERSION (Frédéric Bonnard)
* [4d58f914] UI: Enable virtual NIC hot plug/unplug (Aline Manera)
* [ae33e0e6] Change log message if command to run is not found (Jose Ricardo Ziviani)
* [6f2487ac] Install service on make install (Ramon Medeiros)
* [eb2880b1] Fix SLES version checking in interfaces.py (Rodrigo Trujillo)
* [93a875d8] Remove storage volume creation from file (Aline Manera)
* [a2b84a60] Upload storage volume (Aline Manera)
* [cf76b626] Update controller to make update accept formdata params (Royce Lv)
* [2b7a456e] Fix URI format of guest interfaces (Jose Ricardo Ziviani)
* [0758cf3a] Display MAC Address in guest interface tab (Jose Ricardo Ziviani)
* [a4fa2c08] Avoid certificate validation on tests (Ramon Medeiros)
* [28e2c151] Handle invalid path in 'get_disk_ref_cnt' (Crístian Deives)
* [44475d62] fix: Use correct path when setting 'ref_cnt' to a new volume (Crístian Deives)
* [50f64e7b] Bug fix: Build default pools list according to user input (Aline Manera)
* [2a351070] Fixed section number within the man page itself (Frederic Bonnard)
* [570cd89e] Add documentation for VM suspend/resume (Crístian Deives)
* [12dbc97b] Verify storage pool set as Template default prior to server starts up (Aline Manera)
* [4b64bb3b] Verify all networks set as Template defaults prior to server start up (Aline Manera)
* [3ec063ce] Make Template defaults configurable (Aline Manera)
* [e4fa2c19] snapshot: Handle non-existing snapshots in mock lookup (Crístian Deives)
* [51871d06] Create option to auto create ISO pool or not on server start up (Aline Manera)
* [ef566a1b] Add libvirt-daemon-config-network package as Kimchi dependency (Aline Manera)
* [c43fe1c2] Merge common_spec with defaults value in osinfo.py (Aline Manera)
* [7fad14f9] Remove useless variable in osinfo.py (Aline Manera)
* [6a134aab] Create VMs Asynchronously: UI (Aline Manera)
* [b8ee58d0] Create VMs Asynchronously: Tests (Christy Perez)
* [c8f56d57] Create VMs asynchronously: Backend (Christy Perez)
* [78f1ff63] UI changes for new clone target_uri (Christy Perez)
* [236f3a53] Tests for new clone target_uri (Christy Perez)
* [c449622c] Append clone to target_uri for vm clone task (Christy Perez)
* [db6afa6c] Do not resolve hostname to IP in using remote ISOs (Aline Manera)
* [d9e5d8b5] Improve code to retrieve the number of host CPUs (Jose Ricardo Ziviani)
* [a65660a8] Move kimchi nginx config file to nginx default directory. (Jose Ricardo Ziviani)
* [100aec5e] Add a warn about NM running in the system. (Jose Ricardo Ziviani)
* [c234e9bd] Implement function to check if NM is running. (Jose Ricardo Ziviani)
* [28dcbc40] Host tests (Aline Manera)
* [b042b230] issue #548: Hotplug network interfaces (Crístian Deives)
* [83220337] Use default network model when attaching a NIC (Crístian Deives)
* [aa332f51] Handle missing parameter "network" when attaching a NIC (Crístian Deives)
* [d17d8be8] Parse osinfo.lookup return parameters correctly (Crístian Deives)
* [99bd4bb1] Remove nginx conf on suse (Ramon Medeiros)
* [e1597d32] Create empty files on rpm build (Ramon Medeiros)
* [81ea427e] Adds tests to check disk format information in new templates (Rodrigo Trujillo)
* [1d41799c] Set qcow2 as default disk format in new templates (Rodrigo Trujillo)
* [f06ddfcc] Template: Assign 'raw' to disk format if pool is 'logical' or [i]scsi (Rodrigo Trujillo)
* [351ffbdd] Server tests (Aline Manera)
* [95e3030c] Object store tests (Aline Manera)
* [958d93eb] Add support for VM suspend and resume (Crístian Viana)
* [ae44ff31] Update some VM state conditions (Crístian Viana)
* [63c3a70e] Optimize VM update function (Crístian Viana)
* [7803cdf9] Move stats-related VM functions to VMModel (Crístian Deives)
* [ceb4f3f0] Update stats when looking up one single VM (Crístian Deives)
* [f7d93c43] Add %Used in the header for storage (Socorro Stoppler)
* [89be36b7] Security: Prevent Bar Mitzvah attacks by disabling RC4 (Aline Manera)
* [4722d646] issue #461: Add 'metalink' support for YUM repositories (Crístian Viana)
* [b85c0683] Use more generic message in repo mirror list error (Crístian Viana)
* [5376a6bf] Handle empty variables when updating YUM repository (Crístian Viana)
* [4538eb7f] Update host number of cpus and total physical memory (Jose Ricardo Ziviani)
* [2e72edae] Making urls relative (Frederic Bonnard)
* [464af615] test/test_model: Power architecture fixes (Daniel Henrique Barboza)
* [874f4079] Fix Network create name checking in backend (slashes and quotes) (Rodrigo Trujillo)
* [a126b5f0] Move slash checking in storagepool name from UI to backend (Rodrigo Trujillo)
* [70f7ec56] Prohibits slashes '/' in VM name (Rodrigo Trujillo)
* [7763a912] issue #628: Set ref_cnt=1 on cloned disks (Crístian Viana)
* [6f93d5ba] Issue #623: Fix mismatch in host device details query (Royce Lv)
* [19f941ad] Fix a ZeroDivisionError when starting kimchi service in Qemu. (Jose Ricardo Ziviani)
#### [1.4.1] ####
* [41f87929] Update ChangeLog and VERSION file for 1.4.1 release (Aline Manera)
* [f3d904b3] Update pt_BR translations for Kimchi 1.4.1 (Aline Manera)
* [d72feb17] Update .po files for translation (Aline Manera)
* [ffe6b099] Kimchi tests: Power system fixes - removing hardcoded values (Daniel Henrique Barboza)
* [a45705fa] tests/test_osinfo.py: fixes for Power architecture (Daniel Henrique Barboza)
* [6ffab419] Specify user when changing VM disks permission (Crístian Viana)
* [e9e465c4] issue #518: Simplify template URL verification (Crístian Viana)
* [448a0453] Update ISO file's ACL before checking its permission (Crístian Viana)
* [01f6befb] issue #564: Parse logical volumes to find out their actual formats (Crístian Viana)
* [f88df1d7] issue #565: Allow a template's ISO to be a block device (Crístian Viana)
* [81c300b1] Fix test_model.py to reset Singleton classes when initializing the tests (Aline Manera)
* [5ba64183] Bug fix: Consider server is being started up on servermethod function (Aline Manera)
* [40c1f098] Use the right firewall-cmd command to open Kimchi ports (Aline Manera)
* [def6b0a7] Fix issue #597: Get the right arch when using libvirt Test driver (Aline Manera)
* [a5b119bc] Fix issue #617: Base URL may be an empty string when updating YUM repo (Aline Manera)
* [756d972d] Fix issue #621: Catch libvirt exception when network does not have bridge name (Aline Manera)
* [00a4a6d0] Fix issue #620: Allow use iSCSI/SCSI volume on Template (Aline Manera)
* [70045570] Add support to recognize RHEL-LE distro and version (Jose Ricardo Ziviani)
* [aac05188] Deregister peer information when kimchid exit (Royce Lv)
* [28cd9fd9] Update doc for federation (Royce Lv)
* [28fa8acc] Assign HTML labels to their corresponding elements (Crístian Viana)
* [c30980d7] Fix wrong usage of feature tests (Royce Lv)
* [af2a2337] Avoid using server dependent feature tests when server not running (Royce Lv)
* [aea13b23] Remove slash "/" filter in template name when create VM (Rodrigo Trujillo)
* [8105f8e1] Remove unsupported Fedora ISO link (Royce Lv)
* [052d841a] Issue #587: Man page submission for kimchid (Frederic Bonnard)
* [aa33ab7c] RHEL7: Guide user to install spice-html5 (Aline Manera)
* [19fbca39] Template tests (Aline Manera)
* [a3fd212c] bug fix: Allow adding a iSCSI/SCSI volume from a non-ASCII pool to a template (Aline Manera)
* [cf6ef10e] Fix shallow scan test: wait until storage volume creation finished (Royce Lv)
* [ffe72a05] Change from using /usr/bin/python to /usr/bin/env python2 to improve portabi.. (Alan Jenkins)
* [3d1d8de8] issue #595: Return correct memory value when VM is shutoff (Crístian Viana)
* [5f4e3ed4] Add function to convert data sizes (Crístian Viana)
* [886eb8c9] issue #545: Handle simultaneous authentication methods when updating VM perm.. (Crístian Viana)
* [e717916a] Bug fix: Properly raise authenticate error when login fails (Aline Manera)
* [1ff6ac6f] Bug fix: Properly reload grid content (Aline Manera)
* [1bbcedd8] Set a common message to KCHGRD6002M (Aline Manera)
* [4870ca9e] Fix grammar for selected messages (Christy Perez)
* [ee326e19] Stop collecting background stats (Christy Perez)
* [5c5d9ded] issue #512: Attach the function "showMessage" to the UI grid class (Crístian Viana)
* [2ae8bc34] Add Arch Linux entry to isoinfo. (Alan Jenkins)
* [d5386103] Add modern entry for Arch Linux. (Alan Jenkins)
* [162d1101] Set allocation=capacity when creating images in logical pools (Christy Perez)
* [dd311cd3] Disable SSL on nginx (Tulio Magno Quites Machado Filho)
* [cf626f10] Fix issue #589: Add listener to remove Kimchi leftovers (Aline Manera)
* [c7ee91a9] Fix issue #591: Get the right arch for MockModel (Aline Manera)
* [208d4be5] Bugfix: Kimchi: Better to list storage pool paths (Wen Wang)
* [ac9bd865] Issue #573: Kimchi on ppc64el (Ramon Medeiros)
* [e67be6ca] Transient StoragePool POST request handling (Christy Perez)
* [e2161d3d] Transient Network POST request handling (Christy Perez)
* [0f367ee3] Transient VM POST request handling (Christy Perez)
* [6653afa6] Handle requests differently for transient objects (Christy Perez)
* [a254b9a9] On Ubuntu, current libvirt library requires XML (Aline Manera)
* [e736968f] Update vmtemplate.py to use get_disk_xml() while generating CDROM XML (Aline Manera)
* [80c01b30] Check QEMU stream DNS capability when attaching new disk to guest (Aline Manera)
* [c528ebc0] Get disk type according to file path on get_disk_xml() (Aline Manera)
* [01a227ec] Remove ignore_src parameter from get_disk_xml() (Aline Manera)
* [d0bbde8b] Update get_disk_xml() to get the device same according to bus and index values (Aline Manera)
* [38acb8bd] Remove 'bus' paramater from /vms//storages documentation (Aline Manera)
* [0c6b0d03] Move vmdisks.py functions to xmlutils/disk.py (Aline Manera)
* [1a375460] Move _get_storage_xml() to xmlutils/disk.py (Aline Manera)
* [fcfc65d9] Number of CPUs in Host's Basic Information. (Paulo Vital)
* [3e6f0c0e] Remove libxml2-python as Kimchi dependency (Aline Manera)
* [d210c690] Use lxml.etree on gen-index.py script instead of libxml2 (Aline Manera)
* [3589acd3] Use lxml.etree on xmlutils/utils.py instead of xml.etree and libxml2 (Aline Manera)
* [95f830a2] Remove pyc files on make clean (Christy Perez)
* [c76ecc2a] AsyncTask: Improve continuous status feedback (Zhou Zheng Sheng)
* [c997834a] Translations for new cpu_info messages (Christy Perez)
* [b296b518] cpu_info tests for model and mockmodel (Christy Perez)
* [2c45afa9] Backend support for templates with sockets, cores, and threads (Christy Perez)
* [b4270fa8] ConfigTests: Fix novnc paths (Zhou Zheng Sheng)
* [f7e4f303] ModelTests: Improve leftover cleaning (Zhou Zheng Sheng)
* [a2f88b6d] VMsModel: Make _update_guests_stats() robust against race condition (Zhou Zheng Sheng)
* [4fb50cae] LibvirtConnection: Share underlying connections between instances (Zhou Zheng Sheng)
* [0e2f7538] Update libvirtstoragepool.py to use lxml.builder (Aline Manera)
* [78d09e2a] add sub-makefile in src/kimchi/xmlutils (Simon Jin)
* [2293bae2] Disabling screen log in production environment (Daniel Henrique Barboza)
* [9c273ce0] Move networkxml.py to xmlutils module and update it to use lxml.builder (Aline Manera)
* [8d219ba1] Create a xmlutils module to hold all the XML manipulation (Aline Manera)
* [c82d50f9] Update COPYING content to expose the imported code (Aline Manera)
* [880c5984] Delete former imported spice code (Aline Manera)
* [d9f23260] Update Kimchi to use the installed spice-html5 (Aline Manera)
* [d37430fb] Add new spice-html5 code to Kimchi build process (Aline Manera)
* [138ba2c4] Modify spice_auto.html for Kimchi proposals (Aline Manera)
* [d81bb682] Import the latest spice-html5 code into Kimchi (Aline Manera)
* [f7f73e47] Changes in sample plugin to fix and improve help (Rodrigo Trujillo)
* [5422d036] Fix problems to open plugin's help pages (Rodrigo Trujillo)
* [7ea2f168] Host device passthrough (Front-end): Add PCI Devices to VM (Yu Xin Huo)
* [3c6e7a00] Host device passthrough: Add unit tests and documents (Zhou Zheng Sheng)
* [53cd6f10] Host device passthrough: List VMs that are holding a host device (Zhou Zheng Sheng)
* [754e0569] Host device passthrough: Directly assign and dissmis host device from VM (Zhou Zheng Sheng)
* [79065e87] Host device passthrough: List eligible device to passthrough (Zhou Zheng Sheng)
* [815e03fb] Host device passthrough: List all types of host devices (Zhou Zheng Sheng)
* [61f9f2cf] Delete imported novnc code (Aline Manera)
* [d14f4f18] Add novnc as Kimchi dependency (Aline Manera)
* [2a4a3036] Bugfix#414: Cannot login by clicking on the login button (Wen Wang)
* [f066c789] Enable remote libvirtd (Brent Baude)
* [d5fdd2b1] Delete imported websockify code (Aline Manera)
* [bf10e966] Add websockify as Kimchi dependency (Aline Manera)
* [508f6fd6] bug fix: Redirect user to the URL accessed prior to login (Aline Manera)
* [e7d3f070] pep8: Use blacklist instead of whitelist (Crístian Viana)
* [6f4652dd] pep8: Fix errors in all files (Crístian Viana)
* [60f0f413] Display "README" with markdown style on Github (Crístian Viana)
* [69693af1] Fix: accelerate mockmodel for file upload (Royce Lv)
* [e47b3952] Bugfix: Cancel option not working properly in New Storage Define (Wen Wang)
* [88dc6101] Bug Fix: Correct select menu to handle empty input (Yu Xin Huo)
* [002f942c] Fix wrong config param of repository creation (Royce Lv)
* [b6a1402f] Fix: retrieve right bus type in vmstorage update (Royce Lv)
#### [1.3.0] ####
* [bb517f7a] Update ChangeLog for 1.3 release (Aline Manera)
* [4ca115ad] Update po files for 1.3 release (Aline Manera)
* [da7ddfa9] issue #447: Check download URL prior to start Task (Aline Manera)
* [1a40acf5] Update distros.d files to point to a valid URL (Aline Manera)
* [15307ac5] issue #454: Properly display storage volumes in a pool with sub-directories (Aline Manera)
* [ecffa24f] Fix: Add rollback to update repository (Royce Lv)
* [536dc08c] Reject improper format for storage types (Royce Lv)
* [7835d111] Fix: filter unsupported source type from volume list (Royce Lv)
* [94070a84] issue #445: Request /peers on every click (Aline Manera)
* [dfc8ab0f] issue #462: Do not allow user to enter non-integer template disk size (Crístian Viana)
* [f33c2a77] build: Add README-federation.md to Kimchi package (Aline Manera)
* [088bfa36] issue #447: Remove downloaded volume if an error occurs (Crístian Viana)
* [4f5bdf74] issue #432: Display unique values for iSCSI targets (Aline Manera)
* [e2157305] issue #433: Fix repository tests (Crístian Viana)
* [ca5625ac] issue #437: Only allow a bootable image file to be used on template (Aline Manera)
* [836a3069] issue #417: Validate image file path when creating a new template (Aline Manera)
* [c398099e] Bugfix#424: Edit Template, "Disk (GB)" is changing with storage pool (Wen Wang)
* [980df15d] Update Chinese transtation to po (Wen Wang)
* [f59be72c] issue #435: Fix resource authorization logic (Crístian Viana)
* [a750ab11] Bugfix#426: When no interface available, creating network popup error (Wen Wang)
* [684cacbc] help i18n: Add new languages to build process (Aline Manera)
* [71a56b17] Bugfix#: Prevent overlap issue occurs under General tab on Edit (Wen Wang)
* [f5461632] Bugfix: Overlap issue occurs on the Power Off confirmation dialog (Wen Wang)
* [dec2ed45] Bug 431 Fix (Yu Xin Huo)
* [8c0858fe] issue #429: Properly set rollback function when creating vlan tagged bridged (Aline Manera)
* [52cd1e2a] issue #415: Do not allow renaming a debug report to the same name (Crístian Viana)
* [583bba41] Add firewall instructions to README-federation (Aline Manera)
* [f60fe51e] mock: Do not write file when downloading a volume (Crístian Viana)
* [314ba02b] issue #447: Use required parameter in function "refresh" (Crístian Viana)
* [2ee395fd] Bug 416 Fix (Yu Xin Huo)
* [88f8125f] Bug 418 Fix (Yu Xin Huo)
* [47f340c9] Issue #421: Grid Column Header Issue (Hongliang Wang)
* [3a169ad3] guest-storage-add: removing "Storage Name" backend support (Daniel Henrique Barboza)
* [8cd52c83] guest-storage-add: removing "Storage Name" field (Daniel Henrique Barboza)
* [20d43b15] bug fix: Probe image file only during the template creation (Aline Manera)
* [dc6521a0] Bug 446 Fix (Yu Xin Huo)
* [5fee044b] Bug 457 Fix (Yu Xin Huo)
* [12134e0e] Bugfix#420 UI: Pop up errors when log out at "Host" tab (Wen Wang)
* [a1d5607d] Revert "help i18n: Update Makefile to refeclt new languages." (Aline Manera)
* [3f7c438c] help i18n: Update Simplified Chinese translation (Paulo Vital)
* [e36070c2] help i18n: Update Portuguese (Brazil) translation (Paulo Vital)
* [817c90b2] help i18n: Add Traditional Chinese translation (Paulo Vital)
* [0dea3f5c] help i18n: Add Russian translation (Paulo Vital)
* [2d4ae3d6] help i18n: Add Korean translation (Paulo Vital)
* [cee06570] help i18n: Add Japanese translation (Paulo Vital)
* [ecc59248] help i18n: Add Italian translation (Paulo Vital)
* [2ec8a280] help i18n: Add French translation (Paulo Vital)
* [c21c0610] help i18n: Add Spanish translation (Paulo Vital)
* [ea7e62b0] help i18n: Add German translation (Paulo Vital)
* [48be887a] help i18n: Update Makefile to refeclt new languages. (Paulo Vital)
* [43e412b8] Fix issue #430: Properly list packages update on openSUSE systems (Aline Manera)
* [d9f456fa] Delete useless variables assignment (Aline Manera)
* [5cc81ddf] Update openSUSE section in docs/README.md (Aline Manera)
* [c906df99] Fix cdrom eject (Royce Lv)
* [3201b96c] Disable upload option while adding a volume to a pool (Aline Manera)
* [fe3a9f31] Storage Pool Add Volume UI: Connect the Feature in Storage Tab (Hongliang Wang)
* [b717464a] Storage Pool Add Volume UI: Implement Download/Upload Volume Function (Hongliang Wang)
* [ac9ef965] Storage Pool Add Volume UI: Add i18n Strings (Hongliang Wang)
* [800e7072] Storage Pool Add Volume UI: Add APIs to kimchi.api.js (Hongliang Wang)
* [0e7419fa] bug fix: Pass the right data format to run_command() (Aline Manera)
* [23e12851] python 2.6 compatibility: Use 'with' statement only with one context (Aline Manera)
* [ff45d645] Update po files according to Transifex translations. (Aline Manera)
* [8c88c5fc] Update messages (Aline Manera)
* [fb2764b1] storagevolume: Use default value for param 'name' when appropriate (Crístian Viana)
* [891a1e77] bug fix: Properly set max body size to nginx proxy (Aline Manera)
* [2d6674d2] Identify Kimchi variables from nginx config variables in nginx.conf.in file (Aline Manera)
* [5c994a65] model.host: considering older libvirt versions (Daniel Henrique Barboza)
* [77700482] Increase read chunk size to 1MB while uploading file (Aline Manera)
* [1abab5e9] Only disable report buttons when the selected report is pending (Aline Manera)
* [f756cbf2] List pending debug reports while loading report grid (Aline Manera)
* [279b290a] Add function to list all pending debug reports (Aline Manera)
* [c3fbdb30] Add common function to track Task (Aline Manera)
* [259b877e] Add function to get pending tasks according to filter (Aline Manera)
* [57422c42] Fix: Use "max_request_body_size" value as int instead of string (Crístian Viana)
* [c95cdf0b] UI: Template with VM Image - List (Yu Xin Huo)
* [15c992ee] UI: Template with VM Image - Edit (Yu Xin Huo)
* [ee2f1809] UI: Template with VM Image - Create (Yu Xin Huo)
* [0b96217c] Storage volume upload: Change mockmodel and test (Royce Lv)
* [ae8cb70f] Storage volume upload: Adding progress to task message (Royce Lv)
* [8400dc77] Storage volume upload: Support file based upload (Royce Lv)
* [a8e78fd1] Storage volume upload: Control request body size of kimchi (Royce Lv)
* [b090acf7] Storage volume upload: Parse params for upload formdata (Royce Lv)
* [099572c5] Fix mockmodel reset for objectstore (Royce Lv)
* [a820806f] Storage volume upload: Update API.md (Royce Lv)
* [5c81baaa] storagevolume: Set target URI when creating Task (Crístian Viana)
* [e2fb9fef] storagevolume: Add download progress to task (Crístian Viana)
* [28a59ba7] storagevolume: Check storage pool before adding a volume (Crístian Viana)
* [904f6d58] storagevolume: Download remote images to a storage pool (Crístian Viana)
* [5f4c7f57] Update current code to report target_uri while creating a Task (Aline Manera)
* [b8094387] Expose target_uri on Task resource (Aline Manera)
* [d471bb9a] Update License Statement (Hongliang Wang)
* [1f07a0eb] Storage volume upload: Change storagevolumes to AsyncCollection (Royce Lv)
* [90a1fdfd] Storage volume upload: Dispatch volume create to right handler (Royce Lv)
* [f48ad8ce] UI bug fix: Properly display storage volumes on Storage tab (Aline Manera)
* [c9e7369a] Guest storage: fix volume format overwrite (Royce Lv)
* [27afff90] UI: List Kimchi Peers (Yu Xin Huo)
* [8331929b] Expose federation on /config/capabilities (Aline Manera)
* [44d04e23] Add documentation on how to enable federation on Kimchi (Aline Manera)
* [28887cf9] Discover Kimchi peers using openSLP (Aline Manera)
* [d7efb3ac] Add federation option to Kimchi config file (Aline Manera)
* [82c6c99e] Delete http_port from /config API as it is not in use anymore (Aline Manera)
* [f682f1e2] Update kimchi.config values according to command line input (Aline Manera)
* [59859987] Fix sample plugin configuration (Aline Manera)
* [504010f2] Guest storage: Fix attaching type judgement (Royce Lv)
* [c6079557] UI: List iSCSI Servers & Targets (Yu Xin Huo)
* [00322e19] model.host: changing listDevices() to listAllDevices() (Daniel Henrique Barboza)
* [40f8cb8f] bug fix: Properly get the graphics expiration time (Aline Manera)
* [c55be115] bug fix: Auto-generate guest console password when the passed value is an em.. (Aline Manera)
* [313b138e] i18n support: Add new languages in login page. (Paulo Vital)
* [d2ef5cfb] Allow user updates the passwd expiration time without changing the passwd (Aline Manera)
* [922d7a58] Centralize graphics information (Aline Manera)
* [7cb9a3d1] Update iSCSI volume XML when creating a VM from an iSCSI pool (Aline Manera)
* [da5338d2] Fix duplicated message string in en_US.po file. (Paulo Vital)
* [a5c66484] i18n support: Add Traditional Chinese translation files. (Paulo Vital)
* [6e5309ba] i18n support: Add Russian translation files. (Paulo Vital)
* [5bd619ba] 18n support: Add Korean translation files. (Paulo Vital)
* [b5fa36e5] i18n support: Add Japanese translation files. (Paulo Vital)
* [e06548ab] i18n support: Add Italian translation files. (Paulo Vital)
* [c2b80c69] i18n support: Add French translation files. (Paulo Vital)
* [1eb4dd38] i18n support: Add Spanish translation files. (Paulo Vital)
* [3bc11731] i18n support: Add German translation files. (Paulo Vital)
* [50de9061] i18n support: Changed the file type of plugins/sample/po/LINGUAS (Paulo Vital)
* [cef41d78] Update po files (Aline Manera)
* [8c55c496] Add PowerKVM information as ISO otpion to installation. (Paulo Vital)
* [fbbf7030] Support tablet type as input device in VM's XML. (Eli Qiao)
* [ca3441d1] Change function that verifies network interface status (Ramon Medeiros)
* [74f939a1] Add unit tests for new vm 'persistent' property. (Christy Perez)
* [51e9aeee] Add a check in the UI for the new 'persistent' flag of a VM. (Christy Perez)
* [c711aa4b] Add persistent flag to VM info (Christy Perez)
* [eecab072] model/storagetargets: filtering used nfs paths (Daniel Henrique Barboza)
* [ac03f235] Issue #405 - Fix enter hit in storage tab under guest edit window (Rodrigo Trujillo)
* [46be6346] Issue #405 - Fix cancel button in edit guest storage tab (Rodrigo Trujillo)
* [178a229f] Allow admin user change permission settings when VM is running (Wen Wang)
* [34367adf] UI: Delete Manage Media function from action list (Wen Wang)
* [8585bad5] Bugfix UI: Change button text to indicate user network is generating (Wen Wang)
* [a23a0599] Bugfix: Log out from Administrator tab raises popup errors (Wen Wang)
* [b329c7ca] Fix UI: Show proper message when detaching a guest storage (Rodrigo Trujillo)
* [2e063c85] Refactor vmstorage name generation (Royce Lv)
* [649d5492] Remote ISO attachment: fix UI to accept remote ISO link for cdrom attachment (Royce Lv)
* [cb9055c6] Add unit tests for remote-backed CD ROM updates. (Christy Perez)
* [b16b2a10] Fix verification of remote ISO (Christy Perez)
* [aed694b9] Fix Key Error when editing CD ROM path (Christy Perez)
* [f3f3718a] UI: refactor guest edit code. (ShaoHe Feng)
* [ef562159] UI enhancement: Request /config/capabilities as soon as possible (Aline Manera)
* [a497cae3] Change default environment configuration to production mode. (Paulo Vital)
* [64355759] list host user names as less as possible (Simon Jin)
* [5c269813] bug fix: Properly list host partitions for Ubuntu 14.04 server (Aline Manera)
* [77fc255b] Fix issue #340: Show error message when server fails to list host partitions (Aline Manera)
* [d29438d0] Increasing nginx proxy timeout (Daniel Henrique Barboza)
* [20ed5fae] repository: Remove error message prefix (Crístian Viana)
* [3595e0b4] typo: Fix "repositorie" (Crístian Viana)
* [97f71997] Issue #377: Validate repository URLs (Crístian Viana)
* [d90ac8f6] bug fix: Allow kimchi runs in multiple platforms (Aline Manera)
* [d86f0c70] bug fix: Add spice.css to Makefile and spec files (Aline Manera)
* [05024b5c] Add tests for image based template (Royce Lv)
* [44d6724f] Update mockmodel of base img vm (Royce Lv)
* [ea0a0bed] Create volume based on backing store image (Royce Lv)
* [1e8acc35] Fix: Prevent iso links filling in osinfo.py (Royce Lv)
* [046ec709] Change 'cdrom' to a optional param (Royce Lv)
* [779b36ca] Change doc and api specification (Royce Lv)
* [f1327b20] Add image probe function (Royce Lv)
* [52495de4] Update testcases for bus type decision making (Royce Lv)
* [47f74d1c] Delete 'bus' selection from UI (Royce Lv)
* [0808296a] Delete 'bus' param from backend (Royce Lv)
* [56536c54] Update Chnagelog for 1.2.1.1 tag (Aline Manera)
* [07d2b18c] Update license to LGPLv3 (Aline Manera)
* [adef5a72] Remove useless jquery files (Aline Manera)
* [c4e0e95e] Remove useless image files (Aline Manera)
* [f977ebdf] Install kimchi.mo files in the default locale dir (Aline Manera)
* [cfa56097] Add missing license headers (Aline Manera)
* [40fb6d09] Update copyright date (Aline Manera)
* [425cf095] UI bug fix: Properly display partitions when extending a logical pool (Aline Manera)
* [baf65985] Fix pep8 errors according to pep8 1.5.6 (Aline Manera)
* [de7a5823] Disable vhost feature in Ubuntu and SLES (PPC64 LE) (Rodrigo Trujillo)
* [deafd342] Change modern distro versions for PPC (Rodrigo Trujillo)
* [44fb2a35] PowerPC bootable ISO detection code (Daniel Henrique Barboza)
* [e6995e27] bug fix: Update genChangelog script (Aline Manera)
* [6759eea3] fix test case for volume filtering (Royce Lv)
* [924a7b87] Filter directory in storage volume listing (Royce Lv)
* [93e3380b] Bugfix Issue #397 UI Broken when cookie is clear (Wen Wang)
* [9c4ed91e] Fix pyflakes errors in make check (Royce Lv)
* [c06043e1] bug fix: Avoid equals sign in VM console URL (Aline Manera)
* [e74881b5] Get user groups correctly (Crístian Viana)
* [35d3db8d] Update ChangeLog and VERSION files for 1.2.1.1 release (Aline Manera)
* [d86e6f89] Update Kimchi tag to remove 'kimchi-' prefix (Aline Manera)
* [01fc5ef9] issue #389: Use 127.0.0.1 as VNC listener IP (Aline Manera)
* [e036c63b] authorization: Update test cases based on last changes (Crístian Viana)
* [10c6c1a4] List "admin" as a valid system user in mockmodel (Crístian Viana)
* [0a6ed794] Move "fake_user" credentials to mockmodel (Crístian Viana)
* [b4c36365] Return some groups for every user in mockmodel (Crístian Viana)
* [072bc637] authorization: Remove authorization config from UrlSubNode (Aline Manera)
* [1e008a16] authorization: Update control files to set role_key and admin_methods (Aline Manera)
* [c782ebfe] authorization: Restrict access to Resource instance (Aline Manera)
* [479017ea] authorization: Restrict Collection access based on admin_methods parameter (Aline Manera)
* [46c07511] authorization: Filter resources by users and groups (Aline Manera)
* [655371f7] vm ticket in backend: update test case (ShaoHe Feng)
* [8944a41d] vm ticket in backend: update mockmodel (ShaoHe Feng)
* [523de0b4] vm ticket in backend: update model (ShaoHe Feng)
* [689ee6d1] vm ticket in backend: update controller and API.json (ShaoHe Feng)
* [1fa2e3fd] vm ticket in backend: update API.md (ShaoHe Feng)
* [f3c6bf57] authorization: update po files (Yu Xin Huo)
* [e5e32548] authorization: add users/groups to vm (Yu Xin Huo)
* [f9b43a8c] issue #374: Use base64 encoding to launch VM console (Aline Manera)
* [f64f7582] Authorization: Remove actions based on roles (Wen Wang)
* [17c751b8] Authorization: remove [+] icon from non-root users view (Wen Wang)
* [7a04fa94] Authorization: remove host/template tabs for non-root users (Wen Wang)
* [7ac08e8e] Add roles into cookie (Wen Wang)
* [a6661260] add a base64 safe url encode and decode to js utils (ShaoHe Feng)
* [81894dad] Let frontend redirect user after logging (Aline Manera)
* [827644e5] Remove special console rules from nginx configuration (Aline Manera)
* [43f192c8] Remove former login design files (Aline Manera)
* [3d7543fc] Update test case to reflect new login design (Aline Manera)
* [6efdbcd4] authorization: Get role according to tab instead of sudo rights (Aline Manera)
* [63532075] authorization: Add "access" parameter to VM resource (Aline Manera)
* [d73696e2] authorization: Add "access" elements to tabs.xml to describe user view (Aline Manera)
* [99d84b7e] authorization: Update /login to return user roles instead of sudo parameter (Aline Manera)
* [d76fdd73] authorization: Update authorization rules per API (Aline Manera)
* [01176bb7] Always use unicode in KimchiException message (Aline Manera)
* [18a7a99f] Debug Report Rename: Update Test Code (Royce Lv)
* [1ad0650d] Debug Report: Update MockModel (Hongliang Wang)
* [4df19b21] Debug Report Rename UI: Enable Rename in Host Tab (Hongliang Wang)
* [45fe67c7] Debug Report Rename UI: Add Rename Page (Hongliang Wang)
* [c692ea86] Debug Report Rename UI: Add API in kimchi.api.js (Hongliang Wang)
* [e25a5c5b] Debug Report: Sort Reports by Generated Time Descendingly (Hongliang Wang)
* [6eec9c27] Debug Report: Use Generated Time instead of Most Changed Time (Hongliang Wang)
* [3bfc9759] Debug Report Rename: Implement Back-end (Hongliang Wang)
* [60c3dcdd] Debug Report Rename: Update API.md (Hongliang Wang)
* [b57dbd2b] Debug Report Rename: Update API.json (Hongliang Wang)
* [e897a347] Debug Report UI: Generate Report Doesn't Work with Mock Model (Hongliang Wang)
* [66cc0dc8] MockModel: Can't Generate Report if Name is not Given (Hongliang Wang)
* [dd707437] Add option to add/remove fonts files in rpm packages (ShaoHe Feng)
* [effe684f] Remove useless fonts (Aline Manera)
* [9d25fa29] Change ISO stream feature test and kvm user test for PPC (Rodrigo Trujillo)
* [cb8053e7] Update API.md to reflect /host/users and /host/groups API (Aline Manera)
* [07d5db07] Translation updates for underscore in debug report (Christy Perez)
* [33ec72cd] UI changes to allow underscore in debug report name. (Christy Perez)
* [b615f42f] Add SUSE's products (Dinar Valeev)
#### [kimchi-1.2.1] ####
* [31e0c0bc] Update Changelog and po files for 1.2.1 release (Aline Manera)
* [fcd407e8] bugfix: Add policycoreutils-python as Kimchi dependency (Aline Manera)
* [e475bfab] Add translation for vm disk attach exceptions (Royce Lv)
* [593c4201] Add testcase for vmstorages create (Royce Lv)
* [954185e1] Make sure path and volume will not be specified at same time (Royce Lv)
* [a93aa456] Add mockmodel for vm disk attach (Royce Lv)
* [fff58c24] issue#382: Validate form for adding guest cdrom (Royce Lv)
* [e5333d72] issue#382 :Change false default value (Royce Lv)
* [0599241e] update case for root.get redirection (ShaoHe Feng)
* [eed4f36c] remove kimchisession hook and add the same logic to root.get (ShaoHe Feng)
* [c13d53d6] bug fix: redirect to the protected page after login (ShaoHe Feng)
* [88affbe1] Issue #380: Loading icon message splitted into two lines in Chinese (Wen Wang)
* [5afa07f5] bug fix: UI set the network persistent attribute. (ShaoHe Feng)
* [4197f3ac] Bugfix: Minor i18n updates(Chinese) (Wen Wang)
* [9136f8d4] add firewalld to debian Install Dependencies (ShaoHe Feng)
* [0890b7ab] bug fix: Set charset to help pages (Aline Manera)
* [5ce667a1] Show remote Ubuntu 14.04 x86_64 in new Template window (ShaoHe Feng)
* [000149ee] Update i18n package scripts(Chinese) (Wen Wang)
* [e0a66431] Add missing translation entries in pt_BR (Crístian Viana)
* [93784bee] Add empty translation entries in English (Crístian Viana)
* [45703ecb] Help translation to zh_CN. (Paulo Vital)
* [c29f1e2b] Help translation to pt_BR. (Paulo Vital)
* [b4305761] Show remote Ubuntu 14.04 in new Template window (Rodrigo Trujillo)
* [b5425f83] escape special characters for jQuery selector. (ShaoHe Feng)
* [7b65e7b2] escape < > and & in in xml for network name. (ShaoHe Feng)
* [df9a017f] network name support unicode. (ShaoHe Feng)
* [2fabc33b] bug fix: network name can be any characters except " and / (ShaoHe Feng)
* [7167f316] Host info: Add support to Power. (Paulo Vital)
* [4b096f2d] Fix Bug: Actions Menu Disappears after Refresh in Guests Tab (Hongliang Wang)
* [234c1981] Bug fix: Do not require login for simple resources (Crístian Viana)
* [14bc6fcc] Typo: Rename function create_defautl_network (Crístian Viana)
* [ba96997e] Bug Fix: Fix network list layout. (Wen Wang)
* [4a91e749] Issue#348: Fix UI for nfs mount (Royce Lv)
* [3c6c5c51] List iSCSI targets available for initiator while creating iSCSI Pool (ShaoHe Feng)
* [35050bf6] List iSCSI server for initiator while creating iSCSI Pool (ShaoHe Feng)
* [3f61acbd] Issue #361: Bugfix disable the action button content when creating network (Hongliang Wang)
* [7467febc] Fix i18n packaging scripts (Zhou Zheng Sheng)
* [19b3c4a4] Keep User from Generating a Report with an Existing Name (Hongliang Wang)
* [a1bc654e] Add progress Event Handler for Asynchronized Tasks (Hongliang Wang)
* [5ea8e8f9] Add License Statement in kimchi.report_add_main.js (Hongliang Wang)
* [464d3d01] Add Name Existence Check for Debug Report when Create (Hongliang Wang)
* [c89c2e0f] Bug fix: Display the username on the header bar (Crístian Viana)
* [8ce46e69] Add doc and test case for dedicate iso pool (Royce Lv)
* [e3ab2cea] Store qemu user name in class attribute (Royce Lv)
* [5dc4dd27] Dedicated ISO pool: create an out of box ISO pool (Royce Lv)
* [ff927867] Reword 'isolated' network description (Christy Perez)
* [9aeac735] Disable cache for help page (Royce Lv)
* [27bd99f9] Create pool UI: making 'Create' button disable when forms not filled. (Daniel Henrique Barboza)
* [b7c518c2] bug fix: Make rpm failed (ssdxiao)
* [bd98489b] update ui/pages/Makefile.am to let i18n.json.tmpl be added to the package. (ShaoHe Feng)
* [578ab294] add some sample plugin generated files to .gitignore (ShaoHe Feng)
* [26582d86] skip plugins test, when sample plugin is not enabled (ShaoHe Feng)
* [de177c84] generate the translation files for plugins/sample (ShaoHe Feng)
* [3ce13b55] add an option to toggle the sample plugin (ShaoHe Feng)
* [38bee60a] Issue #342: load i18n.html of the plugin (ShaoHe Feng)
* [45b16d07] Add JS API for fetching i18n JSON (ShaoHe Feng)
* [947bce5e] Update the i18n tmpl to produce JSON (ShaoHe Feng)
* [32051172] Update root.py to make Cheetah render the JSON template. (ShaoHe Feng)
* [3d52774d] Add Minimal UI Page for the Sample Plugin (Zhou Zheng Sheng)
* [d8c2ea1c] Bugfix: List inactive network interface while editing template (Wen Wang)
* [cf015d4f] login: update test config case (ShaoHe Feng)
* [df4749b2] login page prompts error when session timeout (ShaoHe Feng)
* [ba0cf6e9] login page prompts error when username or password is wrong (ShaoHe Feng)
* [d7e828e0] when login successfully, redirect to the last page. (ShaoHe Feng)
* [85e38371] redirect the URL to login page when session timeout or first login (ShaoHe Feng)
* [8f865683] create a new login page (ShaoHe Feng)
* [a556578f] Bugfix: Multiple progress indicator during debug report generating (Wen Wang)
* [54e6bfad] Issue#305: Redesign bridged network UI section tempstorage (Wen Wang)
* [fe235580] Add Ubuntu as modern distro to Power guests. (Paulo Vital)
* [8c50cc8a] Added the generating progress indicator (Wang Wen)
* [250cc3d8] Remove the first column of debug report grid (Wang Wen)
* [c81314fd] Add testcase for cdrom eject (Royce Lv)
* [2768515c] Update model to support cdrom eject (Royce Lv)
* [3282020e] Change doc and controllor to support cdrom eject (Royce Lv)
* [cd676174] Adding test case for updating flags (Royce Lv)
* [a48518b5] Fix wrong create/update/delete flags for vmstorages (Royce Lv)
* [5fee8c2a] Fix Bug: Template Tab Broken in Chrome due to Code Error (Hongliang Wang)
* [08a9c00b] Bug Fix - Save Button Behaves Incorrectly in Guest Edit Window (Hongliang Wang)
* [f2f137e4] Remove Unused Files (Hongliang Wang)
* [c4117ab1] Adjust Guest Edit Storage Tab Styles (Hongliang Wang)
* [339c1aa8] show template is local or remote (ShaoHe Feng)
* [7835e160] Update API.md (Hongliang Wang)
* [67417002] Add Unit (MB) to Memory in Template Edit Window (Hongliang Wang)
* [b558fd90] bug fix: decode volume name in IsoVolumesModel. (ShaoHe Feng)
* [ef7e8e3b] novnc does not work in IE (Adam King)
* [8b6405f6] Code Refector: Extract Variables in kimchi.login_window.js (Hongliang Wang)
* [892238ee] Disable metadata log output in every guest refresh (Crístian Viana)
* [785920b2] Repository Grid Column Resizing Issue (Hongliang Wang)
* [76629f6b] StoragePool Edit: Add Disk to Logical Pool (Royce Lv)
* [5ee2b939] Exception: fix exception details when not specified (Royce Lv)
* [7ca9adef] Remove cdrom '.iso' suffix checking from add template js (Rodrigo Trujillo)
* [7e5f8b23] Remove '.iso' extension checking from json schema (Rodrigo Trujillo)
* [a1e73640] model.host: avoid redundant libvirt lookupByName API invocation (Zhou Zheng Sheng)
* [f7ec8f0e] Rename kimchi.template to kimchi.substitute (Hongliang Wang)
* [bd866e13] Remove unused listDeepScanIsos function (Rodrigo Trujillo)
* [44489485] Update README with the correct FF ESR version. (Adam King)
* [68d4d6cc] VM template: add disk size error message (Zhou Zheng Sheng)
* [0e165c47] adjust the width of host info-container (ShaoHe Feng)
* [d65b8e53] UI: Fix VM Delete Confirmation Dialog Box Title (Zhou Zheng Sheng)
* [96c19c68] Fix text alignment on storage pool type combo boxes (Crístian Viana)
* [c5329c2c] Remove button "Cancel" from modal dialog (Crístian Viana)
* [0666eeea] Fix Text Truncated Problem of Login Button (Hongliang Wang)
* [ff7f9910] bug fix: Allow changing default ports (Aline Manera)
* [96f32489] bug fix: Update test cases to use HTTPS (Aline Manera)
* [1d8476b6] host/partitions: avoid calling disks.get_partitions_names() for each partition (Zhou Zheng Sheng)
* [1d56572c] Correct the ID String of Disk Size in Template Edit Window (Hongliang Wang)
* [5c2a584b] Issue #369: Fix config_dir assignment (Aline Manera)
* [cc3b5b51] Revert "Host Tab: Add Widths for Repository Grid Columns" (Aline Manera)
* [5dc31951] Fix Text Wrapping Problem in Template Edit (Hongliang Wang)
* [9ececcf6] Fix Text Wrapping in Tab Bar (Hongliang Wang)
* [4128392b] Github #368: Removing 'resend' tag from getHostStats JSON (Daniel Henrique Barboza)
* [44ec020d] Set IE edge mode for VNC/Spice web pages (Adam King)
* [73e524cb] bug fix: Properly set the listen IP to SPICE console (Aline Manera)
* [58017f4e] websockets: Disallow non-encrypted client connections (Aline Manera)
* [381864f0] UI: Redirect user to console page after logging (Aline Manera)
* [be9b967d] backend: Redirect 401 error to default page (Aline Manera)
* [e1760d8b] Enable Kimchi authentication in console pages (Aline Manera)
* [74ad9b47] Make use of the mini Web server in the websockify (Aline Manera)
* [9116d539] Enable encryption in vm console connection (Mark Wu)
* [6ddf6a99] Revert "Enable encryption in vm VNC console connection" (Aline Manera)
* [dc6c28e7] vmiface update support: update test case (ShaoHe Feng)
* [b813d6cc] vmiface update support: update mockmodel (ShaoHe Feng)
* [309aa714] vmiface update support: update model. (ShaoHe Feng)
* [51820c47] vmiface update support: update API.md (ShaoHe Feng)
* [c356a759] Display all disk types in storage edit view (Royce Lv)
* [010aaaca] UI: Support add guest disk (Royce Lv)
* [b2d12179] Fix select menu data append (Royce Lv)
* [3c294a5b] Guest disks: Update testcase (Royce Lv)
* [5df01abc] Multiple pep8 fixes (Royce Lv)
* [2360f7c7] Guest disk: deals with disk attachment (Royce Lv)
* [1bc8aa6b] Guest disks: Abstract vm disk functions (Royce Lv)
* [7770a11d] Guest disks: Choose proper bus for device (Royce Lv)
* [4e7a17c8] Guest disks: Update api definition and error reporting (Royce Lv)
* [9c0e2a12] Guest disks: Update doc to support manage guest disks (Royce Lv)
* [93280792] Return info from run_command on exception. (Christy Perez)
* [781b3316] write the template OS info to vm metadata (ShaoHe Feng)
* [85665998] update test case to set/get user and group when VM is running (ShaoHe Feng)
* [2617373e] bug fix: get user and group when vm is living. (ShaoHe Feng)
* [d7e70170] manually manage the metadata element (ShaoHe Feng)
* [2c176c01] Add two function to set and get domain xml metadata (ShaoHe Feng)
* [1f1dcc39] add method to test libvirt metadata api are available (ShaoHe Feng)
* [d777a02b] bug fix: call a method should be followed by "()" (ShaoHe Feng)
* [06238f29] Enable encryption in vm VNC console connection (Mark Wu)
* [6bf630c8] Change the default tab to "Guests" (Crístian Viana)
* [9e85e59e] Define the default tab more clearly (Crístian Viana)
* [976db870] Refactor code to trim file extension (Crístian Viana)
* [37a1e1b3] bug fix: Redirect 3xx responses through proxy (Aline Manera)
* [a7f083c2] Set default storage pool to autostart and make persistent (Christy Perez)
* [6f5d0d97] Fix PEP8 in scan.py (Rodrigo Trujillo)
* [5de2ca86] security: Prevent XSS attacks (Aline Manera)
* [9d3bb9c2] bug fix: Use secure cookies (Aline Manera)
* [def7c674] security: Redirect all HTTP requests to HTTPS (Aline Manera)
* [819cc2a6] Fix Bug: Invalid URL at 404 Not Found Page (Hongliang Wang)
* [7132f759] Changes to use 2048 bit public key for self-signed certificate (Mark Wu)
* [6bac3ec5] Display historical host statistical info on the host tab (Adam King)
* [217858c5] Host stats history: Update test cases (Aline Manera)
* [9d2bf5cb] Add API to return host stats history (Aline Manera)
* [9b2eafbb] repository: Remove full stop symbol from checkbox's label (Crístian Viana)
* [087e739d] repository: Make checkbox clickable (Crístian Viana)
* [f2d6ff45] repository: Place checkbox to the left of its label (Crístian Viana)
* [b4f84dda] Modify edit guest help info (Rodrigo Trujillo)
* [4a8d603b] User action menu overflows when actions with names longer than a few chars a.. (Adam King)
* [1ef15619] Regenerate PO files (Adam King)
* [82c11811] Update po/POTFILES.in (Adam King)
* [3acf6c3e] UI: Edit Guest Network Interface (Yu Xin Huo)
* [19011c7d] Github #329: .gitignore, spec, control.in and readme (Daniel Henrique Barboza)
* [117cd5ab] Github #329: changes in mockmodel, model/config and tests (Daniel Henrique Barboza)
* [152d820e] Github #329: Kimchid, config.py.in and server.py changes (Daniel Henrique Barboza)
* [68835338] Github #329: Proxy module and template file (Daniel Henrique Barboza)
* [775e6306] New domain state pmsuspended (ShaoHe Feng)
* [177a147b] VM shutdown support in UI (ShaoHe Feng)
* [d242e305] VM shutdown support in backend (ShaoHe Feng)
* [44e545e5] Fix error storage pool lookup usage in deep scan (Royce Lv)
* [2271eeb3] Clarify the meaning of an empty vm user or group list (Christy Perez)
* [c01d9834] VM Edit: CPU and memory (Adam King)
* [b31a1345] VM Edit CPU/Memory: (Backend) Changes mockmodel and tests (Rodrigo Trujillo)
* [ac2c7de4] VM Edit CPU/Memory: (Backend) Changes VM control and model (Rodrigo Trujillo)
* [5ea76261] VM Edit CPU/Memory: (Backend) Changes API.md, API.json and i18n.py (Rodrigo Trujillo)
* [ecaf9a8e] Update test cases (Aline Manera)
* [f04f67f5] Remove unused code (Aline Manera)
* [17fd157a] Update users/groups verification based on new API (Aline Manera)
* [fe2fd1db] Add API to list system users and groups (Aline Manera)
* [5641e5e5] Create a new common collection named SimpleCollection (Aline Manera)
* [ce2bbbd8] Bug fix: add PYTHONPATH for contrib/check_i18n.py (ShaoHe Feng)
* [5c2013dd] packaging: ship kimchi with plugins/__init__.py (Zhou Zheng Sheng)
* [361cae4f] Display version/build number in UI (Adam King)
* [a67fe542] Host Tab: Add Widths for Repository Grid Columns (Hongliang Wang)
* [88c190a4] Issue#364: UI - Column Resizing Function Broken in Host Tab (Hongliang Wang)
* [257d0ffe] config version API support in backend. (ShaoHe Feng)
* [698b1016] config version API support: add a method to get kimchi version (ShaoHe Feng)
* [4c7c402e] Add/remove users and groups to VMs (Aline Manera)
* [ca0bfd91] Return users and groups when fetching VM info (Aline Manera)
* [0a38dc9f] Add functions to check if a user/group exists (Aline Manera)
* [021d4d14] Use proper term "user name" instead of "user id" (Aline Manera)
* [0348f4a8] Override only the updated "User" methods in "patch_auth" (Crístian Viana)
* [548f894d] Set virt_use_nfs when NFS pool is added. (Christy Perez)
* [767a34e4] Issue #363: Fix data/information consistence in edit template window (Rodrigo Trujillo)
* [16659a53] Issue #363: Add new rest api function - getStoragePoolVolume (Rodrigo Trujillo)
* [42662184] add a method to check the i18n strings are obsolete (ShaoHe Feng)
* [89411f91] remove obsolete i18n strings which are no longer in use (ShaoHe Feng)
* [3b112197] add a make check-local command to verify the i18n string formatting (ShaoHe Feng)
* [04d2d730] Choose available address for ide disk (Royce Lv)
* [5c487da7] add confirmation for reset a VM (ShaoHe Feng)
* [074f7c50] reset vm in UI (ShaoHe Feng)
* [86f1afa4] reset VM in backend. (ShaoHe Feng)
* [6fe59978] reset VM: update API.md (ShaoHe Feng)
* [9f626cb5] Bug fix #357 - Error when creating template from ISO (Ramon Medeiros)
* [d8617eb3] Fix backend error when creating multiple templates (Rodrigo Trujillo)
* [767e4865] Fix typo while processing request data (Aline Manera)
* [7c3bb7bb] Fix kimchi vlan tagged bridge name (Mark Wu)
* [3bf0173d] error when editing repository entry with no mirrorlist. (Paulo Vital)
* [de1d0f6a] kimchi.disks: Ignore unsupported partition table (Zhou Zheng Sheng)
* [68d86c56] Fix get_storageservers API and UI retrieval of storage servers. (Christy Perez)
* [e19383c6] help pages: Set default index file to /help URI (Aline Manera)
* [23042ddb] help pages: Update .gitignore file (Aline Manera)
* [65051dfc] help pages: Adjust css url (Aline Manera)
* [61d619ef] help pages: Remove former .dita files (Aline Manera)
* [a8f8abdd] Update build process to generate html pages for each help subdir (Aline Manera)
* [4e548cbd] Replicate help pages for pt_BR and zh_CN (Aline Manera)
* [aab87642] Bug fix #360: Support i686 architecture (Ramon Medeiros)
* [42f7771f] Fix volume not found error message (Rodrigo Trujillo)
* [4a34cbf0] Fix debugreports download issue (Mark Wu)
* [c7e47079] objectstore: support sorting by a key in get_list() (Zhou Zheng Sheng)
* [58efd8fe] add confirmation for power off a VM (ShaoHe Feng)
* [250565d6] change the stop to power off for VM in UI (ShaoHe Feng)
* [82fa8d19] change the stop to power off for VM in backend (ShaoHe Feng)
* [70dc7290] Try to activate physical interface when create a network on it (Mark Wu)
* [6e19ac44] Software Update: Make Update Progress Area Collapsible (Hongliang Wang)
* [c012f817] Issue #365: Preventing duplicate Bridged VLAN tagged network. (Paulo Vital)
* [11b2c7ff] improve Chinese translation (ShaoHe Feng)
* [3a2ed85d] Make use of the new forms handling capabilities (Adam King)
* [eadacde0] Extend jQuery form (Adam King)
* [229710ac] Extend base classes to support form processing (Adam King)
* [0e555f57] Fix hardcoded storage bus assignment in vmstorage (Rodrigo Trujillo)
* [58c90251] kimchi.exception: Properly Decode All Kinds of Exception Arguments (Zhou Zheng Sheng)
* [25bd8e04] Sort device paths shown when creating a logical storage pool (Rodrigo Trujillo)
* [02807f8a] Add template clone support (Adam King)
* [15b0e435] Fix pep8: add files to whitelist of Makefile.am (Rodrigo Trujillo)
* [5252d7ae] Fix pep8 issues in src/kimchi/objectstore.py (Rodrigo Trujillo)
* [75542bd2] Fix pep8 in src/kimchi/template.py (Rodrigo Trujillo)
* [b81f7bc4] Fix pep8 in src/kimchi/vmtemplate.py (Rodrigo Trujillo)
* [f2c436b9] Plugins UI: Correctly Load Plugin Tabs (Zhou Zheng Sheng)
* [e057827b] Fix 'disk full' issue: Fix vms/screenshot db store/delete error handling (Rodrigo Trujillo)
* [42a90729] Fix 'disk full' issue: Fix storagepool and asynctasks error handling (Rodrigo Trujillo)
* [fa0b9911] Fix 'disk full' issue: Fix storage volume error handling (Rodrigo Trujillo)
* [b787cba3] Fix 'disk full' issue: Fix Templates db store/delete error handling (Rodrigo Trujillo)
* [dc2174e1] Fix 'disk full' issue: Change objectstore exception handling (Rodrigo Trujillo)
* [e851d992] Add the command to run_command error and debug logging (Christy Perez)
* [833125cf] bug fix: we should pass str to cherrpy HTTPError (ShaoHe Feng)
* [f5c517ad] Issue #343 & #353: Improve & Correct UI Init Logic Flow (Hongliang Wang)
* [bd80b70b] AsyncTask: Propagate cherrypy request information to worker threads (Zhou Zheng Sheng)
* [0ea1f4b1] UI: change some code of storage add page (ShaoHe Feng)
* [d5fd304a] Fix non persistent network handling (mockmodel/tests) (Rodrigo Trujillo)
* [f3f55a83] Fix non persistent network handling (frontend) (Rodrigo Trujillo)
* [cc87c6af] Fix non persistent network handling (backend) (Rodrigo Trujillo)
#### [kimchi-1.2.0] ####
* [335ee71f] Update Changelog for 1.2 release (Aline Manera)
* [015ebb37] Remove LUN assignment in VM (Aline Manera)
* [103e87b6] Update po and pot files for 1.2 release (Aline Manera)
* [002ec769] Translate pt_BR.po file (Ramon Medeiros)
* [35c3000b] Chinese translation for release 1.2 (ShaoHe Feng)
* [1add01ed] bug fix: fix the string format %(pool). (ShaoHe Feng)
* [58da4288] Add error handling for repo management (Adam King)
* [2e4a46a0] Logical Storage Pool: Detect and Enumerate Multipath Block Devices (Zhou Zheng Sheng)
* [179bf149] validate the volume parameter when the pool of template is iscsi or scsi (ShaoHe Feng)
* [31fa6b89] Fix swupdate listing (Royce Lv)
* [9259c907] error message fix. (ShaoHe Feng)
* [b0569039] Fix a typo. (Leonardo Garcia)
* [b31e125f] bug fix: fix the string format. (ShaoHe Feng)
* [429d3700] Add lock in swupdate (Royce Lv)
* [a144b902] fix lock for apt package manager (Royce Lv)
* [1e3e121e] Properly display YUM exception (Aline Manera)
* [074e2656] UI: template edit page support scsi lun (ShaoHe Feng)
* [1060f98f] create a VM from an scsi pool template (ShaoHe Feng)
* [81bc75e6] create a VM from an iscsi pool template. (ShaoHe Feng)
* [0671de37] generate a iscsi volume disk for a guest (ShaoHe Feng)
* [6ac343a7] add a method to get iscsi storage pool auth information. (ShaoHe Feng)
* [f4db0d60] Help for scsi fibre channel (Kersten Richter)
* [e1e7baa7] Fibre Channel SCSI Storage Pool UI (Yu Xin Huo)
* [5f43812b] Added help for repositories (Kersten Richter)
* [5b14926c] Repository Management - Integrate into Host Tab (Hongliang Wang)
* [79991028] Repository Management - Edit Repository Support (Hongliang Wang)
* [55c426b0] Repository Management - Add Repository Support (Hongliang Wang)
* [057f2d45] Repository Management - Add API Support (Hongliang Wang)
* [66b1573f] Repository Management - Add i18n Strings (Hongliang Wang)
* [f18b0bc6] Update grid widget to populate fields from deeply nested objects (Adam King)
* [afea547e] Update form.serializeObject method to handle deep object serialization (Adam King)
* [0d51a2ff] Adds 'in_use' info to API.md (Rodrigo Trujillo)
* [622781de] Template: Check if the host supports Spice (Zhou Zheng Sheng)
* [a8f9f16f] but fix: show the content of combobox and filterselect in storage add page (ShaoHe Feng)
* [24cfe69d] Bug fix: specify the class attribute when change pool state dot. (ShaoHe Feng)
* [281d35c9] Optimize return code check. (Leonardo Garcia)
* [ddd588db] Show error message from debug report generation async task (Rodrigo Trujillo)
* [3d47c5c5] bug fix: Lock YUM operations (Aline Manera)
* [ace80feb] bug fix: Display update progress on real time (Aline Manera)
* [413e36ba] bug fix: Allow user specifies the repository name when adding a new YUM repo (Aline Manera)
* [ad283ee4] bug fix: Instantiate the apt-get manager when update the apt-get packages list (Aline Manera)
* [e94903ac] Issue#349: Software Update Grid Keeps Loading when Error Returns (Hongliang Wang)
* [81c16b48] run pyflakes when make check (ShaoHe Feng)
* [f4cbe913] add template_delete to rollback after create a template (ShaoHe Feng)
* [2fa81bf2] make pyflakes happly, remove unused availables (ShaoHe Feng)
* [8b64eb15] make pyflakes happly, remove the unused import module (ShaoHe Feng)
* [be5c57d8] Remove debug report's file path from UI (Mark Wu)
* [4fa40e1c] partitions: Fix when disk does not have extended partition (Royce Lv)
* [c177cae4] bug fix: instantiate the Yum manager when update the yum packages list (ShaoHe Feng)
* [4a43a7ca] Issue#352: Debug Report Section NOT Hidden for Non-root User (Hongliang Wang)
* [50a373a7] bug fix: Lock yum/apt operations (Aline Manera)
* [bc72f1ca] Update test cases to reflect the repositories changes (Aline Manera)
* [d369c919] bug fix: Do not store internal repository information (Aline Manera)
* [8536141e] bug fix: Let package manager tool create the repository ID (Aline Manera)
* [ca77c509] bug fix: Sort repositories (Aline Manera)
* [5e6300e2] bug fix: Raise exception comming from backend (Aline Manera)
* [384dbecd] Update messages used in the repositories management feature (Aline Manera)
* [340e4f55] mockmodel: Move specific repository data under 'config' (Aline Manera)
* [7d5fad59] bug fix: Reorganize repository information (Aline Manera)
* [81e54409] bug fix: Expose repository management tool name (Aline Manera)
* [9b40f581] VLAN: Do not allow bridge to be the trunk device (Zhou Zheng Sheng)
* [24c4319e] Fix iso streaming functions and feature tests (Rodrigo Trujillo)
* [c44b238f] sudo: run sudo with a pseudo controlling terminal (Zhou Zheng Sheng)
* [e609efa3] Display the error code when displaying error msgs (Crístian Viana)
* [f39dfe48] Apply Kimchi standard error message (Crístian Viana)
* [cb1ece8c] Do not show success messages (Crístian Viana)
* [6a45ad09] Doc: add work around to handle NFS root squash problem (Royce Lv)
* [13819abe] Fix issue 348: NFS pool creation times out (Christy Perez)
* [6d6c8160] Software Update: Enable "Update All" Button when Task Fails (Hongliang Wang)
* [6888a727] Changes to help (Kersten Richter)
* [38d8f1a8] Remove bridge and vlan interface unconditionally on removing vlan network (Mark Wu)
* [01c40357] Fix Bug - Text Overlapped in Template Add Window (Hongliang Wang)
* [9c2b7660] Fix multiple pep8 (Royce Lv)
* [a37e0bdd] Grid Loading Mask - Some Elements are Missing (Hongliang Wang)
* [58ab0163] Skip 'screendump' for vms no video device configured (Mark Wu)
* [cfd29f82] Controller: Improve Kimchi Specific Exception Reporting (Zhou Zheng Sheng)
* [4523b3ec] Grid widget presently interprets displays null values as null strings (Adam King)
* [22dc2afd] mockmodel: Reset packages after updating system (Aline Manera)
* [e6806e4a] UI: Disable stop/undefine buttons when network is in use (Aline Manera)
* [b590cd54] Do not allow user disable/delete a network used by VM or template (Aline Manera)
* [31f7bbf1] Software Update Support in Host Tab (Hongliang Wang)
* [95bd6162] Software Update - APIs in kimchi.api.js (Hongliang Wang)
* [31826530] Software Update - i18n Translation Strings (Hongliang Wang)
* [4f2b2341] Supplement to [PATCH v6 0/3] UI: Software Update Support (Adam King)
* [e9ab7440] bug fix: encode the args in KimchiException when is is unicode. (ShaoHe Feng)
* [8a6db107] Grid Enhancement - Show Message when Loading Data (Hongliang Wang)
* [c7009976] Correct the Repositories parameter name of is_mirror (Adam King)
* [9a546672] Start up Kimchi even if no repo management tool was identified (Aline Manera)
* [aee1318f] Expose repo_mngt_tool to /config/capabilities (Aline Manera)
* [0b811f6f] bug fix: Identify repository management tool based on available system tools (Aline Manera)
* [e3338e2d] bug fix: Identify update tool based on available system tools (Aline Manera)
* [96a02352] Changed xsl file to include stylesheet (Kersten Richter)
* [acde6c78] Added a style sheet to make the html look pretty (Kersten Richter)
* [35033c63] Commit changes to templates and storage.dita files (Kersten Richter)
* [34cd66f3] Added help for host and network tab. (Kersten Richter)
* [681ac873] Grid Enhancement - "title" Attribute for Long Values (Hongliang Wang)
* [5b921e0f] ISO Scan: Use volume set id instead of volume id for some wrong images. (Mark Wu)
* [e7c6426c] Issue #302: let 'create' attr of networks model to create default network (ShaoHe Feng)
* [42008eeb] add a new function to get an available network address (ShaoHe Feng)
* [39a2ba82] move _default_network_check from top model to networks model (ShaoHe Feng)
* [3df47fe1] Update guest action menu (Adam King)
* [626081f0] Pass ajaxError information on to original requester on ajaxError event (Adam King)
* [b113780f] Issue 292 Logical Storage Pool Returning "extended" Partitions as Possible P.. (Zhou Zheng Sheng)
* [5ed36d6b] bug fix: remove the hard code of disk_path (ShaoHe Feng)
* [378eb451] probe iso permission: update test case (ShaoHe Feng)
* [84a28fbc] Don't allow templates to be created with ISOs that won't be usable. (ShaoHe Feng)
* [af51f271] qemu user tests: probe the username of qemu process started by libvirt (ShaoHe Feng)
* [baed491b] add a method to probe the permission as qemu user (ShaoHe Feng)
* [de0400bc] Attach/Replace/Detach a CDROM to/in/from a VM (Hongliang Wang)
* [474e7746] Add/Edit CDROM Support (Hongliang Wang)
* [505409f4] Add i18n Variables for CDROM-related Function (Hongliang Wang)
* [f392c6d9] Add CDROM-related APIs (Hongliang Wang)
* [9cfb6385] kimchi.message - Enhancement (Hongliang Wang)
* [23b58503] Adjust CSS for Window (Hongliang Wang)
* [87a6eecc] Issue 294 The auto logout leaves action menu on page - update JS (Adam King)
* [28419d8e] Issue 294 The auto logout leaves action menu on page - add classes (Adam King)
* [f8ac146b] Fix formatting of the requestJSON function (Adam King)
* [9f91334b] pep8 clean for osinfo.py (ShaoHe Feng)
* [82a743b0] bug fix: add an icon distros list. (ShaoHe Feng)
* [8c3ce5f2] Build help index page only once (Crístian Viana)
* [2c7dbf8d] fix: Build new DITA pages when running "make" (Crístian Viana)
* [11e871ca] Multiple pep8 fixes (Royce Lv)
* [2ab54c17] Add volume ref_cnt: Update test (Royce Lv)
* [3f0e7755] Add volume ref_cnt: Add model and mockmodel implementation (Royce Lv)
* [757a254c] Add volume ref_cnt: Update controller and json schema (Royce Lv)
* [d55e72a2] Add volume ref_cnt: update api.md (Royce Lv)
* [bb89241e] Fix vm disk path when it does not have source element (Royce Lv)
* [86a9b4d6] Export list vms functionality (Royce Lv)
* [dfccd654] Allocate enough space for logical volume (Royce Lv)
* [a815850c] Window Widget Enhancement - Allow onClose Listener (Hongliang Wang)
* [834e48b8] Bug fix: Kimchi could not start guest with iscsi lun assigned as disk (Rodrigo Trujillo)
* [c092436e] issue #200: Rebuild .mo files when running "make" (Crístian Viana)
* [57f9f9f1] Do not show a success msg when creating a template (Crístian Viana)
* [7dc503d4] Window - Correct Footer Height (Hongliang Wang)
* [0c840f08] logical pool: Fix logical pool target path (Royce Lv)
* [75f31dca] Fix storage volume format on logical pool for vm (Royce Lv)
* [3fdbb1c6] Use a pool of threads to valid all remote ISOs in parallel (Aline Manera)
* [456018a1] bug fix: "sudo: sorry, you must have a tty to run sudo". (Paulo Vital)
* [389b13ce] Update distros JSON files to always point to a valid URL (Aline Manera)
* [7b69dfaf] issue #301: Add a loading message while listing default remote ISOs (Aline Manera)
* [db722421] issue #301: Only list remote ISOs with valid URL (Aline Manera)
* [33a92574] Increase memory size for vm template on ppc platform (Mark Wu)
* [5747b58a] Fix issue #339: Change mock and add test to check persistent variable (Rodrigo Trujillo)
* [88bb4a79] Fix issue #339: Changes UI to handle deactivation of non-persistent pools (Rodrigo Trujillo)
* [596ddb12] Fix issue #339: Enable backend to handle not persistent pools (Rodrigo Trujillo)
* [f11beaa9] Fix rollback order (Rodrigo Trujillo)
* [6d234f10] bug fix: Set default flags for virDomain.state() function (Aline Manera)
* [00a60b36] Issue #222: add python-xml to suse require list (ShaoHe Feng)
* [34a6073a] storage volume: fix xml parsing of logical volume format type (Zhou Zheng Sheng)
* [4be19f9b] Support ppc64 isos in Templates: Fix test cases (Rodrigo Trujillo)
* [6a81c0e1] Support ppc64 isos in Templates: Filter remote isos and change UI (Rodrigo Trujillo)
* [01d338b9] Support ppc64 isos in Templates: Add arch and urls to distro jsons (Rodrigo Trujillo)
* [0ef900cf] issue #330: Make sure exception argument is a string to convert it to unicode (Aline Manera)
* [e9a5071b] issue #312: Check volume group exists while creating a logical pool (Aline Manera)
* [186a2ad0] Refreshing an inactive pool causes exception (Shu Ming)
* [853908ac] session expire: update test case (ShaoHe Feng)
* [2907055a] UI: set kimchi robot header for some request. (ShaoHe Feng)
* [ad459df0] auth enhancement: expire the session when the request access periodically (ShaoHe Feng)
* [fa350f68] add timeout for sessions (ShaoHe Feng)
* [eb37a509] Issue #333: do not encode error.html when the cherrpy version less than '3.2.. (ShaoHe Feng)
* [707aee09] bug fix: setup disks to use cache=none to support live migration. (Paulo Vital)
* [6779b95c] While trying to extend a logical pool I got the following error message: (Aline Manera)
* [008e76fb] template integrity verification: update test case to verify storagepool (ShaoHe Feng)
* [2ec01d51] template integrity verification: verify storagepool in backend (ShaoHe Feng)
* [ae3b81b0] template integrity verification: verify storagepool, update API.md (ShaoHe Feng)
* [5f28f72b] Github bug #307: storage pool type list - html and string changes (Daniel Henrique Barboza)
* [a7ea3d26] Github bug #307: add storage pool type list - JS changes (Daniel Henrique Barboza)
* [d977d184] remove unused InvalidOperation instance (ShaoHe Feng)
* [7869c19e] Add test case for kimchi server configuration. (Mark Wu)
* [e65d00ab] Add static directory configurations for plugin's ui (Mark Wu)
* [668f5220] UI: Grid Widget - Enable/Disable Row Selection (Hongliang Wang)
* [e9f67dce] Bug Fix #282: Handle toggleNetwork error returns (Rodrigo Trujillo)
* [41ac09cf] Bug Fix #282: Disable Start/Stop network buttons while wait backend lag (Rodrigo Trujillo)
* [ee36b1f2] Clear pep8 failure in make check (Royce Lv)
* [4175f760] Prevent volume create and delete for certain pool types (Royce Lv)
* [20568e24] Fix vm creation storage rollback clean (Royce Lv)
* [729d15b3] UI: template support spice, update po (ShaoHe Feng)
* [6a17215a] UI: template support spice (ShaoHe Feng)
* [a9d94a77] Fix debug report UI: Error handling and line selection (Rodrigo Trujillo)
* [e1ed6cd6] issue #66: Auto generate template name in backend when none is provided (Aline Manera)
* [bd47f5a6] bug fix: Only check for ISO images in active pools (Aline Manera)
* [74614bdf] bug fix: Do not probe ISO file while checking template integrity (Aline Manera)
* [be2122dc] vmtemplate: Remove useless imports (Aline Manera)
* [276c13ae] Fix typo on KCHAPI6005E message (Aline Manera)
* [c8351751] bug fix: Enable NFS path field when a NFS server is provided (Aline Manera)
* [31c43980] Fix software update action into Host resource (Paulo Vital)
* [793e2c62] Fix test_osinfo.py to use new modern distro version dict. (Paulo Vital)
* [1a053171] Fix VM's network model template for Power systems. (Paulo Vital)
* [9abfad48] kimchi.control.utils: fix request parsing in generate_action_handler() (Zhou Zheng Sheng)
* [5d822419] Issue 299 Inactive storage pools are listed while editing template (Adam King)
* [279a7100] Can not create a VM from a template with disks['volume'] parameters. #181 (Shu Ming)
* [3100c0c3] Fix Kimchi vm tests according to new messages sent from backend (Rodrigo Trujillo)
* [5e902bf3] Delete unsed _vm_exists funtion (Rodrigo Trujillo)
* [9178089f] Fix VM delete error message handling (UI/Backend) (Rodrigo Trujillo)
* [d58edad9] Fix VM reset (UI) error messages hnadling (Rodrigo Trujillo)
* [82b80e32] Fix VM stop error messages handling (backend/UI) (Rodrigo Trujillo)
* [96f54575] Fix vm start UI error return message (Rodrigo Trujillo)
* [f8c9c600] Fix Add Network window (Rodrigo Trujillo)
* [eb8347ee] Add another way to download the debugreport file in the test (Shu Ming)
* [632c3caa] Have a meaningful description for the exception test #81 (Shu Ming)
* [7ee1b095] bug fix: check all Red Hat distributions for yum package management (ShaoHe Feng)
* [8931da13] Set default combo box style to storage pool type list (Aline Manera)
* [c4c093e3] issue #242: Do not allow user deactivate/delete storage pool used by a templ.. (Aline Manera)
* [26631c0a] bug fix: Make URI parameter is not None before encoding it (Aline Manera)
* [d58f4538] Authors cleanup (Paulo Vital)
* [e3ea028b] run_command: log error messages using higher log level when return code is n.. (Zhou Zheng Sheng)
* [c6e82129] Fix screenshots and debug reports paths. (Leonardo Garcia)
* [3514d3bc] Fix tests: restore the monkey patch after testing Paths (Mark Wu)
* [ca04f30e] Issue # 303 The password of iSCSI Authentication should be masked (Adam King)
* [e5cf3838] issue #325: Use RamSession instead of FileSession (Aline Manera)
* [e10177e9] Github bug #327: NFS pool workaround: model changes (Daniel Henrique Barboza)
* [5c388558] Github bug #327: NFS pool workaround: timeout adjustments (Daniel Henrique Barboza)
* [5076c7df] Github bug #327: NFS pool workaround: i18n changes (Daniel Henrique Barboza)
* [948445ff] Packaging: removed start of kimchid from RPM and DEB files (Paulo Vital)
* [d83510c0] bug fix: Properly display missing parameter (Aline Manera)
* [19f6fcf7] Clear out the guests list properly using jQuery (Adam King)
* [baff4780] issue #316: Only verify if path starts with '/' (Aline Manera)
* [ad1ecbc5] Add help to user menu (Adam King)
* [346d50dd] Fix debug report naming problem (UI) (Rodrigo Trujillo)
* [f1d433bf] Fix debug report naming problem (backend) (Rodrigo Trujillo)
* [cde51beb] Github bug #326: run_command: killing all children processes (Daniel Henrique Barboza)
* [0a345706] allow user to create a storagepool with name in his local language (ShaoHe Feng)
* [c580e08c] Issue #243: start/stop/display a VM whose name with "?" (ShaoHe Feng)
* [7cb61c05] Clear unused reference in vmstorages of 'kargs' (Royce Lv)
* [667a6b22] Issue #289: catch the libvirtError when failed to start a vm (ShaoHe Feng)
* [c35c3181] Fix Kimchi UI issues on IE11 (Adam King)
* [5a044d9c] Fix typo on API.json and add missing error messages (Aline Manera)
* [68988c35] cdrom: update model test for media update (Royce Lv)
* [cbab49f1] cdrom: fix cdrom change media (Royce Lv)
* [a319343f] Undefined lable in template buttons. (adriano)
* [30c383a9] Issue #315: edit/delete templates that contains slashes in their names (ShaoHe Feng)
* [243dd85b] Remove tabs in ui/pages/storagepool-add.html.tmpl (Aline Manera)
* [0af44e3c] Change guests tab to update the VM List by DOM manipulation (Adam King)
* [8e7ef052] Update the guest.html.tmpl to use the new circleGauge widget (Adam King)
* [6db93c87] Create a reusable jQuery circleGauge widget (Adam King)
* [b47595d9] Update (mock)model to generate proper JSON (Adam King)
* [3be6341f] PEP8 for mockmodel.py (Adam King)
* [977e7727] Fix PEP8 in test files (Aline Manera)
* [92d04e32] Fix ui/js/Makefile.am (Aline Manera)
* [09366f0f] Implement integrity verification: update test case (ShaoHe Feng)
* [99881280] Implement integrity verification: verify template integrity in backend (ShaoHe Feng)
* [ef8222b3] add a new method to get iso info for VMTemplate class (ShaoHe Feng)
* [f8bdc130] Implement integrity verification: verify template integrity, update API.md (ShaoHe Feng)
* [8c0ad966] issue #324 Improve error messages of creating a storage pool named "kimchi_i.. (Mark Wu)
* [2e93bbd7] Use $(wildcard) to list files in Makefile (Aline Manera)
* [c0ffb52c] Fix duplicate dev names in host with multipath storage (Rodrigo Trujillo)
* [898f3bd0] Return 403 Forbidden when user does not have permission to access kimchi (Aline Manera)
* [88b01a0e] Removing extra word from kimchi description (Christy Perez)
* [a4a64f91] add libxml2 to BuildRequires list (ShaoHe Feng)
* [af31ad13] Host's repositories management: Update error exception messages. (Paulo Vital)
* [1057a2f5] Host's repositories management: Update test-cases. (Paulo Vital)
* [c33ab871] Host's repositories management: Update Makefile (Paulo Vital)
* [f27bcdbe] Host's repositories management: Update backend. (Paulo Vital)
* [fcb7c68f] Host's repositories management: Update REST API (Paulo Vital)
* [b7b2ab35] Host's repositories management: Update API.md (Paulo Vital)
* [5eb9bd8e] Block access for non-root users (Aline Manera)
* [23df447c] Add one more case to network tests (Ramon Medeiros)
* [10a2ed4f] Bug fix #318 Kimchi fails creating new network (Ramon Medeiros)
* [40918255] bug fix: Properly check if there running vms before rebooting system (Aline Manera)
* [ba7dea2a] Bug fix: methods signature in storagetargets.py (Daniel Henrique Barboza)
* [7e4588e2] Add software update action to Host resource (Aline Manera)
* [a695185a] Remove unused vms reference in VMModel (Royce Lv)
* [c53b3eab] Fix encode and decode in storagevolumes.py (Royce Lv)
* [391befb0] ui: Add tooltip when hovering long names (Crístian Viana)
* [91bab780] doc: Generate index.html to join all help pages (Aline Manera)
* [0b7d8610] bug fix: Package doc html files into deb package (Aline Manera)
* [400f3d82] Setup VM's input and output template for Power systems. (Paulo Vital)
* [13d610b9] Fix exception for model test (Royce Lv)
* [db954e95] Implement integrity verification: don't disable network used by guest (ShaoHe Feng)
* [ff94a340] Fix Software Update rebase issue. (Paulo Vital)
* [f5506b94] clone template: update test case (ShaoHe Feng)
* [31dff43f] clone template: update model and mockmodel (ShaoHe Feng)
* [a4be3c04] clone template: update controller (ShaoHe Feng)
* [0f0c9911] Enhance generate_action_handler to redirect a new resource (ShaoHe Feng)
* [50f8272a] clone template: update API.md (ShaoHe Feng)
* [a823e208] Bug fix #309 - network: Unable to create vlan tagged on Ubuntu (Ramon Medeiros)
* [f5502f7d] doc: Ignore the generated files (Crístian Viana)
* [1b3310dd] doc: Export the help pages to cherrypy (Crístian Viana)
* [5257e699] doc: Add help files to dist packages (Crístian Viana)
* [31d9ccf3] doc: Add DITA help pages (Crístian Viana)
* [5c80111a] Enhance UrlSubNode decorator and kimchiauth tool to check for sudo rights. (Leonardo Garcia)
* [1ca8c6fc] Find out user groups and sudo status during login. (Leonardo Garcia)
* [cd65d8f8] Code cleanup. (Leonardo Garcia)
* [382105c9] CDROM Management: changes in tests/test_model.py (Daniel Henrique Barboza)
* [68f87842] CDROM Management: Guest vm storage devices mockmodel and rest api test cases (Rodrigo Trujillo)
* [9ce26155] CDROM Management: Devices management model implementation (Rodrigo Trujillo)
* [68701c21] CDROM Management: Update controller and API.json for guest storages (Rodrigo Trujillo)
* [56a6d9ad] CDROM Management: API.md and externalized error messages (Aline Manera)
* [cbf7a891] bug fix: display kimchi icon instead of cherrypy icon (ShaoHe Feng)
* [82f1b82f] Setup VM's boot order. (Paulo Vital)
* [c58465df] host update: Expose update tool (Aline Manera)
* [dae38306] host update: Update po files (Aline Manera)
* [d23ed36d] Host's software update: Update test cases. (Paulo Vital)
* [002cb04e] Host's software update: Update Makefile (Paulo Vital)
* [216db4f2] Host's software update: Update backend. (Paulo Vital)
* [c29a36f5] Host's software update: Update REST API (Paulo Vital)
* [3714aae9] Host's software update: Update API.md (Paulo Vital)
* [8e6fc17e] bug fix: fix python syntax error (ShaoHe Feng)
* [a9c80ac3] bug fix: make install miss ifaces.py (ShaoHe Feng)
* [bfb56083] Fix host debug report for Fedora 20 (Rodrigo Trujillo)
* [c74e1db9] Storagepool SCSI/FC: Modifies mockmodel and implements tests for FC pool (Rodrigo Trujillo)
* [7c0fc124] Storagepool SCSI/FC: Backend implementation (Rodrigo Trujillo)
* [ecb4d6c5] Storagepool SCSI/FC: API.md entries related to host pci devices (Rodrigo Trujillo)
* [e4d08f33] Storagepool SCSI/FC: Implement node devices API backend (Rodrigo Trujillo)
* [57ece7ad] Add mailing list information. (Leonardo Garcia)
* [39074746] Limit README.md to 80 columns. (Leonardo Garcia)
* [79abe0b6] Add hypervisor information on README.md. (Leonardo Garcia)
* [a3f157e7] refactor exception: Update all po files (Aline Manera)
* [0ee16b44] refactor exception: Update UI references (Aline Manera)
* [ce3953bb] refactor exception: Update gen-pot script to get messages from i18n.py (Aline Manera)
* [f137c23f] refactor exception: Update all exceptions (Aline Manera)
* [8d190599] refator exception: Update control to raise the exception message (Aline Manera)
* [715152ce] refactor exception: Set error messages for jsonschema validation (Aline Manera)
* [26020a59] refactor exception: Add messages to be translated on backend (Aline Manera)
* [e13997a0] refactor exception: Create a common Exception to translate error messages (Aline Manera)
* [b94d36c1] Fix path of plugins dir (Mark Wu)
* [41ba0262] pass params to create method of all Collections. (ShaoHe Feng)
* [9644c056] Fix wrong "Failed to list guest" message (Rodrigo Trujillo)
* [2f6ac7b7] Add disks to LVM pool: API.json changes (Daniel Henrique Barboza)
* [61945fd8] Add disks to LVM pool: mockmodel changes (Daniel Henrique Barboza)
* [0a54dab5] Add disks to LVM pool: API.md changes (Daniel Henrique Barboza)
* [b500a909] Add disks to LVM pool: control and model changes (Daniel Henrique Barboza)
* [d7458e78] Fix missing report-add html page in rpm (Rodrigo Trujillo)
* [db829acf] Fix controller base code: Update function is not using model_args (Rodrigo Trujillo)
* [2fed3f5e] change the vm name in test case (ShaoHe Feng)
* [0adea832] update test case for updating vm with unicode name (ShaoHe Feng)
* [60f3da3d] bug fix: failed to update vm with unicode name (ShaoHe Feng)
* [3f5cdd20] update test case for storage pool support unicode (ShaoHe Feng)
* [4f3d489f] Firewall: Adding WebSocket port in firewall rules (Paulo Vital)
* [8cac63d8] Storage pool support unicode correctly (ShaoHe Feng)
* [cc11627e] bug fix: Set full path to guest page file in guest tab (Aline Manera)
* [9f33184a] bug fix: Fix shallow scan broken after model refactoring (Aline Manera)
* [b9c05941] Make sure ISO files have read permission while starting VM (Aline Manera)
* [461452af] Remove kvmusertests.py (Aline Manera)
* [0e25ad25] Add a method to fix read permission on ISO files (ShaoHe Feng)
* [0368afae] Avoid useless libvirt error log produced by featuretests (apporc)
* [f84b4d5a] Packaging: add the basemodel.py to src/kimchi/Makefile.am (Paulo Vital)
* [02d94f56] Fix get vms list function name (Rodrigo Trujillo)
* [0d7d89cd] Add test cases for BaseModel (Mark Wu)
* [4a5ede75] Break the 'sample' plugin's monolithic model into several smaller ones (Zhou Zheng Sheng)
* [78443aed] refactor model: Update makefile and specs files (Aline Manera)
* [a0a4dc0f] Delete former model.py and rename model_ to model (Aline Manera)
* [17d10143] Update mockmodel imports (Aline Manera)
* [d0ff3f98] Update tests to use the new model (Aline Manera)
* [dd2b2f48] Update server to use the new model (Aline Manera)
* [a87ab931] refactor model: Create a separated model for host resource (Aline Manera)
* [8a93e686] refactor model: Create a separated model for vm interface resource (Aline Manera)
* [5e34a52f] refactor model: Create a separated model for vm resource (Aline Manera)
* [41f0cc79] refactor model: Create a separated model for template resource (Aline Manera)
* [977c2674] refactor model: Create a separated model for storage target resource (Aline Manera)
* [e67c3be7] refactor model: Create a separated model for storage server resource (Aline Manera)
* [b1d2c630] refactor model: Create a separated model for storage volume resource (Aline Manera)
* [f7001ca2] refactor model: Create a separated model for storage pool resource (Aline Manera)
* [8d004e13] refactor model: Create a separated model for interface resource (Aline Manera)
* [3bf22b37] refactor model: Create a separated model for network resource (Aline Manera)
* [39d1b7b9] refactor model: Create a separated model for config resource (Aline Manera)
* [9c38e1f6] refactor model: Create a separated model for debug report resource (Aline Manera)
* [e79ebaaa] refactor model: Create a separated model for plugins resource (Aline Manera)
* [c08c091e] refactor model: Create a separated model for task resource (Aline Manera)
* [a22d9329] Create a model to join all model resources implementation (Aline Manera)
* [4b00cab2] refactor model: Create a common model builder (Aline Manera)
* [f96d5e5b] refactor model: Move StoragePooldef from model to libvirtstoragepools.py (Aline Manera)
* [e2008c56] refactor model: Separate libvirtconnection from model.py (Aline Manera)
* [b77935bf] Allow plugin use kimchi's ui handler (Mark Wu)
* [44be0d2d] Add test cases for paths generation code (Mark Wu)
* [8bc4dded] Reorganize the kimchi's paths gereneration code (Mark Wu)
* [fce20301] Move resource config's info fetching to model level (Mark Wu)
* [2ab9785c] CSS: Change all CSS files indentation to 4 spaces (Crístian Viana)
* [ab999de1] CSS: Do not allow lines longer than 79 characters (Crístian Viana)
* [84df5f7b] HTML: Make the form element's labels clickable (Crístian Viana)
* [29e17e4e] Update README to direct users to the oVirt mailing list (Adam King)
* [9057ae17] Use Autoconf macros AC_PROG_MKDIR_P and MKDIR_P (ShaoHe Feng)
* [21f099f0] GET /plugins failed, fix it (ShaoHe Feng)
* [b1bf1055] get vms list by listAllDomains (ShaoHe Feng)
* [6bcbb3f0] Make guests template handling more robust like host template handling (Adam King)
* [fdbd2a8f] Remove the unnecessary 'exposed' (Mark Wu)
* [de892cbc] bug fix: Expose /storageservers (Aline Manera)
* [a6a49992] bug fix: remove decode for resouce ident when use cherrypy's default dispatc.. (ShaoHe Feng)
* [b67aa7b4] fix: Add missing license copyright to css files (Aline Manera)
* [89892831] PEP8 cleanup and bug fix for src/kimchi/utils.py (Mark Wu)
* [7410a58e] support create/delete VMIface: update testcase (ShaoHe Feng)
* [9072f67f] support create/delete VMIface: update API.json (ShaoHe Feng)
* [4cf2b6e9] support create/delete VMIface: update mockmodel (ShaoHe Feng)
* [c66c6759] support create/delete VMIface: update model (ShaoHe Feng)
* [f4942a01] bug fix: guest iface does not return model if no model is found (ShaoHe Feng)
* [dd5bf4a4] bug fix: Use cherrypy host to run feature tests instead of localhost (Aline Manera)
* [6ded2abc] VM supports interfaces: update testcase (ShaoHe Feng)
* [e2e5aabe] VM supports interfaces: update mockmodel (ShaoHe Feng)
* [d90f38e2] VM supports interfaces: update controller (ShaoHe Feng)
* [58259435] VM supports interfaces: update model (ShaoHe Feng)
* [398a171f] VM supports interfaces: update API (ShaoHe Feng)
* [304217b1] Add a control.vm module (ShaoHe Feng)
* [b4fe1dcf] bug fix: test case can not find plugin, fix it (ShaoHe Feng)
* [b0aed860] improve controller: set authentication automatically (ShaoHe Feng)
* [18b68ea5] improve controller: Root loads collections/resouces automatically (ShaoHe Feng)
* [5b82bdf7] improve controller: tag the collections/resouces of root with @UrlSubNode (ShaoHe Feng)
* [c7d2856f] improve controller: add a method to load root sub collections/resouces autom.. (ShaoHe Feng)
* [f68a3bcb] add gettext to package require list (ShaoHe Feng)
* [7cff21e9] Modify bug in spice UI (zhoumeina)
* [2ef94b9f] Add nfs server and target UI in create storage pool (zhoumeina)
* [504213f6] Fix libvirt nfs target probe problem (Royce Lv)
* [881361fa] Add showmount function and feature test for libvirt target probe (Royce Lv)
* [e024dd38] storage target: Add model support (Royce Lv)
* [d60c4b8d] storage target: Update controller and json schema (Royce Lv)
* [4be609ad] storage target: Update API.md (Royce Lv)
* [2e1657e8] storage server: Update model and mockmodel (Royce Lv)
* [e976b781] storage server: update controller.py (Royce Lv)
* [545ec785] Storage server: Update API.md (Royce Lv)
* [1740a255] Add testcase for GET param (Royce Lv)
* [478d01dc] Support params for GET method (Royce Lv)
* [4750f332] Remove 'encoding=iso-8859-1' from json.dumps() (Mark Wu)
* [7dfb3e43] Integrate nfs path check before create nfs pool (Royce Lv)
* [f575b52e] utils: Add nfs prevalication (Royce Lv)
* [0a02212e] storagepool: Use callback functions when deleting a pool (Crístian Viana)
* [41e4c8cc] storagepool: Do not assume different 'else' values in pool type (Crístian Viana)
* [7606325e] Issue #310: Query correct name to validate logical devices (Crístian Viana)
* [7813c631] storagepool: Add missing msg when no logical device is selected (Crístian Viana)
* [3a49821e] Ubuntu: Add the LVM dependency package to README (Crístian Viana)
* [c69fa0f1] Use cherrypy's default dispatcher for subcollection (Mark Wu)
* [43618b0b] UI bug fix: Set vlan_id value only if 'Enable VLAN' is checked (Aline Manera)
* [5e829c21] Add the iSCSI dependency packages to README (Crístian Viana)
* [6ae06e90] add a synchronous function with timeout to execute command (ShaoHe Feng)
* [f060c183] Add jquery widget dropDown button (zhoumeina)
* [a2e7b357] Modify vnc_proxy_port to display_proxy_port (zhoumeina)
* [19ae1dd2] Add the front end support for SPICE (zhoumeina)
* [b6054328] RollbackContext: Make it complied with Python Standard (Zhou Zheng Sheng)
* [1a2d3269] UI: Remove Unused Label Room for Debug Report (Hongliang Wang)
* [0dbfe200] host.css: Change Indent to 4 Spaces (Hongliang Wang)
* [5289d020] Add a timeout tuning environment variable for debug report test (Shu Ming)
* [f51dbbcf] Skip the debug report test if there is no tool avaible (Shu Ming)
* [88553a8c] Issue #308: Use correct iSCSI package for openSUSE (Crístian Viana)
* [1567cbba] spec: Open 8000 and 8001 port by default (Eli Qiao)
* [31ef97ff] Add support to RHEL 7 (Adriano Botega)
* [342334e2] Deep scan: listing 'unknown' bootable isos after deep scan (Daniel Henrique Barboza)
* [c3a548ee] UI: template supports networks (Xin Ding)
* [7b608a02] Add graphics parameters description in API.md (apporc)
* [655f03da] Update test case for graphics support (apporc)
* [4951d3c1] Update mockmodel for spice support (apporc)
* [6c3bc68a] Validate graphics parameters input by users (apporc)
* [88ddc578] Add spice backend support for kimchi (apporc)
* [5ab77d37] Fix break of deep scanning (Royce Lv)
* [f5b47406] network improvement: update test case to support vms field (ShaoHe Feng)
* [866e8361] network improvement: update mockmodel to support vms field (ShaoHe Feng)
* [dff73d0b] network improvement: add vms field (ShaoHe Feng)
* [2f54aaba] UI: All user to specify a vlan ID for a virtual network. (Mark Wu)
* [6b339da7] Support creating vlan tagged virtual network (Mark Wu)
* [69edfe9b] Generate libvirt's interface XML definition for vlan tagged bridge (Mark Wu)
* [b656d4dd] Fix qemu-io option in featuretests (Mark Wu)
* [dff70381] Add Fedora 20 and Ubuntu 13.10 to distros.d (Mark Wu)
* [319a83bd] Github issue #300: hardcoded server port fix (Daniel Henrique Barboza)
* [e57b07e8] Update the po files (Shu Ming)
* [99808b2b] Remove the legacy files (Shu Ming)
* [641ace24] Remove the legacy files from automake and package configurations (Shu Ming)
* [90b61f0a] Remove jquery-ui customization in network (Yu Xin Huo)
* [af8cac4b] Customize jquery-ui dialog (Yu Xin Huo)
* [762c522b] Customize jquery-ui menu (Yu Xin Huo)
* [5ba06d71] Customize jquery-ui button (Yu Xin Huo)
* [98827325] Remove vnc related code in mockmodel (Mark Wu)
* [f1234b19] Use one weksockify instance as all vms' vnc proxy. (Mark Wu)
* [84803654] Add a configuration for vnc websocket proxy (Mark Wu)
* [47e64e7d] Move configuration parsing to config.py (Mark Wu)
* [212dc335] Add the ISCSI translation po files (zhoumeina)
* [4997624f] Add UI support of iscsi (zhoumeina)
* [618035a9] Support VM template for Power machine (Mark Wu)
* [177c2a07] Dynamically generate template parameters for different distros (Mark Wu)
* [b4ca2a87] Fix: Storagepool json schema has not been tested when create new SP (Rodrigo Trujillo)
* [0b507ffe] pep8 cleanup for isoinfo.py (Aline Manera)
* [b5d80d88] isoinfo: Move _probe_iso() to IsoImage() (Aline Manera)
* [e885f0ba] Move ISO path validation to IsoImage() (Aline Manera)
* [ff79ea86] Move IsoFormatError() from isoinfo.py to exception.py (Aline Manera)
* [1eb47bf4] isoinfo: Use absolute path only for local ISO files (Aline Manera)
* [e0b2d832] isoinfo: Add default value for ignore_list paramter (Aline Manera)
* [67227583] template supports networks: update test case (ShaoHe Feng)
* [6f7fda81] template supports networks: update mockmodel (ShaoHe Feng)
* [51c1af4c] template supports networks: update model (ShaoHe Feng)
* [e777c77b] template supports networks: update controller and json schema (ShaoHe Feng)
* [7d03a1cd] template supports networks: update API (ShaoHe Feng)
* [601d1408] template supports networks: fix test case (ShaoHe Feng)
* [ee3377fd] template supports networks: let template xml support more networks (ShaoHe Feng)
* [1a0fd41b] pep8 cleanup for exception.py (Aline Manera)
* [be26ed4f] pep8 cleanup for distroloader.py (Aline Manera)
* [170709e7] qemu user tests: probe the username of qemu process started by libvirt (ShaoHe Feng)
* [8a7aca2e] plugin: fix dynamic import mechanism (Zhou Zheng Sheng)
* [05f999fc] test_model: test creating iSCSI storage pool (Zhou Zheng Sheng)
* [f163d22e] storagepool: Support Creating iSCSI storagepool in model.py (Zhou Zheng Sheng)
* [53e1d400] storagepool: rename and consolidate arguments of creating (front-end) (Zhou Zheng Sheng)
* [265de8d7] storagepool: rename and consolidate arguments of creating (back-end) (Zhou Zheng Sheng)
* [ab63bbad] storagepool: refactor _get_pool_xml() (Zhou Zheng Sheng)
* [08ff87d9] Issue #293: Resizing Issue When There Are Multiple Grids (Hongliang Wang)
* [5e5a6a63] touch 4 files when move RollbackContext, fix pep8 on them (ShaoHe Feng)
* [7c98d3b0] move RollbackContext from tests/utils to src/kimchi/rollbackcontext (ShaoHe Feng)
* [cb7c355d] Move all resources related to tasks to control/tasks.py (Aline Manera)
* [423e9bbc] Move all resources related to plugins to control/plugins.py (Aline Manera)
* [ae9cc6b4] Move all resources related to host to control/host.py (Aline Manera)
* [ceff3620] Move all resources related to config to control/config.py (Aline Manera)
* [0d44ed9e] Move all resources related to networks to control/networks.py (Aline Manera)
* [cd5d5bcf] Move all resources related to interfaces to control/interfaces.py (Aline Manera)
* [8a7a5f63] Move all resources related to storage volume to control/storagevolumes.py (Aline Manera)
* [05ce4ddf] Move all resources related to storage pools to control/storagepools.py (Aline Manera)
* [69a241ad] Move all resources related to debug reports to control/debugreports.py (Aline Manera)
* [6ea6d323] Move all resources related to templates to control/templates.py (Aline Manera)
* [1a23ce17] Move all resources related to vms to control/vms.py (Aline Manera)
* [f824fa21] Move basic controller resources to control/base.py (Aline Manera)
* [cae61e6d] Move login() and logout() functions from controller.py to root.py (Aline Manera)
* [9cf0c0fb] Move common functions for Resource and Collection to control/utils.py (Aline Manera)
* [2d6d1f5a] Move generate_action_handler() function to Resource() class (Aline Manera)
* [817d3ad2] Simplify domain xml in featuretests.py (Aline Manera)
* [b44e6587] pep8 cleanup for featuretests.py (Aline Manera)
* [07c25db3] fix whitespace in test_mockmodel (ShaoHe Feng)
* [c56582e2] logical pool: list unused physical volume (Zhou Zheng Sheng)
* [2553e21d] logical pool fixes: only list leaf devices, and read file instead of run "cat" (Zhou Zheng Sheng)
* [e467b321] Organize python imports (Rodrigo Trujillo)
* [1410acdb] Add support for Gentoo Linux (Crístian Viana)
* [320fd131] PEP 8: Fix an alignment issue in src/kimchi/auth.py (Zhou Zheng Sheng)
* [7cead00f] pep8 cleanup for root.py (Aline Manera)
* [de1867af] pep8 cleanup for cachebust.py (Aline Manera)
* [508ada2f] pep8 cleanup for auth.py (Aline Manera)
* [c0b9d572] Bug fix: Kimchi will try to create directory for 'DIR' storagepool (Rodrigo Trujillo)
* [f70d34f2] Replace tab to 4 spaces (Aline Manera)
* [86981731] Issue #290: correct the log usage (ShaoHe Feng)
* [5831b4de] screenshot: fix problem on Power of truncated picture (Royce Lv)
* [acbcf04b] Return source information for storage pool (Royce Lv)
#### [kimchi-1.1.0] ####
* [88e5ec69] Update changelog and version files for 1.1 release (Aline Manera)
* [bf6d929e] Issue #276, logical pool: a quick fix for the device listing rules, front-end (Zhou Zheng Sheng)
* [902d2957] Issue #276: logical pool: a quick fix for the device listing rules, back-end (Zhou Zheng Sheng)
* [b555f83e] PEP 8: cleanup src/kimchi/disks.py (Zhou Zheng Sheng)
* [85d16e12] Add some brazilian portuguese lang translations (Alexandre Tanaka Hirata)
* [f2de42ce] do Chinese translation for release 1.1 (ShaoHe Feng)
* [3c7f2d70] issue #287: Confirm box will be hidden by the window dialog (Xin Ding)
* [bf1d443b] Use spacewalk repo to get python-ethtool on suse. (ShaoHe Feng)
* [17732148] Add confirm box to create logical pool,and modify device path number (zhoumeina)
* [0faa9024] bug fix: Make sure to use string with os.walk (Aline Manera)
* [b12167b8] bug fix: Add authentication to host tab (Aline Manera)
* [0e274b8b] bug fix: Update openSUSE instructions in README file (Aline Manera)
* [d5fe662c] bug fix: Don't display vlan interfaces while creating network bridge (Aline Manera)
* [a6ddab1d] Issue #283: Fix memory leak caused by libvirt connection wrapper (Mark Wu)
* [7c62e724] Templates: Remote ISO Image page aligning mess (Xin Ding)
* [07111ae7] Meaningless text "Default Settings" in the templates tab page (Xin Ding)
* [8b41a3f3] create template in batch don't show success detail message (Xin Ding)
* [d2f4951c] Bug fix:251 template edit page disk unit with no unit and make cdrom disable (zhoumeina)
* [a4b412ca] Incosistent pages when no guests or templates available (Xin Ding)
* [3a44881c] Update test_model to compare distro name using unicode (Ramon Medeiros)
* [af05155b] Set autostart value for logical storagepool (Shu Ming)
* [3cf5330b] Issue #259: vm create: fail msg need to be more specific (Hongliang Wang)
* [1a97be65] Fix emulator path in feature tests (Mark Wu)
* [428fce57] Issue #279: some plugins/sample files are missing in dist. (ShaoHe Feng)
* [be5969d7] Tests: Generate UUID and use as temp report file name (Zhou Zheng Sheng)
* [1d158331] sosreport: fix name matching of the generated report file (Zhou Zheng Sheng)
* [c8a760ad] Support unicode on Host Basic Information page (Ramon Medeiros)
* [d57226d6] Issue #278: add iso_gen.py to Makefile EXTRA_DIST list (ShaoHe Feng)
* [0d63a802] Issue 277, Disable 'bridged' option when no interface available (Yu Xin Huo)
* [97139d8e] Issue #271, add address space for bridged nework (Yu Xin Huo)
* [842f72b4] Issue #241: require python-psutil version (ShaoHe Feng)
* [ed971d13] Issue #262: Switch tab lose default network type selection (Yu Xin Huo)
* [9a22f756] bug fix: set the network ip as bridge ip instead of subnet IP (ShaoHe Feng)
* [d43e5383] Bug #260 fix: Makes UI show missing storage volume information (Rodrigo Trujillo)
* [c8a25fd0] Bug Fix: Wrong host available memory value (Rodrigo Trujillo)
* [37f4d8cd] Issue #273: unittest.TestCase has no attribute 'assertLessEqual' (ShaoHe Feng)
* [e12b93ea] bug fix #254: Reset guest statistics when vm is powered off (Aline Manera)
* [1dd695d8] bug fix #257: Specify the mime type for debugreports static dir (Aline Manera)
* [01d72ca8] bug fix: Don't use shell=True in subprocess.Popen while running qemu-io test (Aline Manera)
* [175869d4] Issue #263: network: bridge network shows network/prefix (ShaoHe Feng)
* [89d4766d] Packaging: add host.html.tmpl to ui/pages/tabs/Makefile.am (Paulo Vital)
* [ce43d08c] Add build in localdisk back-end (zhoumeina)
* [92d81c6a] Add logical pool UI support (zhoumeina)
* [97a5e81b] Packaging: add the disks.py to src/kimchi/Makefile.am (Zhou Zheng Sheng)
* [55f5fa0a] Nit fix of scan_dir_prepare (Royce Lv)
* [2f4de5ff] Deduplication: deduplication in shallow scan (Royce Lv)
* [b44c66a8] Deep scan: Adding scan ignore path (Royce Lv)
* [8d55a0df] Deep scan result deduplication (Royce Lv)
* [e3cf2c28] interface bug fix: only expose the unused interfaces to the front end (ShaoHe Feng)
* [e9b8deb2] Tests: fix test_model.ModelTests.test_debug_reports (Zhou Zheng Sheng)
* [612b8e31] UI: Enhancement & Fixes for Host Monitoring (Hongliang Wang)
* [1bf51f91] Issue #240: The bridge address of nat and isolated network is invalid, fix it (ShaoHe Feng)
* [b1dd7b40] Interface: Fix status return (Rodrigo Trujillo)
* [132bfc52] Logical StoragePool: changes in API.md (Daniel Henrique Barboza)
* [59a09764] Logical StoragePool: changes in controller.py (Daniel Henrique Barboza)
* [343f3d18] Logical StoragePool: changes in model and mockmodel (Daniel Henrique Barboza)
* [d9a2013d] Logical StoragePool: adding disks.py module (Daniel Henrique Barboza)
* [2686b5f1] PEP8 cleanup for server.py (Mark Wu)
* [8e488fff] Add deep scan test (Royce Lv)
* [6b2f43a8] ISSUE #236: Fix break of deep scanning (Royce Lv)
* [02192e5d] Add pseudo iso_gen for deep scan test (Royce Lv)
* [64c541ac] Template: Enable update Disk size and CDROM path (UI) (Rodrigo Trujillo)
* [d7b1be8f] Add dependency of nfs client (Royce Lv)
* [a7223e02] Concatenate ISO URL correctly with port number (Crístian Viana)
* [ebac998a] UI: Host Monitoring (Hongliang Wang)
* [f684b364] Issue #235: changetoProperUnit Returns Wrong Result (Hongliang Wang)
* [01640989] change the unit of host disk and net IO rate from kb/s to B/s (ShaoHe Feng)
* [006f7732] Fix test cases according to new Templates Schema validation (Rodrigo Trujillo)
* [46e9b940] Enable template data verification against json schema (Rodrigo Trujillo)
* [c57da0d1] Json schema for templates (Rodrigo Trujillo)
* [b9b4359c] Host reboot and shutdown backend implementation (Rodrigo Trujillo)
* [76f8d5d6] ui: Adjust storage pool window layout (Aline Manera)
* [2ad5768f] po files: NFS pool (Pradeep K Surisetty)
* [e62ff62b] Add/delete NFS pool (Pradeep K Surisetty)
* [76653ec2] bug fix: remove wlans from nics. (ShaoHe Feng)
* [33f487e5] bug fix: assert list append successfully when get all network interfaces (ShaoHe Feng)
* [f793d3aa] Fix minor issue in import order (Rodrigo Trujillo)
* [3ddb97dd] Add Network UI Files to Makefile (Yu Xin Huo)
* [f7a0fa8b] network UI: update po files (Yu Xin Huo)
* [dc0fc099] create/delete network (Yu Xin Huo)
* [f2cf0b61] List/Start/Stop Network (Yu Xin Huo)
* [e6b0afcf] Center the storage pool "Actions" button (Crístian Viana)
* [842e55be] Use consistent padding in storage pool details (Crístian Viana)
* [4e2748a7] Use jQuery to load xml to make code consistent (zhoumeina)
* [8e23fef2] host net-io: update test case (ShaoHe Feng)
* [c4721dfc] host net-io: update model and mockmodel (ShaoHe Feng)
* [80bcbcb9] host net-io: update API.md (ShaoHe Feng)
* [b0bc8ba8] Authentication is required to access networks (ShaoHe Feng)
* [853cdf1d] network: update test case (ShaoHe Feng)
* [df2b66ec] network: update mockmodel (ShaoHe Feng)
* [3e0d05b4] network: update makefile, spec file and README (ShaoHe Feng)
* [9070d60c] network: update model (ShaoHe Feng)
* [d30ca35f] network: generate network xml and testcast for it (ShaoHe Feng)
* [26ee2089] network: update controller (ShaoHe Feng)
* [dbe31d3e] network: update API.md (ShaoHe Feng)
* [e7c9ce78] Add license to scan.py file (Aline Manera)
* [65f6ad34] Organize imports in all .py files (Aline Manera)
* [0048f33a] fix disk unit: 1K bytes is 1024 bytes instead of 1000 bytes (ShaoHe Feng)
* [ad75a6fb] Add test cases for plugin support (Mark Wu)
* [2abc2516] Add a sample kimchi plugin (Mark Wu)
* [9fb6a09e] Move API schema loading to the initialization of application (Mark Wu)
* [f8793900] Add a plugin mechanism for Kimchi server (Mark Wu)
* [ce3e182b] Add the missing Makefiles for plugins support (Mark Wu)
* [f22dd255] Add a helper function to get kimchi python package directory (Mark Wu)
* [302f1866] host disk-io: update test case (ShaoHe Feng)
* [f987fb58] host disk-io: update model and mockmodel (ShaoHe Feng)
* [76f3f5bc] host disk-io: update API.md (ShaoHe Feng)
* [940742ac] Fix kimchi make rpm fail error (zhoumeina)
* [e2930100] Authentication is required to access debugreports (Shu Ming)
* [f2fce9dc] Add the front-end support of tabs (zhoumeina)
* [ebf366fd] Add the back-end support of tabs (zhoumeina)
* [b45e7098] Template update UI return 'cpus' and 'memory' as numbers (Rodrigo Trujillo)
* [277bd3bb] UI: deep scan (Xin Ding)
* [a83f2ee2] Use "dropdown" CSS class on the Edit Template page (Crístian Viana)
* [11f78db4] Format template and storage pool details (Crístian Viana)
* [7cb6c2a9] deep scan: Probe iso information (Aline Manera)
* [00d01a79] Add sos/sosreport package as Kimchi dependency (Aline Manera)
* [af1de8e0] Expose if the host has at least one system report tool (Aline Manera)
* [c75d7732] Fix low version libvirt bug when get cpuinfo (malcolm yu)
* [df327bb5] VM Edit UI (Hongliang Wang)
* [81a7b87c] vm-rename fix: return domain after static config change (Royce Lv)
* [89b7631b] Sort the storage pool list (Crístian Viana)
* [09f9ee0b] Update storage pool list after activate/deactivate (Crístian Viana)
* [722c5a8d] vm-rename: Update testcases for vm-rename (Royce Lv)
* [bb895c69] vm-rename: Update mockmodel for vm edit (Royce Lv)
* [b2953fcc] vm-rename: Update model for vm edit (Royce Lv)
* [edaa063a] vm-rename: Update controller (Royce Lv)
* [a0223e21] vm-rename: Update API.md for vm rename (Royce Lv)
* [ceb4ca3f] host memory stats: update test case (ShaoHe Feng)
* [e225c83a] host memory stats: update model and mockmodel (ShaoHe Feng)
* [95dda58d] host memory stats: update API.md (ShaoHe Feng)
* [63f6f778] support recrusive probe in iso scanning (Royce Lv)
* [ab7518fc] Fix session locking issue (Mark Wu)
* [59a8a086] amend API.md (ShaoHe Feng)
* [cdb9023e] host info: update test case (ShaoHe Feng)
* [f0f069c6] host info: update mockmodel (ShaoHe Feng)
* [371dcdcd] host info: update model (ShaoHe Feng)
* [4843de78] host info: update controller (ShaoHe Feng)
* [cd1d5451] host info: update API.md (ShaoHe Feng)
* [45df3704] interface: update makefile, spec file and README (ShaoHe Feng)
* [2036b2c1] interface: update test case (ShaoHe Feng)
* [6f22e4e9] interface: update mockmodel (ShaoHe Feng)
* [9054bf93] interface: update model (ShaoHe Feng)
* [c47ba916] interface: update controller (ShaoHe Feng)
* [5ced3ef5] interface: update API (ShaoHe Feng)
* [1bd987ce] interface: some new utils to get the interface info (ShaoHe Feng)
* [76515edf] Add json schema for API's request parameters (Mark Wu)
* [8ceadbed] Extend the action decorator into an action handler generator (Mark Wu)
* [da4f395d] host cpu usage: update test case (ShaoHe Feng)
* [f84e32dd] host cpu usage: update mockmodel (ShaoHe Feng)
* [ca7648b5] host cpu usage: update model (ShaoHe Feng)
* [1f558d70] host cpu usage: update controller (ShaoHe Feng)
* [18b24b36] host cpu usage: update API.md (ShaoHe Feng)
* [8ef7b15f] Use socket.getservbyname() to get the default port of a protocol (Aline Manera)
* [4c054235] Expose the number of CPUs assigned to a VM (Aline Manera)
* [e40d2375] Make the report tool silent in the background (Shu Ming)
* [1c807b67] DebugReports: Downloading the archives (Shu Ming)
* [cd74bb85] DebugReports: Implement the real backend (Shu Ming)
* [b01b9f41] DebugReports: Implement the mock model (Shu Ming)
* [bb59b46c] DebugReports: Add collection and Resource (Shu Ming)
* [b81fce35] DebugReports: Define the APIs (Shu Ming)
* [31f60d79] Add testcase of template storagepool customise (Royce Lv)
* [aa77a7ad] pre-create validate: validate for mockmodel vm create (Royce Lv)
* [94b3b653] pre-create validate: Add iso/storage/network availabilty check (Royce Lv)
* [623135f4] test storage pool not changed after vm customization (Royce Lv)
* [24b4c23e] model: aggregate vm config customization when creating (Royce Lv)
* [02aa5eb0] mockmodel: generate customised temporary template when create vm (Royce Lv)
* [549da651] Customise template storage: Report 'storagepool' info in controller (Royce Lv)
* [1a090d68] Customise template storage: Update API.md (Royce Lv)
* [e2e5892d] Set a custom pool for a template (Xin Ding)
* [226f6f74] deep scan: add model support (Royce Lv)
* [0469f1ec] Deep scan: Add functions for deep scan preparation (Royce Lv)
* [c359641c] Deep scan: update controller (Royce Lv)
* [c71a5a6f] Deep scan: Update API.md (Royce Lv)
* [b5e5bc24] Deep scan: Fix isoinfo.py for iso can't be reported (Royce Lv)
* [0c603c5e] Adding "python-psutil" package to Kimchi (Daniel Henrique Barboza)
* [fe82184f] Issue #227: Misunderstood labels and error messages in templates tab. (Paulo Vital)
* [39dae679] Fix text wrap in template and guest (zhoumeina)
* [1d306446] issue #228: Use SIGKILL to kill proc in featuretests (ShaoHe Feng)
* [0e50096c] close libvirt connection in featuretests (ShaoHe Feng)
* [e74728c2] Add gen-pot to .gitignore list (Aline Manera)
* [7d86a64d] Add missing ui files to spec file (Mark Wu)
* [c3395758] Distribute po/get-pot.in instead of po/get-pot (Mark Wu)
* [0bd82455] bug fix: put distroloader.py in Makefile dist list (ShaoHe Feng)
* [50a37a40] Remove 'config.py' from the distribution (Mark Wu)
* [07d9a85b] Bug fix:153 Drop kimchi-iso from storagepool list (zhoumeina)
* [2ee72cec] bug fix: Use vm uuid to properly get vm statistics (Aline Manera)
* [a276aff5] bug fix: correct to use float when calculate guest net and disk IO (ShaoHe Feng)
* [38bb3bde] iso streaming: Add default port for all protocols (Aline Manera)
* [b4e01222] ISO streaming: Enable UI (Aline Manera)
* [620618b9] iso streaming: QEMU workaround (Aline Manera)
* [29c73388] iso streaming: Libvirt workaround (Aline Manera)
* [93d3ccc2] Expose QEMU ISO streaming functionality to host capabilities (Aline Manera)
* [03aa2e99] feature tests: Verify QEMU can properly work with hostname while streaming I.. (Aline Manera)
* [9e1eae2d] feature tests: Verify QEMU supports ISO streaming (Aline Manera)
* [e14dec15] feature tests: Rename libvirt test to express what it does (Aline Manera)
* [99331be1] distros: update testcase in test_rest and rest_model (ShaoHe Feng)
* [8a2980a4] distros: add mockmodel and model implementation (ShaoHe Feng)
* [d8b067a5] distros: update Controller to add Distros collection and Distro resource (ShaoHe Feng)
* [7e2a5ac7] distros: update API document (ShaoHe Feng)
* [7add3d9c] distros: add a DistroLoader to load distros (ShaoHe Feng)
* [185cad13] distros: add new distros files (ShaoHe Feng)
* [0e3cb342] Drop IE8 support in README (zhoumeina)
* [cbcbd5dd] pep8 cleanup for asynctask.py (Mark Wu)
* [cafab099] Enable pep8 code style checking (Mark Wu)
* [ad793e0b] Display error message on template delete failure (Crístian Viana)
* [a138304c] Choose right icon for centos iso (Royce Lv)
* [949fc692] Add jquery-ui files to dist data list. (Yu Xin Huo)
* [b1d5002d] isoinfo: Allow the main program probe a single ISO file (remote or local) (Aline Manera)
* [193ab1a3] templates: Try to identify distro and version from remote ISO file (Aline Manera)
* [e7f33373] isoinfo: Add support to identify distro and version from remote ISO file (Aline Manera)
* [26f1688f] StoragePool: Pool name error message (Pradeep K Surisetty)
* [e9599d55] Add jquery-ui (Yu Xin Huo)
* [00536ab3] Remove redundant interface in api.js (zhoumeina)
* [8f3e38c1] Issue #199: Update templates list only after success of deleteTemplate (Aline Manera)
* [cbafe92c] vm-uuid: Update testcases (Royce Lv)
* [053fa95b] vm-uuid: Report uuid in controller (Royce Lv)
* [d44883e6] vm-uuid: make vm stats indexed in uuid (Royce Lv)
* [b0bbc20a] vm-uuid: store vm extra information indexed in uuid (Royce Lv)
* [d022fffb] vm-uuid: Use uuid in screenshot generation (Royce Lv)
* [8d70b27d] vm-uuid: Using uuid in vmtemplate (Royce Lv)
* [51e9766e] Use "font-weight: bold" in header texts (Crístian Viana)
* [ec381bbc] No HttpOnly is set to the cookie for session id (Xin Ding)
* [18567d7d] Use libvirt api to implement find_qemu_binary (apporc)
* [ce122351] eliminate messages keys from all po files (ShaoHe Feng)
* [1e164ca7] bug fix: make gen-pot scan multi lines (ShaoHe Feng)
* [765887d1] Add the three translation for Chinese (zhoumeina)
#### [kimchi-1.0.1] ####
* [1726c5bd] Update ChangeLog for the 1.0.1 release (Adam Litke)
* [9d0c89c4] Do not generate ChangeLog when outside a Git repo (Crístian Viana)
* [c44d03bf] Add VERSION file with Kimchi version (Aline Manera)
* [51d365f2] Get the appropriate Kimchi version from Git tag (Crístian Viana)
* [d9d4cdd1] Fix variable name "iptype" (Crístian Viana)
* [564babe3] Issue #97: "Make distclean" does not remove all the intermediate files (Paulo Vital)
* [4a6edb23] Issue #180: Singular/plural noun agreement on "Templates" (Crístian Viana)
#### [kimchi-1.0.0] ####
* [d665854e] Update ChangeLog for the 1.0.0 release (Adam Litke)
* [0448a5a3] opensuse: Start kimchid automatically (Adam Litke)
* [5db3d20e] Issue #173: set the correct mime type of Content-Type in HTTP respose header (ShaoHe Feng)
* [665406d3] Bugfix: Issue #182 int object has no attribute isdigit (apporc)
* [06541047] Encode parameters in URL generated by the server (Xin Ding)
* [f7fa1d81] Encode parameters in URL When calling REST APIs (Xin Ding)
* [4fdc7083] Make header text sizes equal (Crístian Viana)
* [3c88c7ff] build: Generate ChangeLog (Adam Litke)
* [51f15c6a] issue #183: Display all template information in pt_BR on Firefox (Aline Manera)
* [adb065f3] i18n: Update translation catalogue (Adam Litke)
* [f4d7f5b2] Fix typo in English translation (Aline Manera)
* [65bdf9e4] Issue #183: Adjust Template Tile Layout (Hongliang Wang)
* [916344a3] Fug fix:Chinese tooltip will wrap in storage (zhoumeina)
* [045c506c] change the storage arrow style, and make arrow disable when inactive (zhoumeina)
* [b45b62cf] i18n: Update pt_BR translations (Aline Manera)
* [27cebf6b] Issue #154: Prompt User When Creating VM and There is NO Template (Hongliang Wang)
* [85195d61] Issue #191: Log-in Name Disappears after Restarting Browser (Hongliang Wang)
* [4cf0113e] Issue #190: Language Selector Value NOT Match Page Content (Hongliang Wang)
* [6c855317] Bug fix: login window will have scroll bar when putted wrong password (zhoumeina)
* [111494af] Drop the handle in storage,fix the position error of the navbar arrow (zhoumeina)
* [917d120c] The icon image for unknown os is not suitable (Xin Ding)
* [aea983c5] issue #166: Destroy storage when vm define fails (Royce Lv)
* [32696700] The size unit of scanned ISOs is wrong (Xin Ding)
* [66be2735] kimchid: Fix default for 'host' parameter (Adam Litke)
* [1fd22841] Add the translation of English and Chinese (zhoumeina)
* [832a2705] bug fix: 404 error in debugger network tab when creating new VM (Aline Manera)
* [457afa8a] Apply Kimchi style to login screen (Aline Manera)
* [26f8b502] model: Handle libvirt connection failures (Adam Litke)
* [b97428f0] MockModel: fix mock_environment (Adam Litke)
* [e7c976e7] Issue#93 UI Not updated after deleting the last guest (fix) (Adam King)
* [e5154261] issue #171: Adjust template box style to avoid text overlapping (Aline Manera)
* [3d4d2099] Fix bug:145 Make a util to change the storage unit (zhoumeina)
* [318a1833] update test case after a series unit bug fixed (ShaoHe Feng)
* [385a1b0d] bug fix: keep the default value of storage info from libvirt (ShaoHe Feng)
* [8171fcca] bug fix: set the capacity unit to MB when pass it the storagevolumes_create. (ShaoHe Feng)
* [508cbdbf] bug fix: mockmodel set the storage volume size to MB according to the API.md (ShaoHe Feng)
* [aee9ebef] bug fix: Update API for storage volume resize (ShaoHe Feng)
* [5eb9b8be] Issue: #177: iso storage volume get wrong allocation value (ShaoHe Feng)
* [8976efdb] Add spaces around words on "Templates" (Crístian Viana)
* [4ed3db96] tests: Add tests to verify data validation when editing a template (Aline Manera)
* [cf817b99] issue #75: Validate parameters when updating a Template (Aline Manera)
* [71a3a883] Create default network if it does not exist (Aline Manera)
* [59efe0c2] bug fix: Fix log error message when kimchi can not create default pool (Aline Manera)
* [c20106f0] bug fix: Fix typo while logging information to cherrypy handlers (Aline Manera)
* [e97498ac] bug fix: Import missing modules (Aline Manera)
* [6d8d739f] doc: Restart libvirt after installing packages (Adam Litke)
* [53871982] tests: Add assertIn and assertNotIn for python2.6 (Adam Litke)
* [7498532b] Update README and packaging files for release (Adam Litke)
* [f8ef6246] Fix typo on Storage Tab (Aline Manera)
* [f6a60ff1] change the login window css to make language selector in the head (zhoumeina)
* [0509118e] Issue #174: error page can not be translated, fix it. (ShaoHe Feng)
* [de3cc142] UI Template Edit: Hide Unsupported Items (Hongliang Wang)
* [87b2930c] Fix bug Regex in checking url (zhoumeina)
* [149f12d6] Align storage header in Storage tab (Aline Manera)
* [e7e8c618] Autostart storagepools created from kimchi (apporc)
* [d41f4f52] UI: Enable Language Selection (Hongliang Wang)
* [87049d16] Enable the template_create test with non-root account (Shu Ming)
* [ba5fbc35] Streamline template creation flows - update (Xin Ding)
* [0abccf7b] bug fix: Recognize openSUSE 12.3 ISO file (Aline Manera)
* [a8c54301] Fixed the regx pattern (Shu Ming)
* [d244cb6a] bug fix: Recognize Fedora 19 ISO file (Aline Manera)
* [488784e3] Issue #133: mv make_dirs from kimchid.in to server.py (ShaoHe Feng)
* [ac1d7c25] Streamline template creation flows (Xin Ding)
* [436ce3e7] doc: Update images in README (Adam Litke)
* [4ea86e3b] Issue #167: Duplicate Requests for HTML Fragment when Switching Pages (Hongliang Wang)
* [657bb3b8] Issue #161: Firefox Doesn't Take Correct Favicon for Kimchi (Hongliang Wang)
* [0ba88f80] bug fix: remove ordereddict from suse spec require list (ShaoHe Feng)
* [768441a9] Style of uneditable fileds in template edit (Xin Ding)
* [26a94273] Change the ico of iso (zhoumeina)
* [6f74c37a] Bug fix:137 UI: When expanding an empty pool, show a message in the drawer (zhoumeina)
* [827f3b2a] Issue #151: No Message when User Opens http://kimchi:port/#i18n (Hongliang Wang)
* [316565ca] issue#149: fix relative symlink path error in iso scan (Royce Lv)
* [cb7b5e54] Issue #131: Wrong Arrow Position after Error Page (Hongliang Wang)
* [87fdfb83] Add test for refresh and vol number display (Royce Lv)
* [0c7900a9] Update model to support refresh and 'nr_volumes' info (Royce Lv)
* [fa3ffc22] Change mockmodel to refresh pool volumes (Royce Lv)
* [2391429e] Update Controller to add 'nr_volumes' into its info (Royce Lv)
* [8c4fedce] Update the description StoragePool and StorageVolume in API.md (Royce Lv)
* [868db8ee] Add testcase for create volume for active pool (Royce Lv)
* [76579473] Prevent mockmodel from creating volumes for deactive pool (Royce Lv)
* [45c6769a] Activate default pool for mockmodel (Royce Lv)
* [78f18e78] Create default pool and activate in model (Royce Lv)
* [3a33f1c7] Issue #112: Guest reboot and power buttons do not have hover text (Hongliang Wang)
* [b8ad3fdc] Issue #147: Storage UI NOT List Storage Automatically After Logging in (Hongliang Wang)
* [d514ac6a] KPI: Updates model and mockmodel tests (Aline Manera)
* [c2dcfa94] KPI: Update API documentation (Aline Manera)
* [8e6448e5] Display disk I/O rate instead of storage usage (Aline Manera)
* [f6c1daf5] Display network I/O rate instead of memory usage (Aline Manera)
* [dd1b6044] Create new thread to collect Kimchi statistics (Aline Manera)
* [9e20380e] Fix Log-in Window Redrawn after 401 Returned (Hongliang Wang)
* [55391565] tests: Fix auth tests (Adam Litke)
* [87dc3226] tests: Add authentication tests (Adam Litke)
* [3d993d34] Issue #125: Switching Page Tabs Breaks Pop-up Menu Disappearing (Hongliang Wang)
* [f00ee099] i18n: Correct storage pool create error message (Adam Litke)
* [adf3ac38] issue #143: Add missing parameter while calling the request error handler (Aline Manera)
* [a915292c] Add the globalization translation in English/Chinese (zhoumeina)
* [8ccaf94f] Fix bug: Storage pool name will wrap when it contains - and white-space (zhoumeina)
* [b27d1f42] issue #141: Fix regex responsible to check if an URL is valid or not (Aline Manera)
* [e9a87235] fix issue #136 about mockmodel iso pool type (Royce Lv)
* [d412d207] There will be two goto homepage button at the #tag nonexistent page (zhoumeina)
* [d894fc17] Aggregate read for iso to improve scan efficiency (Royce Lv)
* [6ffb568d] Add a go to homepage button at the error page (zhoumeina)
* [cd1b23d9] capabilities: Update REST API tests (Aline Manera)
* [f5089e88] capabilities: Update API.md (Aline Manera)
* [8f54df9d] Capabilities detection (Aline Manera)
* [b0a0c73d] screenshot: Expose stream test result (Aline Manera)
* [99f9d9e4] Update Test Code (Hongliang Wang)
* [d00782c5] Edit Template API: Change HTTP Code to 303 (Hongliang Wang)
* [cfc30c82] UI: Update Template (Hongliang Wang)
* [f12ebc04] UI:[Storage support]Add the html of Storage support (zhoumeina)
* [53cad8d6] UI:[Storage support]Add the js files of storage (zhoumeina)
* [59f07ab2] UI:[Storage support]Add the css style of the storage page (zhoumeina)
* [3d9a7ff5] UI:[Storage support]Add the po files of storage ui design (zhoumeina)
* [e806e87c] UI:[Storage support]Add the png files for storage ui design (zhoumeina)
* [6d72c828] tests: Disable auth debug (Adam Litke)
* [740ae820] tests: Fix unit tests after auth was merged (Adam Litke)
* [c8876e30] auth: Prevent HTTBA in browser with FF Poster (Adam Litke)
* [114d52ed] Enable UI (Hongliang Wang)
* [e13434a4] Enable Cookie Manipulating in Client Side (Hongliang Wang)
* [bd1367be] Enable REST API (Hongliang Wang)
* [d69d14cd] authentication (ShaoHe Feng)
* [f2949fab] Raise exception when cdrom URl does not match any criteria (Aline Manera)
* [ec0dd6a6] Create sanity test to verify libvirt supports iso streaming (Aline Manera)
* [2a0504d0] Adjust VM xml to support iso streaming (Aline Manera)
* [2d9ee88c] bug fix: Use unitdir macro when creating directory for systemd units (ShaoHe Feng)
* [706a277d] Create templates by shallow scan, deep scan and distros (Xin Ding)
* [50a5f269] shallow scan: Update testcases (Royce Lv)
* [0ef21303] Shallow scan: Add mockmodel implementation (Royce Lv)
* [e652eaf1] shallow scan: Add model support (Royce Lv)
* [451c006c] shallow scan: Change controller to be compatible with virtual pool (Royce Lv)
* [e2dd5333] shallow scan: return unknown distro and version rather than none (Royce Lv)
* [3bceeaf9] shallow scan: Report path info to storage volume (Royce Lv)
* [fac0794b] shallow scan: extend API.md to make volume report iso information (Royce Lv)
* [04539921] Create template iso path needs to check (zhoumeina)
* [f1594e49] Fix bug:119 Action will be closed after refresh each 5 s (zhoumeina)
* [9e7ccbae] No html escape in the kimchi.template function (Xin Ding)
* [a3b48917] Add browser support in README (zhoumeina)
* [78ba75c5] Remove the msg check in test_exception.py (Bing Bu Cao)
* [d64c1fb2] Catch the libvirt exceptions when accessing storage objects (Bing Bu Cao)
* [0ca05c13] Return abspath for iso scanning (Royce Lv)
* [7a018407] Add parentheses around dependency version in deb control file (Aline Manera)
* [781ba1d1] issue#110: Fix list storage volume for inactive pool (Royce Lv)
* [b53bb352] Add testcase for InvalidOperation (Royce Lv)
* [a21aaeb1] Catch InvalidOperation in collection (Royce Lv)
* [99638deb] tests: Test the REST API using an SSL connection (Adam Litke)
* [2f26f371] server: Support SSL connections (Adam Litke)
* [a92de0dd] api: Add an API to retrieve application configuration (Adam Litke)
* [8aac0d1d] bug fix: add two dependencies in README. (apporc)
* [7dd12436] bug fix: two python souce missing in distribution (apporc)
* [1e467308] build: Include extra top-level files in dist (Adam Litke)
* [e8f27d82] Issue #76 - ImportError: No module named discover (Bing Bu Cao)
* [270a9716] adopt a single log convention (ShaoHe Feng)
* [fff1bdf6] IE8: The arrow indicator of dropdown menus can't be displayed (Xin Ding)
* [c73d9e61] A module to check the pam authenticate (ShaoHe Feng)
* [a724d98f] set expires for static content caching (ShaoHe Feng)
* [c89a1ed3] cacheBust parameter for static content caching (ShaoHe Feng)
* [ce1ad9c9] add a cachebust module to generate href with cacheBust (ShaoHe Feng)
* [253a8940] IE8: No background style for items in the template list page (Xin Ding)
* [0ea6333e] IE8: No selected style for items in the main (Xin Ding)
* [44202b0a] Fix indent of the js files (zhoumeina)
* [4d78ca5e] template-update: real model support implement update method (ShaoHe Feng)
* [d3f864b0] template-update: add the test case for update (ShaoHe Feng)
* [d3c4cb29] template-update: mock model support implement update method (ShaoHe Feng)
* [7d924e62] template-update: resouce support update method (ShaoHe Feng)
* [f67cf47c] template-update: define an update method in API.md document (ShaoHe Feng)
* [dab26886] codingstyle: Fix indent for templates.html.tmpl (Adam Litke)
* [d12b4747] IE8: The template list page can't be displayed (Xin Ding)
* [d24d1d5e] Add delete confirm message box (zhoumeina)
* [40f0d9d4] issues #95: Added files generated by build to .gitignore (ShaoHe Feng)
* [6528b11e] IE8: Very long guest names cause column misalignment (Xin Ding)
* [8b6f92ff] issue #82: convert from svg image to png image (ShaoHe Feng)
* [41206f4c] Add Portuguese (Brazil) translation (Aline Manera)
* [e1eb228a] Remove magic directories from config.py.in (Adam Litke)
* [9bc6ba23] i18n: Stop adding location comments to po files (Adam Litke)
* [c8738677] Issue #39: Animate Button Clicks to Provide User Feedback (Hongliang Wang)
* [692cdd66] ui: Rename tab pages (Adam Litke)
* [eb1c6a3e] python2.6 do not support dict key iteration (ShaoHe Feng)
* [c59b7d62] Using absolute path in error page (Royce Lv)
* [5f04ac07] test case for creating a vm with unicode name (ShaoHe Feng)
* [1797fe8c] mockmodel support a VM with ww language name (ShaoHe Feng)
* [af8014d3] support create a vm with unicode name (ShaoHe Feng)
* [a4c99ebd] sqlite3 support unicode (ShaoHe Feng)
* [ae358e4f] Passing the options from autogen.sh to configure (Shu Ming)
* [ff869d5b] remove the translation keys in i18n.thml and update the po files (ShaoHe Feng)
* [afb3a77b] UI: update some labels of template edit page (ShaoHe Feng)
* [04395d54] All templates translate all languages no exceptions for English (ShaoHe Feng)
* [49a02da3] Issue #72: Make Pages Be Bookmark-able (Hongliang Wang)
* [a5fceb29] fix bug:35 GUEST 'VNC' do not work which graphic type is 'spice' (zhoumeina)
* [bfd91d81] ui: Keep image ratio while displaying VM icon and screenshot image (Aline Manera)
* [1846daab] Exception: Add UI support (Royce Lv)
* [431d5543] Exception: Add testcase to test error reporting (Royce Lv)
* [55d84e1f] Exception: Distinguish development mode and production mode in kimchi server (Royce Lv)
* [14633037] Exception: reporting error in controller.py in details (Royce Lv)
* [dc8881f1] Exception: Customise error page handler (Royce Lv)
* [b8c6eee5] Exception: move exceptions from model (Royce Lv)
* [3e86f3fd] ui: Disable 'Create' button on create guest without required input (Aline Manera)
* [c5e3951a] Update Banner image for Kimchi rename (Adam King)
* [551a564b] Issue #43: UI Reports Error When Pressing Enter Key in Creating VM Form (Hongliang Wang)
* [75ce9073] fix bug:#51 guest tab contains 404 file not find error (zhoumeina)
* [2086de3a] Bug fix:#67 add M for template memory (zhoumeina)
* [831160b0] update UI to get connect graphics (ShaoHe Feng)
* [a196235f] add graphics in mockmodel (ShaoHe Feng)
* [091af9bc] add an attribute to get graphics of vm in model and update test case (ShaoHe Feng)
* [9d178206] bug fix: Add graphics of vm in API.md document (ShaoHe Feng)
* [4c227f5c] Add ignore_missing parameter to ObjectStoreSession.delete() method (Aline Manera)
* [7c5b4d38] add automake and autoconf to dependencies (zhoumeina)
* [895f18c6] add i18n.html.tmpl in dist_html_DATA list (ShaoHe Feng)
* [e67e4794] doc: Update README.md with new build steps (Adam Litke)
* [91746b71] Rename burnet to kimchi (Adam Litke)
* [da6bc2ca] build: Set install prefix using autoconf (Adam Litke)
* [0eba7d3a] build: remove old distutils build files (Adam Litke)
* [818f1845] build: Add support for building distro packages (Adam Litke)
* [544d8bd9] build: Add gettext i18n support (Adam Litke)
* [b868785a] build: Compile, distribute and install files (Adam Litke)
* [3529c606] build: Add basic autotools infrastructure (Adam Litke)
* [fff51671] screenshot: Add timeout to screenshot creation (Aline Manera)
* [5bebdc20] bug fix:#49 404 in debugger network tab when opening kimchi templates tab (zhoumeina)
* [30bc539a] tests: Fix test_server_start (Adam Litke)
* [6228dee0] ui: Ensure i18n.html loads (Adam Litke)
* [7e963feb] Remove obsolete data used in rendering page (Royce Lv)
* [cc89b1e3] add js globalization method (ShaoHe Feng)
* [0c1cdcb6] Asynctask: add logging to async task (Royce Lv)
* [37b87abd] Remove 'path' which should not be specified when creating volume (Bing Bu Cao)
* [95b74466] Use #unicode instead of #encoding in Cheetah templates (Aline Manera)
* [cbd5afae] fix bug: xmlutils get node context by context attribute (ShaoHe Feng)
* [80df6765] issue34: add handling invalid iso file (Royce Lv)
* [5380105f] issue60: Avoid using default database file in test (Royce Lv)
* [56b6e672] Issue #59: Make the popup menu entirely visible in browser (Hongliang Wang)
* [8796558b] template: add rhel to osinfo (Royce Lv)
* [e05096c8] bug: fix list vm name in unicode for mockmodel (Royce Lv)
* [de4d8b46] bug fix: kimchi supports to show VM with Chinese name (ShaoHe Feng)
* [b5fa8c2c] Fix the exception caused by IE8 (Shu Ming)
* [4a8fcfdc] fix-bug: remove the useless mini-line (ShaoHe Feng)
* [130d98b6] UI:Add Template button should be disable but not hide before input the iSO (Xin Ding)
* [7c4c1b52] fix-bug: issues30 UI:Add Template contains js errors (Xin Ding)
* [a747f742] Hidden the VNC button when VM is stopped (Bing Bu Cao)
* [f17e1011] #32 template name too long make page abnarmally (zhoumeina)
* [2477c0c9] Fix Issue #10: Very long guest names cause column misalignment (Hongliang Wang)
* [1b33dedd] Remove useless text in template-add.html.tmpl (Xin Ding)
* [868abd77] doc: Update README.md with more package dependencies (ShaoHe Feng)
* [5cda59c2] Need root privilege to run test_vm_list_sorted test (Shu Ming)
* [69669a1d] test: change testcase to allow running single test (Royce Lv)
#### [v0.1.0] ####
#### [kimchi-0.1.0] ####
* [3efcaa26] Enable the usage of test:///default (Eduardo Elias Ferreira)
* [96f604ff] Ordered guest list (Eduardo Elias Ferreira)
* [7c06d1d2] Convert VM list to unicode (Eduardo Elias Ferreira)
* [72125907] Cannot delete a VM that is powered on (Eduardo Elias Ferreira)
* [85927b01] Check if VM exists before stopping or deleting (Eduardo Elias Ferreira)
* [dcabdcbb] ui: overwrite vm start and stop click event to fix multi-click bug. (ShaoHe Feng)
* [03cbce42] ui: add a vm load icon for multi-click bug. (ShaoHe Feng)
* [90e586e3] Change test filename to a standard format (Eduardo Elias Ferreira)
* [0e2801e4] fix bug: UI displays abnormal follow the README (ShaoHe Feng)
* [61332e78] fix bug: let i18n_files depends on po files instead of mo files. (ShaoHe Feng)
* [98c03738] Bug Fix: Get correct exception info when run unittest on Python2.6 (Bing Bu Cao)
* [811c10e1] Raise an exception in skipUnless() to abort the test on Python2.6 (Bing Bu Cao)
* [2ac72903] mockmodel: Use ps|grep to find open VNC port (Aline Manera)
* [acfa9f22] Add another path for SLES11 to find the qemu binary (Bing Bu Cao)
* [329a4c3a] ui: Fix screenshot flicker (Royce Lv)
* [9ed459c7] fix: Remove extra import statement in objectstore.py (Aline Manera)
* [41ab0c0c] Tasks: Implement the backend (Shu Ming)
* [0968b5c9] Tasks: Implement mock model (Shu Ming)
* [41f107e1] Tasks: Splitting ObjectStore from model file (Shu Ming)
* [bf3501f6] Tasks: Define the APIs (Shu Ming)
* [73437833] Correct License file to correctly cite ASL2 (Adam King)
* [59831080] Bug 94806 screenshot can not display from design UI. JS Updates (Adam King)
* [5e6ebea6] Bug 94806 Screenshot live tile gets 404 on initial load. Refactor html (Adam King)
* [9a232633] Update setup.py make_po task to be verbose (Adam King)
* [34f1f3eb] Remove unused rule .template-drop in template list CSS (Hongliang Wang)
* [75a4e4f5] Update the Rest and MockModel tests to account for the server no longer redi.. (Adam King)
* [0cf1d006] Update controller.py to prefer InternalRedirect to HTTPRedirect (Adam King)
* [4b65b209] Add RHEL6 support (Eduardo Elias Ferreira)
* [f2149f47] Merge pull request #3 from crobinso/fedora-pil-fix (Adam Litke)
* [163c3cdf] Fix Image imports on Fedora 19 (Cole Robinson)
* [6fbc8ed4] ui: Display template icons (Adam Litke)
* [9fc1789b] templates: Scan ISO to determine os_distro and os_version (Adam Litke)
* [68baf7a7] Identify Operating System from ISO file (Adam Litke)
* [7ee068d6] osinfo: Fix osinfo to use the correct distro shortnames and versions (Adam Litke)
* [8fafad1e] Refactor osinfo/VMTemplate parameter handling (Adam Litke)
* [365e6e55] Update design ui html template to use favorites icon (Adam)
* [2becd3a6] Add icon file for use as favorites icon (Adam)
* [c8c0eb75] Make logging level configurable (Aline Manera)
* [b59ab8ac] Separate burnet logs into access log and error log (Aline Manera)
* [ff5d076d] tests: Screenshot is not available until vm is started (Adam Litke)
* [c812468b] Add improved README with screenshots (Anthony Liguori)
* [59a94c89] ui: remove the mocked up username (Anthony Liguori)
* [48b6efbf] UI: Support Edit a Template (Hong Liang L Wang)
* [e7b69fe0] ui: template creation without iso scan support (xinding@cn.ibm.com)
* [2783ce99] UI: Support List Templates & Delete a Template (Hong Liang L Wang)
* [0f18271a] new ui: Display a VM's icon when it is powered off (Aline Manera)
* [47f5c52a] Revert 5a9ff5d61fa03c19c71c1d22e0f841ca1377a423 This patch is part of the fu.. (Adam Litke)
* [5a9ff5d6] add template navigation title (zhoumeina)
* [40c1eaa6] change button styles according to the latest ui design (Xin BJ Ding)
* [d364d02d] Bug Fix: this patch fix the bug 95350 (Bing Bu Cao)
* [ed4ec609] Added additional patterns to .gitignore (Adam King)
* [07d906d7] Add cpu_stats field to ModelTests (Aline Manera)
* [0f094b16] Generate the cdrom XML based on template config. (Tony Breeds)
* [fc6e2b9e] Move bus_to_dev into the VMTemplate class. (Tony Breeds)
* [30515ef5] bug: using whitespace when probing qemu process with vnc option (Bing Bu Cao)
* [c44dfaf9] UI: remove red exclamation point before the vm name (ShaoHe Feng)
* [70db7f47] burnet: relicense source tree (Anthony Liguori)
* [0ecc1a3d] Assume guest arch is the same as host, rather than x86_64. (Tony Breeds)
* [1a8bc2fe] Display percentage of CPU usage for each virtual machine (Aline Manera)
* [d14d2d56] ui: Display a warning if the UI needs to be built (Adam Litke)
* [96035143] packaging: python-polib is required (Adam Litke)
* [61a170a8] dev-ui: Fix vnc linkage (Adam Litke)
* [1df03643] Fix screenshot stream resource leak (Royce Lv)
* [d7c586b3] ui: Update the build process and server configuration (Adam Litke)
* [2a91a9d8] ui: Import pages and i18n (Adam Litke)
* [f852fa38] ui: Import javascript files (Adam Litke)
* [b3502a37] ui: import modernizr (Adam Litke)
* [21a23549] ui: Import jquery-1.10.0.min.js (Adam Litke)
* [4ca183ac] ui: Import the default theme images (Adam Litke)
* [67bef518] ui: Import css files for the default theme (Adam Litke)
* [df49b712] ui: Namespace the dev ui (Adam Litke)
* [97896507] ui: Filter all requests for html pages through cheetah (Adam Litke)
* [40e5b6b4] Move noVNC files into new directory structure (Adam Litke)
* [975bfa4a] Reorganize UI files (Adam Litke)
* [40a538f7] ui: Let the UI pick the default icon for a VM (Adam Litke)
* [3d414ed4] i18n: Fix install paths of gettext .mo files (Adam Litke)
* [ffa826ce] Revert b8cfa245b868d4778c68f407fcf3180dde895673 I applied a patch to fix fli.. (Adam Litke)
* [313b52d9] ui: Increase screenshot refresh frequency (Adam Litke)
* [4552ca51] ui: Allow scrollbars on the VNC window if necessary (Adam Litke)
* [b8cfa245] Fix screenshot image flicker (Royce Lv)
* [77b11774] do not translate en_US (ShaoHe Feng)
* [0a83bd7e] add README for i18n (ShaoHe Feng)
* [096f5122] check pygettext.py is available (ShaoHe Feng)
* [16b259ac] install the i18n files correctly (ShaoHe Feng)
* [983e1406] info_po command to show the summary infomation of po files (ShaoHe Feng)
* [f222a31a] add make_po command to generate or update po files (ShaoHe Feng)
* [28b5875f] give gettext another nickname ' _t' (ShaoHe Feng)
* [beee18cf] trim index.tmpl to make pygettext.py happy (ShaoHe Feng)
* [26d56d78] translate burnet home page to Chinese (ShaoHe Feng)
* [2c0af9f7] initialize the language select on the URL loading (ShaoHe Feng)
* [8a400040] i18n the title 'hostname' of index.tmpl (ShaoHe Feng)
* [d099fb34] define a dummy _() function to defer actual translation (ShaoHe Feng)
* [8a36c456] generate mo files during build time (ShaoHe Feng)
* [574833a4] configure the gettext of Cheetah template to support i18n (ShaoHe Feng)
* [cb38be80] add po files for i18n (ShaoHe Feng)
* [90ab55cd] get language that the client prefers (ShaoHe Feng)
* [5e04efc1] ui: Add button to delete a templete (ShaoHe Feng)
* [f3eb2ed8] tests: Fix expected result in test_vm_info (Adam Litke)
* [aa6101f9] tests: Add required logfile variable to server options (Adam Litke)
* [87964ad6] Fix websockify.py permission after installation (Royce Lv)
* [bd387ce7] browser report start VM error, fix it (ShaoHe Feng)
* [6ca43a6a] Set default log directory according to burnet root directory (Aline Manera)
* [12ea4a38] Create build process for Debian distributions (Aline Manera)
* [d2e55143] Create build process for SLES-based distributions (Aline Manera)
* [4d439352] Create build process for RHEL-based distributions (Aline Manera)
* [674e1295] Add sysvinit support (Aline Manera)
* [972c689e] Add upstart support (Aline Manera)
* [9e191e6b] Add systemd support (Aline Manera)
* [c969f03a] Create log file to burnet server (Aline Manera)
* [d357d37f] Replace argparse with optparse (Adam Litke)
* [b086e2bd] Import OrderedDict across multiple distros (Adam Litke)
* [3f729770] fix the prefix of burnet date path (ShaoHe Feng)
* [23815be9] add the static files into data_files list (ShaoHe Feng)
* [74d31b26] Display a VM's icon when it is powered off (Adam Litke)
* [fe48e634] resize no_VNC window dynamically (ShaoHe Feng)
* [3f1a9153] Use ps instead of pgrep to search for VNC qemu port (Aline Manera)
* [b9daead0] Update vm-toolbar on each vm selection (Aline Manera)
* [a0511aab] Make storage*s_create() return the name of the resource (Bing Bu Cao)
* [d7e8a539] Open VNC port for MockModel only once (Aline Manera)
* [77c5fca7] Fix mock backend vm delete error (Royce Lv)
* [7850b3ba] Hide dialog-delete-confirm div in Burnet main page (Aline Manera)
* [261cc99d] Enable folder navigation for Templates in the UI (Aline Manera)
* [2c774f9d] Add bread-crumbs style to burnet template (Aline Manera)
* [088ba067] Add folder field to Template Resource (Aline Manera)
* [0e8c94b5] screenshot: libvirt backend screenshot (Royce Lv)
* [0a607da3] screenshot: Nit fix of mockmodel (Royce Lv)
* [a27afd28] screenshot: minor change to common screenshot class (Royce Lv)
* [c08bab92] Add libvirt backend StoragePool(s) and StorageVolume(s) unitTest (Bing Bu Cao)
* [dc8952d5] Add libvirt backend StoragePool(s) and StorageVolume(s) support to Burnet (Bing Bu Cao)
* [ed4bda5e] Remove useless 'pass' in mockmodel.py added before (Bing Bu Cao)
* [0dc32934] ui: Add button to delete a VM (Adam Litke)
* [a1e335f1] ui: Create a new VM from a Template (Adam Litke)
* [1b147fcd] API: Make VM name optional (Adam Litke)
* [ded4a867] Provision storage when creating a VM from a Template (Adam Litke)
* [e421821d] objectstore: rollback transactions on error (Adam Litke)
* [830d4e4d] osinfo: Add osinfo for some popular operating systems (Adam Litke)
* [b7562ae6] Add 'vnc_port' key (Bing Bu Cao)
* [40f4b45a] Add screenshot directory to data/ directory (Royce Lv)
* [e402a07e] merge-fail: Add the file 'src/burnet/vnc.py' When taking the patch: [PATCH 0.. (Adam Litke)
* [4b9a62cb] Handle the 'Display' link (Aline Manera)
* [7ccfed2b] Restore 'Display' link state after performing power on/off (Aline Manera)
* [1688f155] Enable 'Display' link only if a running virtual machine is selected (Aline Manera)
* [9c3778ae] Deselect virtual machines after performing power on/off (Aline Manera)
* [5c9a736e] Implement real backend to start VNC session (Aline Manera)
* [0000eb6f] Handle 'connect' action to virtual machine in MockModel (Aline Manera)
* [19be36fc] Open vnc port in MockModel (Aline Manera)
* [ee197f69] Make static/ directory available in the web server (Aline Manera)
* [5ab68dee] Import noVNC files (Aline Manera)
* [65e23124] Import python WebSocket library as it is (Aline Manera)
* [30a45039] screenshot: Add time-based screenshot refresh testcase (Royce Lv)
* [e95a0074] screenshot: Change mock backend to support screenshot generation (Royce Lv)
* [03682f3d] screenshot: Add screenshot sub resource (Royce Lv)
* [aadc37cc] screenshot: Add common screenshot class (Royce Lv)
* [cbcf0026] screenshot: expose screenshot path (Royce Lv)
* [5ebada47] doc: Add screenshot resource definition (Royce Lv)
* [f30e4c2c] images: Import some icons for popular operating systems (Adam Litke)
* [7194621c] api: Return HTTP:404 when deleting a non-existent resource (Adam Litke)
* [cbb8396b] add a select to setup a language cookie (ShaoHe Feng)
* [24e76c3c] ui: Refresh UI at a 5 second interval (Adam Litke)
* [c70b03f9] Make sure the data/ directory exists in the source tree (Adam Litke)
* [19f8c026] Add a simple object persistence mechanism (Adam Litke)
* [d335aa17] Implement the real backend using libvirt (Adam Litke)
* [36ca77cd] Create VM from a template (Adam Litke)
* [6135a151] templates: Implement the mock model (Adam Litke)
* [ff6ae739] templates: Add osinfo dictionary (Adam Litke)
* [068ea78c] templates: Add Collection and Resource (Adam Litke)
* [90cf130c] doc: Define the template APIs (Adam Litke)
* [f93dde35] Add Rest API test cases (Bing Bu Cao)
* [44ff8295] Add the Collection and Resource (Bing Bu Cao)
* [94dc8943] Define the StoragePool(s) and StorageVolume(s) APIs (Bing Bu Cao)
* [0fd434f5] Enable power off virtual machines in UI (Aline Manera)
* [8f94ee5c] Enable power on virtual machines in UI (Aline Manera)
* [09a75ce0] Enable virtual machine selection in UI (Aline Manera)
* [50b4937a] Setting the code encoding of cheetah template as UTF-8 (ShaoHe Feng)
* [212add9f] Add screenshot field to VM Resource (Adam Litke)
* [2c48de8b] doc: Document the desired REST API (Adam Litke)
* [25d98875] UI: Load VM information from the actual REST API (Adam Litke)
* [b0e36f7b] Add basic VM operations (Adam Litke)
* [dbdb61aa] Remove GPL license (Anthony Liguori)
* [8dc800db] Add basic Virtual Machine support (agl@linux.vnet.ibm.com)
* [f5f8f85c] Add basic model/controller support (agl@linux.vnet.ibm.com)
* [a2d20854] template: Fix the separators for json rendering (agl@linux.vnet.ibm.com)
* [bee9ca07] tests: Correct test_server_start expected result (agl@linux.vnet.ibm.com)
* [2ed17454] template: Don't forget to import json (agl@linux.vnet.ibm.com)
* [50dbe224] ui: expose the js/css/images directory and the index template (Anthony Liguori)
* [ae3d4f78] ui: add javascript, css, and template for main page (Anthony Liguori)
* [7a563b45] ui: add external resources (jquery, etc.) (Anthony Liguori)
* [26107492] burnet: add template module (Anthony Liguori)
* [7d0c7d6c] burnet: add config file (Anthony Liguori)
* [980b749d] setup.py: use package instead of py_modules (Anthony Liguori)
* [4e982f9c] docs: add CONTRIBUTE.md to the top-level (Anthony Liguori)
* [d60a0853] tests: Introduce basic unit testing infrastructure (v2) (agl@linux.vnet.ibm.com)
* [5e9b7aac] Initial import of code base (Anthony Liguori)
================================================
FILE: INSTALL
================================================
Installation Instructions
*************************
Copyright (C) 1994-1996, 1999-2002, 2004-2011 Free Software Foundation,
Inc.
Copying and distribution of this file, with or without modification,
are permitted in any medium without royalty provided the copyright
notice and this notice are preserved. This file is offered as-is,
without warranty of any kind.
Basic Installation
==================
Briefly, the shell commands `./configure; make; make install' should
configure, build, and install this package. The following
more-detailed instructions are generic; see the `README' file for
instructions specific to this package. Some packages provide this
`INSTALL' file but do not implement all of the features documented
below. The lack of an optional feature in a given package is not
necessarily a bug. More recommendations for GNU packages can be found
in *note Makefile Conventions: (standards)Makefile Conventions.
The `configure' shell script attempts to guess correct values for
various system-dependent variables used during compilation. It uses
those values to create a `Makefile' in each directory of the package.
It may also create one or more `.h' files containing system-dependent
definitions. Finally, it creates a shell script `config.status' that
you can run in the future to recreate the current configuration, and a
file `config.log' containing compiler output (useful mainly for
debugging `configure').
It can also use an optional file (typically called `config.cache'
and enabled with `--cache-file=config.cache' or simply `-C') that saves
the results of its tests to speed up reconfiguring. Caching is
disabled by default to prevent problems with accidental use of stale
cache files.
If you need to do unusual things to compile the package, please try
to figure out how `configure' could check whether to do them, and mail
diffs or instructions to the address given in the `README' so they can
be considered for the next release. If you are using the cache, and at
some point `config.cache' contains results you don't want to keep, you
may remove or edit it.
The file `configure.ac' (or `configure.in') is used to create
`configure' by a program called `autoconf'. You need `configure.ac' if
you want to change it or regenerate `configure' using a newer version
of `autoconf'.
The simplest way to compile this package is:
1. `cd' to the directory containing the package's source code and type
`./configure' to configure the package for your system.
Running `configure' might take a while. While running, it prints
some messages telling which features it is checking for.
2. Type `make' to compile the package.
3. Optionally, type `make check' to run any self-tests that come with
the package, generally using the just-built uninstalled binaries.
4. Type `make install' to install the programs and any data files and
documentation. When installing into a prefix owned by root, it is
recommended that the package be configured and built as a regular
user, and only the `make install' phase executed with root
privileges.
5. Optionally, type `make installcheck' to repeat any self-tests, but
this time using the binaries in their final installed location.
This target does not install anything. Running this target as a
regular user, particularly if the prior `make install' required
root privileges, verifies that the installation completed
correctly.
6. You can remove the program binaries and object files from the
source code directory by typing `make clean'. To also remove the
files that `configure' created (so you can compile the package for
a different kind of computer), type `make distclean'. There is
also a `make maintainer-clean' target, but that is intended mainly
for the package's developers. If you use it, you may have to get
all sorts of other programs in order to regenerate files that came
with the distribution.
7. Often, you can also type `make uninstall' to remove the installed
files again. In practice, not all packages have tested that
uninstallation works correctly, even though it is required by the
GNU Coding Standards.
8. Some packages, particularly those that use Automake, provide `make
distcheck', which can by used by developers to test that all other
targets like `make install' and `make uninstall' work correctly.
This target is generally not run by end users.
Compilers and Options
=====================
Some systems require unusual options for compilation or linking that
the `configure' script does not know about. Run `./configure --help'
for details on some of the pertinent environment variables.
You can give `configure' initial values for configuration parameters
by setting variables in the command line or in the environment. Here
is an example:
./configure CC=c99 CFLAGS=-g LIBS=-lposix
*Note Defining Variables::, for more details.
Compiling For Multiple Architectures
====================================
You can compile the package for more than one kind of computer at the
same time, by placing the object files for each architecture in their
own directory. To do this, you can use GNU `make'. `cd' to the
directory where you want the object files and executables to go and run
the `configure' script. `configure' automatically checks for the
source code in the directory that `configure' is in and in `..'. This
is known as a "VPATH" build.
With a non-GNU `make', it is safer to compile the package for one
architecture at a time in the source code directory. After you have
installed the package for one architecture, use `make distclean' before
reconfiguring for another architecture.
On MacOS X 10.5 and later systems, you can create libraries and
executables that work on multiple system types--known as "fat" or
"universal" binaries--by specifying multiple `-arch' options to the
compiler but only a single `-arch' option to the preprocessor. Like
this:
./configure CC="gcc -arch i386 -arch x86_64 -arch ppc -arch ppc64" \
CXX="g++ -arch i386 -arch x86_64 -arch ppc -arch ppc64" \
CPP="gcc -E" CXXCPP="g++ -E"
This is not guaranteed to produce working output in all cases, you
may have to build one architecture at a time and combine the results
using the `lipo' tool if you have problems.
Installation Names
==================
By default, `make install' installs the package's commands under
`/usr/local/bin', include files under `/usr/local/include', etc. You
can specify an installation prefix other than `/usr/local' by giving
`configure' the option `--prefix=PREFIX', where PREFIX must be an
absolute file name.
You can specify separate installation prefixes for
architecture-specific files and architecture-independent files. If you
pass the option `--exec-prefix=PREFIX' to `configure', the package uses
PREFIX as the prefix for installing programs and libraries.
Documentation and other data files still use the regular prefix.
In addition, if you use an unusual directory layout you can give
options like `--bindir=DIR' to specify different values for particular
kinds of files. Run `configure --help' for a list of the directories
you can set and what kinds of files go in them. In general, the
default for these options is expressed in terms of `${prefix}', so that
specifying just `--prefix' will affect all of the other directory
specifications that were not explicitly provided.
The most portable way to affect installation locations is to pass the
correct locations to `configure'; however, many packages provide one or
both of the following shortcuts of passing variable assignments to the
`make install' command line to change installation locations without
having to reconfigure or recompile.
The first method involves providing an override variable for each
affected directory. For example, `make install
prefix=/alternate/directory' will choose an alternate location for all
directory configuration variables that were expressed in terms of
`${prefix}'. Any directories that were specified during `configure',
but not in terms of `${prefix}', must each be overridden at install
time for the entire installation to be relocated. The approach of
makefile variable overrides for each directory variable is required by
the GNU Coding Standards, and ideally causes no recompilation.
However, some platforms have known limitations with the semantics of
shared libraries that end up requiring recompilation when using this
method, particularly noticeable in packages that use GNU Libtool.
The second method involves providing the `DESTDIR' variable. For
example, `make install DESTDIR=/alternate/directory' will prepend
`/alternate/directory' before all installation names. The approach of
`DESTDIR' overrides is not required by the GNU Coding Standards, and
does not work on platforms that have drive letters. On the other hand,
it does better at avoiding recompilation issues, and works well even
when some directory options were not specified in terms of `${prefix}'
at `configure' time.
Optional Features
=================
If the package supports it, you can cause programs to be installed
with an extra prefix or suffix on their names by giving `configure' the
option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
Some packages pay attention to `--enable-FEATURE' options to
`configure', where FEATURE indicates an optional part of the package.
They may also pay attention to `--with-PACKAGE' options, where PACKAGE
is something like `gnu-as' or `x' (for the X Window System). The
`README' should mention any `--enable-' and `--with-' options that the
package recognizes.
For packages that use the X Window System, `configure' can usually
find the X include and library files automatically, but if it doesn't,
you can use the `configure' options `--x-includes=DIR' and
`--x-libraries=DIR' to specify their locations.
Some packages offer the ability to configure how verbose the
execution of `make' will be. For these packages, running `./configure
--enable-silent-rules' sets the default to minimal output, which can be
overridden with `make V=1'; while running `./configure
--disable-silent-rules' sets the default to verbose, which can be
overridden with `make V=0'.
Particular systems
==================
On HP-UX, the default C compiler is not ANSI C compatible. If GNU
CC is not installed, it is recommended to use the following options in
order to use an ANSI C compiler:
./configure CC="cc -Ae -D_XOPEN_SOURCE=500"
and if that doesn't work, install pre-built binaries of GCC for HP-UX.
HP-UX `make' updates targets which have the same time stamps as
their prerequisites, which makes it generally unusable when shipped
generated files such as `configure' are involved. Use GNU `make'
instead.
On OSF/1 a.k.a. Tru64, some versions of the default C compiler cannot
parse its `' header file. The option `-nodtk' can be used as
a workaround. If GNU CC is not installed, it is therefore recommended
to try
./configure CC="cc"
and if that doesn't work, try
./configure CC="cc -nodtk"
On Solaris, don't put `/usr/ucb' early in your `PATH'. This
directory contains several dysfunctional programs; working variants of
these programs are available in `/usr/bin'. So, if you need `/usr/ucb'
in your `PATH', put it _after_ `/usr/bin'.
On Haiku, software installed for all users goes in `/boot/common',
not `/usr/local'. It is recommended to use the following options:
./configure --prefix=/boot/common
Specifying the System Type
==========================
There may be some features `configure' cannot figure out
automatically, but needs to determine by the type of machine the package
will run on. Usually, assuming the package is built to be run on the
_same_ architectures, `configure' can figure that out, but if it prints
a message saying it cannot guess the machine type, give it the
`--build=TYPE' option. TYPE can either be a short name for the system
type, such as `sun4', or a canonical name which has the form:
CPU-COMPANY-SYSTEM
where SYSTEM can have one of these forms:
OS
KERNEL-OS
See the file `config.sub' for the possible values of each field. If
`config.sub' isn't included in this package, then this package doesn't
need to know the machine type.
If you are _building_ compiler tools for cross-compiling, you should
use the option `--target=TYPE' to select the type of system they will
produce code for.
If you want to _use_ a cross compiler, that generates code for a
platform different from the build platform, you should specify the
"host" platform (i.e., that on which the generated programs will
eventually be run) with `--host=TYPE'.
Sharing Defaults
================
If you want to set default values for `configure' scripts to share,
you can create a site shell script called `config.site' that gives
default values for variables like `CC', `cache_file', and `prefix'.
`configure' looks for `PREFIX/share/config.site' if it exists, then
`PREFIX/etc/config.site' if it exists. Or, you can set the
`CONFIG_SITE' environment variable to the location of the site script.
A warning: not all `configure' scripts look for a site script.
Defining Variables
==================
Variables not defined in a site shell script can be set in the
environment passed to `configure'. However, some packages may run
configure again during the build, and the customized values of these
variables may be lost. In order to avoid this problem, you should set
them in the `configure' command line, using `VAR=value'. For example:
./configure CC=/usr/local2/bin/gcc
causes the specified `gcc' to be used as the C compiler (unless it is
overridden in the site shell script).
Unfortunately, this technique does not work for `CONFIG_SHELL' due to
an Autoconf bug. Until the bug is fixed you can use this workaround:
CONFIG_SHELL=/bin/bash /bin/bash ./configure CONFIG_SHELL=/bin/bash
`configure' Invocation
======================
`configure' recognizes the following options to control how it
operates.
`--help'
`-h'
Print a summary of all of the options to `configure', and exit.
`--help=short'
`--help=recursive'
Print a summary of the options unique to this package's
`configure', and exit. The `short' variant lists options used
only in the top level, while the `recursive' variant lists options
also present in any nested packages.
`--version'
`-V'
Print the version of Autoconf used to generate the `configure'
script, and exit.
`--cache-file=FILE'
Enable the cache: use and save the results of the tests in FILE,
traditionally `config.cache'. FILE defaults to `/dev/null' to
disable caching.
`--config-cache'
`-C'
Alias for `--cache-file=config.cache'.
`--quiet'
`--silent'
`-q'
Do not print messages saying which checks are being made. To
suppress all normal output, redirect it to `/dev/null' (any error
messages will still be shown).
`--srcdir=DIR'
Look for the package's source code in directory DIR. Usually
`configure' can determine that directory automatically.
`--prefix=DIR'
Use DIR as the installation prefix. *note Installation Names::
for more details, including other options available for fine-tuning
the installation locations.
`--no-create'
`-n'
Run the configure checks, but stop before creating any output
files.
`configure' also accepts some other, not widely useful, options. Run
`configure --help' for more details.
================================================
FILE: Makefile.am
================================================
#
# Kimchi
#
# Copyright IBM Corp, 2013-2016
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
SUBDIRS = contrib control distros.d docs model po tests ui xmlutils
kimchi_PYTHON = $(filter-out config.py, $(wildcard *.py))
nodist_kimchi_PYTHON = config.py
if WITH_SPICE
WITH_SPICE=yes
else
WITH_SPICE=no
endif
if WITH_SPICE_WEB_CLIENT
WITH_SPICE_WEB_CLIENT=yes
else
WITH_SPICE_WEB_CLIENT=no
endif
wokdir = $(pythondir)/wok
kimchidir = $(pythondir)/wok/plugins/kimchi
wokconfdir = $(sysconfdir)/wok/plugins.d
dist_wokconf_DATA = kimchi.conf
confdir = $(sysconfdir)/kimchi
dist_conf_DATA = template.conf
AUTOMAKE_OPTIONS = foreign
ACLOCAL_AMFLAGS = --install -I m4
EXTRA_DIST = \
config.rpath \
API.json \
autogen.sh \
COPYING.ASL2 \
COPYING.LGPL \
CONTRIBUTE.md \
VERSION \
fedora-dev-deps.list \
fedora-runtime-deps.list \
opensuse-leap-dev-deps.list \
opensuse-leap-runtime-deps.list \
ubuntu-dev-deps.list \
ubuntu-runtime-deps.list \
requirements-FEDORA.txt \
requirements-OPENSUSE-LEAP.txt \
requirements-UBUNTU.txt \
build-aux/pkg-version \
config.py.in \
$(NULL)
PEP8_BLACKLIST = *config.py,*i18n.py,*tests/test_config.py
OS_DISTRO=$(shell sed -n -e '/^ID=/p' /etc/os-release | sed 's/ID=//g; s|["'\'']||g')
I18N_FILES = ./i18n.py \
$(NULL)
check-local:
PYTHONPATH=. contrib/check_i18n.py $(I18N_FILES)
@if [ -d '.git' ]; then \
find . -path './.git' -prune -o \
-name '*.py' -o -name '*.py.in' | \
xargs $(PYFLAKES) | \
while read LINE; do echo "$$LINE"; false; done \
else \
find . -name '*.py' -o -name '*.py.in' | \
xargs $(PYFLAKES) | \
while read LINE; do echo "$$LINE"; false; done \
fi
$(PEP8) --version
$(PEP8) --filename '*.py,*.py.in' --exclude="$(PEP8_BLACKLIST)" .
./check_ui_code_errors.sh
@if $(GIT) rev-parse &> /dev/null ; then \
echo "Whitespace verification ..."; \
git grep --cached -Il '' | grep -Ev '^ui/spice-html5/|^ui/spice-web-client/' | \
xargs egrep '.* +$$' \
&& echo "ERROR: Whitespaces found" || echo "Ok"; \
fi;
@if [ -f $(RPMLINT) ]; then \
./check_spec_errors.sh; \
fi;
# Link built mo files in the source tree to enable use of translations from
# within the source tree
all-local:
while read L && test -n "$$L"; do \
dir=mo/$$L/LC_MESSAGES ; \
$(MKDIR_P) $$dir ; \
ln -sf ../../../po/$$L.gmo $$dir/kimchi.mo ; \
done < po/LINGUAS
do_substitution = \
sed -e 's,[@]prefix[@],$(prefix),g' \
-e 's,[@]datadir[@],$(datadir),g' \
-e 's,[@]sysconfdir[@],$(sysconfdir),g' \
-e 's,[@]localstatedir[@],$(localstatedir),g' \
-e 's,[@]runstatedir[@],$(runstatedir),g' \
-e 's,[@]pkgdatadir[@],$(pkgdatadir),g' \
-e 's,[@]wokdir[@],$(wokdir),g' \
-e 's,[@]kimchidir[@],$(kimchidir),g' \
-e 's,[@]kimchiversion[@],$(PACKAGE_VERSION),g' \
-e 's,[@]kimchirelease[@],$(PACKAGE_RELEASE),g' \
-e 's,[@]withspice[@],$(WITH_SPICE),g' \
-e 's,[@]withspicewebclient[@],$(WITH_SPICE_WEB_CLIENT),g'
config.py: config.py.in Makefile
$(do_substitution) < $(srcdir)/config.py.in > config.py
#
# Packaging helpers
#
install-deb: install
cp -R $(top_srcdir)/contrib/DEBIAN $(DESTDIR)/
mkdir -p $(DESTDIR)/$(localstatedir)/lib/kimchi
mkdir -p $(DESTDIR)/$(localstatedir)/lib/kimchi/ws-tokens
mkdir -p $(DESTDIR)/$(localstatedir)/lib/kimchi/screenshots
mkdir -p $(DESTDIR)/$(localstatedir)/lib/kimchi/isos
mkdir -p $(DESTDIR)/$(localstatedir)/lib/kimchi/virtviewerfiles
deb: contrib/make-deb.sh
$(top_srcdir)/contrib/make-deb.sh
kimchi.spec: contrib/kimchi.spec.fedora contrib/kimchi.spec.suse
@if [[ $(OS_DISTRO) == "fedora" ]]; then \
ln -sf contrib/kimchi.spec.fedora $@ ; \
elif [[ $(OS_DISTRO) == "opensuse-leap" ]]; then \
ln -sf contrib/kimchi.spec.suse $@ ; \
else \
echo "Unable to select a spec file for RPM build" ; \
/bin/false ; \
fi
rpm: dist kimchi.spec
$(MKDIR_P) rpm/BUILD rpm/RPMS rpm/SOURCES rpm/SPECS rpm/SRPMS
cp $(top_srcdir)/kimchi.spec rpm/SPECS/kimchi.spec
cp $(DIST_ARCHIVES) rpm/SOURCES
rpmbuild -ba --define "_topdir `pwd`/rpm" rpm/SPECS/kimchi.spec
fedora-rpm: dist contrib/kimchi.spec.fedora
ln -sf contrib/kimchi.spec.fedora kimchi.spec
$(MAKE) rpm
suse-rpm: dist contrib/kimchi.spec.suse
ln -sf contrib/kimchi.spec.suse kimchi.spec
$(MAKE) rpm
ChangeLog:
@if $(GIT) rev-parse &> /dev/null ; then \
$(top_srcdir)/build-aux/genChangelog --release > $@; \
fi
install-data-local:
@if test -d "$(systemdsystemunitdir)" ; then \
mkdir -p $(DESTDIR)/etc/systemd/system/wokd.service.d; \
if test -f /etc/debian_version; then \
$(INSTALL_DATA) contrib/kimchid.service.debian $(DESTDIR)/etc/systemd/system/wokd.service.d/kimchi.conf; \
else \
$(INSTALL_DATA) contrib/kimchid.service.fedora $(DESTDIR)/etc/systemd/system/wokd.service.d/kimchi.conf; \
fi; \
fi; \
$(MKDIR_P) $(DESTDIR)/$(localstatedir)/lib/kimchi/
$(MKDIR_P) $(DESTDIR)$(kimchidir)
$(INSTALL_DATA) API.json $(DESTDIR)$(kimchidir)/API.json
mkdir -p $(DESTDIR)/$(localstatedir)/lib/kimchi/ws-tokens
mkdir -p $(DESTDIR)/$(localstatedir)/lib/kimchi/screenshots
mkdir -p $(DESTDIR)/$(localstatedir)/lib/kimchi/isos
mkdir -p $(DESTDIR)/$(localstatedir)/lib/kimchi/virtviewerfiles
uninstall-local:
@if test -f $(DESTDIR)/etc/systemd/system/wokd.service.d/kimchi.conf; then \
$(RM) $(DESTDIR)/etc/systemd/system/wokd.service.d/kimchi.conf; \
fi; \
$(RM) $(DESTDIR)$(kimchidir)/API.json
$(RM) -rf $(DESTDIR)/$(localstatedir)/lib/kimchi
VERSION:
@if $(GIT) rev-parse &> /dev/null ; then \
git describe --abbrev=0 --always > $@; \
fi
.PHONY: deb install-deb rpm fedora-rpm suse-rpm VERSION
clean-local:
rm -rf mo rpm
BUILT_SOURCES = config.py
CLEANFILES = config.py kimchi.spec `find "$(top_srcdir)" -type f -name "*.pyc" -print`
================================================
FILE: VERSION
================================================
3.0.0
================================================
FILE: __init__.py
================================================
#
# Project Kimchi
#
# Copyright IBM Corp, 2015-2016
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
from wok.plugins.kimchi.root import Kimchi
__all__ = [Kimchi]
================================================
FILE: autogen.sh
================================================
#!/bin/bash
#
# Project Kimchi
#
# Copyright IBM Corp, 2013-2016
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
aclocal
automake --add-missing
autoreconf
if [ ! -f "configure" ]; then
echo "Failed to generate configure script. Check to make sure autoconf, "
echo "automake, and other build dependencies are properly installed."
exit 1
fi
if [ "x$1" == "x--system" ]; then
shift
./configure --prefix=/usr --sysconfdir=/etc --localstatedir=/var $@
else
if [ $# -gt 0 ]; then
./configure $@
else
./configure --prefix=/usr/local
fi
fi
================================================
FILE: build-aux/config.rpath
================================================
#! /bin/sh
# Output a system dependent set of variables, describing how to set the
# run time search path of shared libraries in an executable.
#
# Copyright 1996-2010 Free Software Foundation, Inc.
# Taken from GNU libtool, 2001
# Originally by Gordon Matzigkeit , 1996
#
# This file is free software; the Free Software Foundation gives
# unlimited permission to copy and/or distribute it, with or without
# modifications, as long as this notice is preserved.
#
# The first argument passed to this file is the canonical host specification,
# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM
# or
# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM
# The environment variables CC, GCC, LDFLAGS, LD, with_gnu_ld
# should be set by the caller.
#
# The set of defined variables is at the end of this script.
# Known limitations:
# - On IRIX 6.5 with CC="cc", the run time search patch must not be longer
# than 256 bytes, otherwise the compiler driver will dump core. The only
# known workaround is to choose shorter directory names for the build
# directory and/or the installation directory.
# All known linkers require a `.a' archive for static linking (except MSVC,
# which needs '.lib').
libext=a
shrext=.so
host="$1"
host_cpu=`echo "$host" | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'`
host_vendor=`echo "$host" | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'`
host_os=`echo "$host" | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'`
# Code taken from libtool.m4's _LT_CC_BASENAME.
for cc_temp in $CC""; do
case $cc_temp in
compile | *[\\/]compile | ccache | *[\\/]ccache ) ;;
distcc | *[\\/]distcc | purify | *[\\/]purify ) ;;
\-*) ;;
*) break;;
esac
done
cc_basename=`echo "$cc_temp" | sed -e 's%^.*/%%'`
# Code taken from libtool.m4's _LT_COMPILER_PIC.
wl=
if test "$GCC" = yes; then
wl='-Wl,'
else
case "$host_os" in
aix*)
wl='-Wl,'
;;
darwin*)
case $cc_basename in
xlc*)
wl='-Wl,'
;;
esac
;;
mingw* | cygwin* | pw32* | os2* | cegcc*)
;;
hpux9* | hpux10* | hpux11*)
wl='-Wl,'
;;
irix5* | irix6* | nonstopux*)
wl='-Wl,'
;;
newsos6)
;;
linux* | k*bsd*-gnu)
case $cc_basename in
ecc*)
wl='-Wl,'
;;
icc* | ifort*)
wl='-Wl,'
;;
lf95*)
wl='-Wl,'
;;
pgcc | pgf77 | pgf90)
wl='-Wl,'
;;
ccc*)
wl='-Wl,'
;;
como)
wl='-lopt='
;;
*)
case `$CC -V 2>&1 | sed 5q` in
*Sun\ C*)
wl='-Wl,'
;;
esac
;;
esac
;;
osf3* | osf4* | osf5*)
wl='-Wl,'
;;
rdos*)
;;
solaris*)
wl='-Wl,'
;;
sunos4*)
wl='-Qoption ld '
;;
sysv4 | sysv4.2uw2* | sysv4.3*)
wl='-Wl,'
;;
sysv4*MP*)
;;
sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*)
wl='-Wl,'
;;
unicos*)
wl='-Wl,'
;;
uts4*)
;;
esac
fi
# Code taken from libtool.m4's _LT_LINKER_SHLIBS.
hardcode_libdir_flag_spec=
hardcode_libdir_separator=
hardcode_direct=no
hardcode_minus_L=no
case "$host_os" in
cygwin* | mingw* | pw32* | cegcc*)
# FIXME: the MSVC++ port hasn't been tested in a loooong time
# When not using gcc, we currently assume that we are using
# Microsoft Visual C++.
if test "$GCC" != yes; then
with_gnu_ld=no
fi
;;
interix*)
# we just hope/assume this is gcc and not c89 (= MSVC++)
with_gnu_ld=yes
;;
openbsd*)
with_gnu_ld=no
;;
esac
ld_shlibs=yes
if test "$with_gnu_ld" = yes; then
# Set some defaults for GNU ld with shared library support. These
# are reset later if shared libraries are not supported. Putting them
# here allows them to be overridden if necessary.
# Unlike libtool, we use -rpath here, not --rpath, since the documented
# option of GNU ld is called -rpath, not --rpath.
hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
case "$host_os" in
aix[3-9]*)
# On AIX/PPC, the GNU linker is very broken
if test "$host_cpu" != ia64; then
ld_shlibs=no
fi
;;
amigaos*)
hardcode_libdir_flag_spec='-L$libdir'
hardcode_minus_L=yes
# Samuel A. Falvo II reports
# that the semantics of dynamic libraries on AmigaOS, at least up
# to version 4, is to share data among multiple programs linked
# with the same dynamic library. Since this doesn't match the
# behavior of shared libraries on other platforms, we cannot use
# them.
ld_shlibs=no
;;
beos*)
if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
:
else
ld_shlibs=no
fi
;;
cygwin* | mingw* | pw32* | cegcc*)
# hardcode_libdir_flag_spec is actually meaningless, as there is
# no search path for DLLs.
hardcode_libdir_flag_spec='-L$libdir'
if $LD --help 2>&1 | grep 'auto-import' > /dev/null; then
:
else
ld_shlibs=no
fi
;;
interix[3-9]*)
hardcode_direct=no
hardcode_libdir_flag_spec='${wl}-rpath,$libdir'
;;
gnu* | linux* | k*bsd*-gnu)
if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
:
else
ld_shlibs=no
fi
;;
netbsd*)
;;
solaris*)
if $LD -v 2>&1 | grep 'BFD 2\.8' > /dev/null; then
ld_shlibs=no
elif $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
:
else
ld_shlibs=no
fi
;;
sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*)
case `$LD -v 2>&1` in
*\ [01].* | *\ 2.[0-9].* | *\ 2.1[0-5].*)
ld_shlibs=no
;;
*)
if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
hardcode_libdir_flag_spec='`test -z "$SCOABSPATH" && echo ${wl}-rpath,$libdir`'
else
ld_shlibs=no
fi
;;
esac
;;
sunos4*)
hardcode_direct=yes
;;
*)
if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
:
else
ld_shlibs=no
fi
;;
esac
if test "$ld_shlibs" = no; then
hardcode_libdir_flag_spec=
fi
else
case "$host_os" in
aix3*)
# Note: this linker hardcodes the directories in LIBPATH if there
# are no directories specified by -L.
hardcode_minus_L=yes
if test "$GCC" = yes; then
# Neither direct hardcoding nor static linking is supported with a
# broken collect2.
hardcode_direct=unsupported
fi
;;
aix[4-9]*)
if test "$host_cpu" = ia64; then
# On IA64, the linker does run time linking by default, so we don't
# have to do anything special.
aix_use_runtimelinking=no
else
aix_use_runtimelinking=no
# Test if we are trying to use run time linking or normal
# AIX style linking. If -brtl is somewhere in LDFLAGS, we
# need to do runtime linking.
case $host_os in aix4.[23]|aix4.[23].*|aix[5-9]*)
for ld_flag in $LDFLAGS; do
if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then
aix_use_runtimelinking=yes
break
fi
done
;;
esac
fi
hardcode_direct=yes
hardcode_libdir_separator=':'
if test "$GCC" = yes; then
case $host_os in aix4.[012]|aix4.[012].*)
collect2name=`${CC} -print-prog-name=collect2`
if test -f "$collect2name" && \
strings "$collect2name" | grep resolve_lib_name >/dev/null
then
# We have reworked collect2
:
else
# We have old collect2
hardcode_direct=unsupported
hardcode_minus_L=yes
hardcode_libdir_flag_spec='-L$libdir'
hardcode_libdir_separator=
fi
;;
esac
fi
# Begin _LT_AC_SYS_LIBPATH_AIX.
echo 'int main () { return 0; }' > conftest.c
${CC} ${LDFLAGS} conftest.c -o conftest
aix_libpath=`dump -H conftest 2>/dev/null | sed -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; }
}'`
if test -z "$aix_libpath"; then
aix_libpath=`dump -HX64 conftest 2>/dev/null | sed -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; }
}'`
fi
if test -z "$aix_libpath"; then
aix_libpath="/usr/lib:/lib"
fi
rm -f conftest.c conftest
# End _LT_AC_SYS_LIBPATH_AIX.
if test "$aix_use_runtimelinking" = yes; then
hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath"
else
if test "$host_cpu" = ia64; then
hardcode_libdir_flag_spec='${wl}-R $libdir:/usr/lib:/lib'
else
hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath"
fi
fi
;;
amigaos*)
hardcode_libdir_flag_spec='-L$libdir'
hardcode_minus_L=yes
# see comment about different semantics on the GNU ld section
ld_shlibs=no
;;
bsdi[45]*)
;;
cygwin* | mingw* | pw32* | cegcc*)
# When not using gcc, we currently assume that we are using
# Microsoft Visual C++.
# hardcode_libdir_flag_spec is actually meaningless, as there is
# no search path for DLLs.
hardcode_libdir_flag_spec=' '
libext=lib
;;
darwin* | rhapsody*)
hardcode_direct=no
if test "$GCC" = yes ; then
:
else
case $cc_basename in
xlc*)
;;
*)
ld_shlibs=no
;;
esac
fi
;;
dgux*)
hardcode_libdir_flag_spec='-L$libdir'
;;
freebsd1*)
ld_shlibs=no
;;
freebsd2.2*)
hardcode_libdir_flag_spec='-R$libdir'
hardcode_direct=yes
;;
freebsd2*)
hardcode_direct=yes
hardcode_minus_L=yes
;;
freebsd* | dragonfly*)
hardcode_libdir_flag_spec='-R$libdir'
hardcode_direct=yes
;;
hpux9*)
hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir'
hardcode_libdir_separator=:
hardcode_direct=yes
# hardcode_minus_L: Not really in the search PATH,
# but as the default location of the library.
hardcode_minus_L=yes
;;
hpux10*)
if test "$with_gnu_ld" = no; then
hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir'
hardcode_libdir_separator=:
hardcode_direct=yes
# hardcode_minus_L: Not really in the search PATH,
# but as the default location of the library.
hardcode_minus_L=yes
fi
;;
hpux11*)
if test "$with_gnu_ld" = no; then
hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir'
hardcode_libdir_separator=:
case $host_cpu in
hppa*64*|ia64*)
hardcode_direct=no
;;
*)
hardcode_direct=yes
# hardcode_minus_L: Not really in the search PATH,
# but as the default location of the library.
hardcode_minus_L=yes
;;
esac
fi
;;
irix5* | irix6* | nonstopux*)
hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
hardcode_libdir_separator=:
;;
netbsd*)
hardcode_libdir_flag_spec='-R$libdir'
hardcode_direct=yes
;;
newsos6)
hardcode_direct=yes
hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
hardcode_libdir_separator=:
;;
openbsd*)
if test -f /usr/libexec/ld.so; then
hardcode_direct=yes
if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
hardcode_libdir_flag_spec='${wl}-rpath,$libdir'
else
case "$host_os" in
openbsd[01].* | openbsd2.[0-7] | openbsd2.[0-7].*)
hardcode_libdir_flag_spec='-R$libdir'
;;
*)
hardcode_libdir_flag_spec='${wl}-rpath,$libdir'
;;
esac
fi
else
ld_shlibs=no
fi
;;
os2*)
hardcode_libdir_flag_spec='-L$libdir'
hardcode_minus_L=yes
;;
osf3*)
hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
hardcode_libdir_separator=:
;;
osf4* | osf5*)
if test "$GCC" = yes; then
hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
else
# Both cc and cxx compiler support -rpath directly
hardcode_libdir_flag_spec='-rpath $libdir'
fi
hardcode_libdir_separator=:
;;
solaris*)
hardcode_libdir_flag_spec='-R$libdir'
;;
sunos4*)
hardcode_libdir_flag_spec='-L$libdir'
hardcode_direct=yes
hardcode_minus_L=yes
;;
sysv4)
case $host_vendor in
sni)
hardcode_direct=yes # is this really true???
;;
siemens)
hardcode_direct=no
;;
motorola)
hardcode_direct=no #Motorola manual says yes, but my tests say they lie
;;
esac
;;
sysv4.3*)
;;
sysv4*MP*)
if test -d /usr/nec; then
ld_shlibs=yes
fi
;;
sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*)
;;
sysv5* | sco3.2v5* | sco5v6*)
hardcode_libdir_flag_spec='`test -z "$SCOABSPATH" && echo ${wl}-R,$libdir`'
hardcode_libdir_separator=':'
;;
uts4*)
hardcode_libdir_flag_spec='-L$libdir'
;;
*)
ld_shlibs=no
;;
esac
fi
# Check dynamic linker characteristics
# Code taken from libtool.m4's _LT_SYS_DYNAMIC_LINKER.
# Unlike libtool.m4, here we don't care about _all_ names of the library, but
# only about the one the linker finds when passed -lNAME. This is the last
# element of library_names_spec in libtool.m4, or possibly two of them if the
# linker has special search rules.
library_names_spec= # the last element of library_names_spec in libtool.m4
libname_spec='lib$name'
case "$host_os" in
aix3*)
library_names_spec='$libname.a'
;;
aix[4-9]*)
library_names_spec='$libname$shrext'
;;
amigaos*)
library_names_spec='$libname.a'
;;
beos*)
library_names_spec='$libname$shrext'
;;
bsdi[45]*)
library_names_spec='$libname$shrext'
;;
cygwin* | mingw* | pw32* | cegcc*)
shrext=.dll
library_names_spec='$libname.dll.a $libname.lib'
;;
darwin* | rhapsody*)
shrext=.dylib
library_names_spec='$libname$shrext'
;;
dgux*)
library_names_spec='$libname$shrext'
;;
freebsd1*)
;;
freebsd* | dragonfly*)
case "$host_os" in
freebsd[123]*)
library_names_spec='$libname$shrext$versuffix' ;;
*)
library_names_spec='$libname$shrext' ;;
esac
;;
gnu*)
library_names_spec='$libname$shrext'
;;
hpux9* | hpux10* | hpux11*)
case $host_cpu in
ia64*)
shrext=.so
;;
hppa*64*)
shrext=.sl
;;
*)
shrext=.sl
;;
esac
library_names_spec='$libname$shrext'
;;
interix[3-9]*)
library_names_spec='$libname$shrext'
;;
irix5* | irix6* | nonstopux*)
library_names_spec='$libname$shrext'
case "$host_os" in
irix5* | nonstopux*)
libsuff= shlibsuff=
;;
*)
case $LD in
*-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") libsuff= shlibsuff= ;;
*-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") libsuff=32 shlibsuff=N32 ;;
*-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") libsuff=64 shlibsuff=64 ;;
*) libsuff= shlibsuff= ;;
esac
;;
esac
;;
linux*oldld* | linux*aout* | linux*coff*)
;;
linux* | k*bsd*-gnu)
library_names_spec='$libname$shrext'
;;
knetbsd*-gnu)
library_names_spec='$libname$shrext'
;;
netbsd*)
library_names_spec='$libname$shrext'
;;
newsos6)
library_names_spec='$libname$shrext'
;;
nto-qnx*)
library_names_spec='$libname$shrext'
;;
openbsd*)
library_names_spec='$libname$shrext$versuffix'
;;
os2*)
libname_spec='$name'
shrext=.dll
library_names_spec='$libname.a'
;;
osf3* | osf4* | osf5*)
library_names_spec='$libname$shrext'
;;
rdos*)
;;
solaris*)
library_names_spec='$libname$shrext'
;;
sunos4*)
library_names_spec='$libname$shrext$versuffix'
;;
sysv4 | sysv4.3*)
library_names_spec='$libname$shrext'
;;
sysv4*MP*)
library_names_spec='$libname$shrext'
;;
sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
library_names_spec='$libname$shrext'
;;
uts4*)
library_names_spec='$libname$shrext'
;;
esac
sed_quote_subst='s/\(["`$\\]\)/\\\1/g'
escaped_wl=`echo "X$wl" | sed -e 's/^X//' -e "$sed_quote_subst"`
shlibext=`echo "$shrext" | sed -e 's,^\.,,'`
escaped_libname_spec=`echo "X$libname_spec" | sed -e 's/^X//' -e "$sed_quote_subst"`
escaped_library_names_spec=`echo "X$library_names_spec" | sed -e 's/^X//' -e "$sed_quote_subst"`
escaped_hardcode_libdir_flag_spec=`echo "X$hardcode_libdir_flag_spec" | sed -e 's/^X//' -e "$sed_quote_subst"`
LC_ALL=C sed -e 's/^\([a-zA-Z0-9_]*\)=/acl_cv_\1=/' < 4.9.0 (upstream clean)
# - 4.9.0-1 => 4.9.0 (downstream clean)
# - 4.9.0-2-g34e62f => 4.9.0 (upstream dirty)
# - 4.9.0-1-2-g34e62f => 4.9.0 (downstream dirty)
AWK_VERSION='
BEGIN { FS="-" }
/^[0-9]/ {
print $1
}'
# tags and output releases:
# - 4.9.0 => 0 (upstream clean)
# - 4.9.0-1 => 1 (downstream clean)
# - 4.9.0-2-g34e62f1 => 2.git34e62f1 (upstream dirty)
# - 4.9.0-1-2-g34e62f1 => 1.2.git34e62f1 (downstream dirty)
AWK_RELEASE='
BEGIN { FS="-"; OFS="." }
/^[0-9]/ {
if (NF == 1) print 0
else if (NF == 2) print $2
else if (NF == 3) print $2, "git" substr($3, 2)
else if (NF == 4) print $2, $3, "git" substr($4, 2)
}'
if [ ! -e .git ]; then
PKG_VERSION=`cat VERSION`
else
PKG_VERSION=`git describe --tags --match "[0-9]*" || cat VERSION`
fi
if test "x$1" = "x--full"; then
echo $PKG_VERSION | tr -d '[:space:]'
elif test "x$1" = "x--version"; then
echo $PKG_VERSION | awk "$AWK_VERSION" | tr -cd '[:alnum:].'
elif test "x$1" = "x--release"; then
echo $PKG_VERSION | awk "$AWK_RELEASE" | tr -cd '[:alnum:].'
else
echo "usage: $0 [--full|--version|--release]"
exit 1
fi
================================================
FILE: build_packages.py
================================================
import argparse
import yaml
import shutil
import sys
import subprocess
from subprocess import check_call, check_output, CalledProcessError
from wok.plugins.kimchi.config import get_kimchi_version
from wok.config import get_version
REPOS_LIST = ('production', 'staging')
DISTROS_LIST = ('centos/8', 'fedora/31', 'ubuntu/19.10', 'debian/10', 'opensuse/15.1', 'all')
JFROG_BASE = 'https://kimchi.jfrog.io/kimchi/'
HOMEWOK = '/tmp/wok/'
HOMEKIMCHI = HOMEWOK + 'src/wok/plugins/kimchi/'
WOK = [
'git clone https://github.com/kimchi-project/wok.git ' + HOMEWOK
]
KIMCHI = [
'mkdir -p ' + HOMEKIMCHI,
'git clone https://github.com/kimchi-project/kimchi.git ' + HOMEKIMCHI ,
]
PACKAGES = {}
PACKAGES['wok'] = WOK
PACKAGES['kimchi'] = KIMCHI
BUILD = [['./autogen.sh', '--system'], ['make'], ['make','install']]
COMMANDS_OS = {
'debian' : {
'install' : 'apt install -y',
'update' : 'apt update -y',
'make' : ['make', 'deb'],
'pk' : '.deb',
'pip' : 'sudo -H pip3 install -r ' + HOMEKIMCHI + 'requirements-UBUNTU.txt',
},
'fedora' : {
'install' : 'dnf install -y',
'update' : 'dnf update -y',
'make' : ['make', 'rpm'],
'pk' : '.rpm',
'pip' : 'sudo -H pip3 install -r ' + HOMEKIMCHI + 'requirements-FEDORA.txt',
},
'opensuse/LEAP' : {
'install' : 'zypper install -y',
'update' : 'zypper update -y',
'make' : ['make', 'rpm'],
'pk' : '.rpm',
'pip' : 'sudo -H pip3 install -r ' + HOMEKIMCHI + 'requirements-OPENSUSE-LEAP.txt',
},
}
def usage():
'''
# Handle parameters
@param repo string repository
@param distro string distro
@param user string JFROG user
@param password string Token JFROG
'''
parser = argparse.ArgumentParser(
description='python install.py -r production -d rhel/7 -u username -p password ',
)
parser.add_argument("-r", "--repo", choices=REPOS_LIST, required=True)
parser.add_argument("-d", "--distro", choices=DISTROS_LIST, default="all")
parser.add_argument("-u", "--user", help="Account name at %s. This account needs to be granted to write in \
the repository." % (JFROG_BASE), metavar=(""),required=True)
parser.add_argument("-p", "--password", help="Token at %s. This token needs to be granted to write in."
% (JFROG_BASE),metavar=(""),required=True)
args = parser.parse_args()
repo = args.repo
if args.distro == "all":
distros = DISTROS_LIST
distros.remove("all")
else:
distros = [args.distro]
return repo, distros, args.user, args.password
def run_cmd(command):
'''
Run the given command using check_call and verify its return code.
@param str command command to be executed
'''
try:
check_call(command.split())
except CalledProcessError as e:
print('An exception h:as occurred: {0}'.format(e))
sys.exit(1)
def execute_cmd(list, step):
'''
Execute the given commands using run_cmd function
@param list list commands to be executed
@param step str name of the comand to be executed
'''
print('Step: %s' % (step))
for item in list:
run_cmd(item)
def run_build(list, dir):
'''
Execute the given commands in other directory
@param list list commands to be executed
@param dir str directory path
'''
try:
build = subprocess.Popen(list, cwd=dir)
build.wait()
except CalledProcessError as e:
print('An exception has occurred: {0}'.format(e))
sys.exit(1)
def curl_cmd(repo, distro_name, distro, package_name, user, password, path, component):
'''
Move package to JFROG repository
@param str repo repo
@param str distro_name distro name
@param str distro distro name and version
@param str package_name package name
@param str user JFROG user
@param str password JFROG password
@param str path path to package
@param str component component name
'''
if distro_name == 'debian' or distro_bame == 'ubuntu':
cmd = 'curl --silent -u%s:%s -XPUT \
https://kimchi.jfrog.io/kimchi/%s/%s;deb.distribution=%s;deb.component=%s;deb.architecture=noarch -T %s' \
% (user, password, distro, package_name, distro, component, path)
elif distro_name == 'staging':
cmd = 'curl --silent -u%s:%s -XPUT https://kimchi.jfrog.io/kimchi/staging/%s/ -T %s' \
% (user, password, distro, path)
else:
cmd = 'curl --silent -u%s:%s -XPUT https://kimchi.jfrog.io/kimchi/%s/ -T %s' % (user, password, distro, path)
execute_cmd([cmd], 'Moving package to JFROG')
def install_dependencies(distro, pm):
'''
Install package dependencies
@param str distro distro name
@param str pm package manager
'''
packages = []
for file in (HOMEWOK + 'dependencies.yaml', HOMEKIMCHI + 'dependencies.yaml' ):
with open(file, 'r') as dep_file:
packages_list = yaml.load(dep_file, Loader=yaml.Loader)
if 'kimchi' in str(dep_file):
new_distro = 'ubuntu'
else:
new_distro = distro
packages.append(' '.join([str(elem) for elem in packages_list['development-deps']['common']]))
packages.append(' '.join([str(elem) for elem in packages_list['development-deps'][new_distro]]))
packages.append(' '.join([str(elem) for elem in packages_list['runtime-deps']['common']]))
packages.append(' '.join([str(elem) for elem in packages_list['runtime-deps'][new_distro]]))
for package in packages:
execute_cmd([COMMANDS_OS[pm]['install'] + ' ' + package], 'Installing necessary packages')
execute_cmd(['sudo -H pip3 install -r ' + HOMEWOK+ 'requirements-dev.txt'], 'Installing requirements')
execute_cmd(['sudo -H pip3 install -r ' + HOMEKIMCHI+ 'requirements-dev.txt'], 'Installing requirements')
def main():
repo, distros, user, password = usage()
kimchi_version = get_kimchi_version()
wok_version = get_version()
for distro in distros:
distro_name = distro.split("/")
if distro_name[0] == 'ubuntu':
pm = 'debian'
else:
pm = distro_name[0]
try:
shutil.rmtree(HOMEWOK)
except:
pass
execute_cmd([COMMANDS_OS[pm]['update']], 'Updating system')
execute_cmd(PACKAGES['wok'], 'Cloning Wok')
execute_cmd(PACKAGES['kimchi'], 'Cloning Kimchi')
install_dependencies(distro_name[0], pm)
execute_cmd([COMMANDS_OS[pm]['pip']],'Installing Pip packages')
for item in BUILD:
run_build(item, HOMEWOK)
run_build(item, HOMEKIMCHI)
run_build(COMMANDS_OS[pm]['make'], HOMEWOK)
run_build(COMMANDS_OS[pm]['make'], HOMEKIMCHI)
wok_package = 'wok-' + wok_version + '.' + distro_name[0] + '.noarch' + COMMANDS_OS[pm]['pk']
kimchi_package = 'kimchi-' + kimchi_version + '.noarch' + COMMANDS_OS[pm]['pk']
curl_cmd(repo, distro_name[0], distro, wok_package, user, password, HOMEWOK + wok_package, 'wok')
curl_cmd(repo, distro_name[0], distro, kimchi_package, user, password, HOMEKIMCHI + kimchi_package, 'kimchi')
print("All Good, check JFROG")
if __name__ == "__main__":
main()
================================================
FILE: check_spec_errors.sh
================================================
#!/bin/bash
#
# Project Kimchi
#
# Copyright IBM Corp, 2016
#
# Code derived from Wok Project
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
echo "Checking spec guidelines"
# create links
cp contrib/kimchi.spec.fedora contrib/kimchi_fedora.spec
cp contrib/kimchi.spec.suse contrib/kimchi_suse.spec
# run checking
rpmlint contrib/kimchi_fedora.spec
rpmlint contrib/kimchi_suse.spec
# remove links
rm contrib/kimchi_fedora.spec
rm contrib/kimchi_suse.spec
================================================
FILE: check_ui_code_errors.sh
================================================
#!/bin/bash
#
# Project Kimchi
#
# Copyright IBM Corp, 2015-2016
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
errors="$(cat ui/pages/i18n.json.tmpl | grep -o 'KCH[0-9A-Z]*'| sort)"
uiErrors="$(grep -ERo 'KCH[0-9A-Z]+' ui/js/ | cut -d: -f2 | sort| uniq)"
# all errors on i18n are present in js/html files: success
if [ "$errors" == "$uiErrors" ]; then
echo "UI errors codes are correct"
else
echo "Error while checking UI errors codes."
diff <(echo "$errors" ) <(echo "$uiErrors")
fi
================================================
FILE: config.py.in
================================================
#
# Project Kimchi
#
# Copyright IBM Corp, 2015-2017
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
#
import libvirt
import os
import platform
import threading
from wok.config import PluginConfig, PluginPaths
from wok.utils import load_plugin_conf
from wok.xmlutils.utils import xpath_get_text
kimchiLock = threading.Lock()
__with_spice__ = "@withspice@"
__with_spice_web_client__ = "@withspicewebclient@"
__version__ = "@kimchiversion@"
__release__ = "@kimchirelease@"
# Storage pool constant for read-only pool types
READONLY_POOL_TYPE = ['iscsi', 'scsi', 'mpath']
def get_libvirt_path():
run_state_dir = "@runstatedir@" if "@runstatedir@" else "@localstatedir@/run"
return os.path.join(run_state_dir, 'libvirt')
def get_kimchi_version():
return "-".join([__version__, __release__])
def with_spice_web_client():
return __with_spice_web_client__ == 'yes'
def get_distros_store():
return os.path.join(kimchiPaths.sysconf_dir, 'distros.d')
def get_debugreports_path():
return os.path.join(PluginPaths('kimchi').state_dir, 'debugreports')
def get_object_store():
return os.path.join(PluginPaths('kimchi').state_dir, 'objectstore')
def get_screenshot_path():
return os.path.join(PluginPaths('kimchi').state_dir, 'screenshots')
def get_virtviewerfiles_path():
return os.path.join(PluginPaths('kimchi').state_dir, 'virtviewerfiles')
def get_config():
return load_plugin_conf('kimchi')
config = get_config()
def find_qemu_binary(find_emulator=False):
try:
connect = libvirt.open(None)
except Exception as e:
raise Exception("Unable to get qemu binary location: %s" % e)
try:
xml = connect.getCapabilities()
# On Little Endian system, the qemu binary is
# qemu-system-ppc64, not qemu-system-ppc64le as expected
arch = platform.machine()
if arch == "ppc64le":
arch = "ppc64"
if find_emulator:
expr = "/capabilities/guest/arch[@name='%s']\
/emulator" % arch
else:
expr = "/capabilities/guest/arch[@name='%s']\
/domain[@type='kvm']/emulator" % arch
res = xpath_get_text(xml, expr)
location = res[0]
except Exception as e:
raise Exception("Unable to get qemu binary location: %s" % e)
finally:
connect.close()
return location
class KimchiPaths(PluginPaths):
def __init__(self):
super(KimchiPaths, self).__init__('kimchi')
if __with_spice_web_client__ == 'yes':
self.spice_file = os.path.join(self.ui_dir,
'spice-web-client/index.html')
self.spice_dir = os.path.join(self.ui_dir, 'spice-web-client')
else:
self.spice_file = os.path.join(self.ui_dir,
'spice-html5/pages/spice_auto.html')
if __with_spice__ == 'yes':
self.spice_dir = os.path.join(self.ui_dir, 'spice-html5')
elif os.path.exists('@datadir@/spice-html5'):
self.spice_dir = '@datadir@/spice-html5'
else:
self.spice_dir = '/usr/share/spice-html5'
if os.path.exists('@datadir@/novnc'):
self.novnc_dir = '@datadir@/novnc'
else:
self.novnc_dir = '/usr/share/novnc'
if self.installed:
self.spice_css_file = os.path.join(self.spice_dir, 'spice.css')
# Expose system configuration directory
self.sysconf_dir = os.path.join('@sysconfdir@', 'kimchi')
else:
self.spice_css_file = os.path.join(self.spice_dir, 'css/spice.css')
self.sysconf_dir = self.add_prefix(self.plugin_dir)
self.serial_dir = os.path.join(self.ui_dir, 'serial')
kimchiPaths = KimchiPaths()
class KimchiConfig(PluginConfig):
def __init__(self):
super(KimchiConfig, self).__init__('kimchi')
static_config = {
'/novnc': {'type': 'dir',
'path': kimchiPaths.novnc_dir},
'/spice-html5': {'type': 'dir',
'path': kimchiPaths.spice_dir},
'/spice_auto.html': {'type': 'file',
'path': kimchiPaths.spice_file},
'/spice-html5/spice.css': {'type': 'file',
'path': kimchiPaths.spice_css_file},
'/spice-web-client': {'type': 'dir',
'path': kimchiPaths.spice_dir},
'/serial': {'type': 'dir',
'path': kimchiPaths.serial_dir}}
custom_config = {
'/help': {'tools.nocache.on': True,
'tools.staticdir.dir':
os.path.join(kimchiPaths.ui_dir, 'pages/help'),
'tools.staticdir.on': True},
'/data/screenshots': {'tools.nocache.on': False,
'tools.staticdir.dir':
get_screenshot_path(),
'tools.staticdir.on': True},
'/data/virtviewerfiles': {'tools.nocache.on': False,
'tools.staticdir.dir':
get_virtviewerfiles_path(),
'tools.staticdir.on': True}}
for uri, data in static_config.items():
custom_config[uri] = {'tools.nocache.on': True,
'tools.wokauth.on': True}
path = data['path']
if data['type'] == 'dir':
custom_config[uri].update({'tools.staticdir.on': True,
'tools.staticdir.dir': path})
elif data['type'] == 'file':
custom_config[uri].update({'tools.staticfile.on': True,
'tools.staticfile.filename': path})
self.update(custom_config)
================================================
FILE: config.rpath
================================================
#! /bin/sh
# Output a system dependent set of variables, describing how to set the
# run time search path of shared libraries in an executable.
#
# Copyright 1996-2010 Free Software Foundation, Inc.
# Taken from GNU libtool, 2001
# Originally by Gordon Matzigkeit , 1996
#
# This file is free software; the Free Software Foundation gives
# unlimited permission to copy and/or distribute it, with or without
# modifications, as long as this notice is preserved.
#
# The first argument passed to this file is the canonical host specification,
# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM
# or
# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM
# The environment variables CC, GCC, LDFLAGS, LD, with_gnu_ld
# should be set by the caller.
#
# The set of defined variables is at the end of this script.
# Known limitations:
# - On IRIX 6.5 with CC="cc", the run time search patch must not be longer
# than 256 bytes, otherwise the compiler driver will dump core. The only
# known workaround is to choose shorter directory names for the build
# directory and/or the installation directory.
# All known linkers require a `.a' archive for static linking (except MSVC,
# which needs '.lib').
libext=a
shrext=.so
host="$1"
host_cpu=`echo "$host" | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'`
host_vendor=`echo "$host" | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'`
host_os=`echo "$host" | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'`
# Code taken from libtool.m4's _LT_CC_BASENAME.
for cc_temp in $CC""; do
case $cc_temp in
compile | *[\\/]compile | ccache | *[\\/]ccache ) ;;
distcc | *[\\/]distcc | purify | *[\\/]purify ) ;;
\-*) ;;
*) break;;
esac
done
cc_basename=`echo "$cc_temp" | sed -e 's%^.*/%%'`
# Code taken from libtool.m4's _LT_COMPILER_PIC.
wl=
if test "$GCC" = yes; then
wl='-Wl,'
else
case "$host_os" in
aix*)
wl='-Wl,'
;;
darwin*)
case $cc_basename in
xlc*)
wl='-Wl,'
;;
esac
;;
mingw* | cygwin* | pw32* | os2* | cegcc*)
;;
hpux9* | hpux10* | hpux11*)
wl='-Wl,'
;;
irix5* | irix6* | nonstopux*)
wl='-Wl,'
;;
newsos6)
;;
linux* | k*bsd*-gnu)
case $cc_basename in
ecc*)
wl='-Wl,'
;;
icc* | ifort*)
wl='-Wl,'
;;
lf95*)
wl='-Wl,'
;;
pgcc | pgf77 | pgf90)
wl='-Wl,'
;;
ccc*)
wl='-Wl,'
;;
como)
wl='-lopt='
;;
*)
case `$CC -V 2>&1 | sed 5q` in
*Sun\ C*)
wl='-Wl,'
;;
esac
;;
esac
;;
osf3* | osf4* | osf5*)
wl='-Wl,'
;;
rdos*)
;;
solaris*)
wl='-Wl,'
;;
sunos4*)
wl='-Qoption ld '
;;
sysv4 | sysv4.2uw2* | sysv4.3*)
wl='-Wl,'
;;
sysv4*MP*)
;;
sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*)
wl='-Wl,'
;;
unicos*)
wl='-Wl,'
;;
uts4*)
;;
esac
fi
# Code taken from libtool.m4's _LT_LINKER_SHLIBS.
hardcode_libdir_flag_spec=
hardcode_libdir_separator=
hardcode_direct=no
hardcode_minus_L=no
case "$host_os" in
cygwin* | mingw* | pw32* | cegcc*)
# FIXME: the MSVC++ port hasn't been tested in a loooong time
# When not using gcc, we currently assume that we are using
# Microsoft Visual C++.
if test "$GCC" != yes; then
with_gnu_ld=no
fi
;;
interix*)
# we just hope/assume this is gcc and not c89 (= MSVC++)
with_gnu_ld=yes
;;
openbsd*)
with_gnu_ld=no
;;
esac
ld_shlibs=yes
if test "$with_gnu_ld" = yes; then
# Set some defaults for GNU ld with shared library support. These
# are reset later if shared libraries are not supported. Putting them
# here allows them to be overridden if necessary.
# Unlike libtool, we use -rpath here, not --rpath, since the documented
# option of GNU ld is called -rpath, not --rpath.
hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
case "$host_os" in
aix[3-9]*)
# On AIX/PPC, the GNU linker is very broken
if test "$host_cpu" != ia64; then
ld_shlibs=no
fi
;;
amigaos*)
hardcode_libdir_flag_spec='-L$libdir'
hardcode_minus_L=yes
# Samuel A. Falvo II reports
# that the semantics of dynamic libraries on AmigaOS, at least up
# to version 4, is to share data among multiple programs linked
# with the same dynamic library. Since this doesn't match the
# behavior of shared libraries on other platforms, we cannot use
# them.
ld_shlibs=no
;;
beos*)
if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
:
else
ld_shlibs=no
fi
;;
cygwin* | mingw* | pw32* | cegcc*)
# hardcode_libdir_flag_spec is actually meaningless, as there is
# no search path for DLLs.
hardcode_libdir_flag_spec='-L$libdir'
if $LD --help 2>&1 | grep 'auto-import' > /dev/null; then
:
else
ld_shlibs=no
fi
;;
interix[3-9]*)
hardcode_direct=no
hardcode_libdir_flag_spec='${wl}-rpath,$libdir'
;;
gnu* | linux* | k*bsd*-gnu)
if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
:
else
ld_shlibs=no
fi
;;
netbsd*)
;;
solaris*)
if $LD -v 2>&1 | grep 'BFD 2\.8' > /dev/null; then
ld_shlibs=no
elif $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
:
else
ld_shlibs=no
fi
;;
sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*)
case `$LD -v 2>&1` in
*\ [01].* | *\ 2.[0-9].* | *\ 2.1[0-5].*)
ld_shlibs=no
;;
*)
if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
hardcode_libdir_flag_spec='`test -z "$SCOABSPATH" && echo ${wl}-rpath,$libdir`'
else
ld_shlibs=no
fi
;;
esac
;;
sunos4*)
hardcode_direct=yes
;;
*)
if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
:
else
ld_shlibs=no
fi
;;
esac
if test "$ld_shlibs" = no; then
hardcode_libdir_flag_spec=
fi
else
case "$host_os" in
aix3*)
# Note: this linker hardcodes the directories in LIBPATH if there
# are no directories specified by -L.
hardcode_minus_L=yes
if test "$GCC" = yes; then
# Neither direct hardcoding nor static linking is supported with a
# broken collect2.
hardcode_direct=unsupported
fi
;;
aix[4-9]*)
if test "$host_cpu" = ia64; then
# On IA64, the linker does run time linking by default, so we don't
# have to do anything special.
aix_use_runtimelinking=no
else
aix_use_runtimelinking=no
# Test if we are trying to use run time linking or normal
# AIX style linking. If -brtl is somewhere in LDFLAGS, we
# need to do runtime linking.
case $host_os in aix4.[23]|aix4.[23].*|aix[5-9]*)
for ld_flag in $LDFLAGS; do
if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then
aix_use_runtimelinking=yes
break
fi
done
;;
esac
fi
hardcode_direct=yes
hardcode_libdir_separator=':'
if test "$GCC" = yes; then
case $host_os in aix4.[012]|aix4.[012].*)
collect2name=`${CC} -print-prog-name=collect2`
if test -f "$collect2name" && \
strings "$collect2name" | grep resolve_lib_name >/dev/null
then
# We have reworked collect2
:
else
# We have old collect2
hardcode_direct=unsupported
hardcode_minus_L=yes
hardcode_libdir_flag_spec='-L$libdir'
hardcode_libdir_separator=
fi
;;
esac
fi
# Begin _LT_AC_SYS_LIBPATH_AIX.
echo 'int main () { return 0; }' > conftest.c
${CC} ${LDFLAGS} conftest.c -o conftest
aix_libpath=`dump -H conftest 2>/dev/null | sed -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; }
}'`
if test -z "$aix_libpath"; then
aix_libpath=`dump -HX64 conftest 2>/dev/null | sed -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; }
}'`
fi
if test -z "$aix_libpath"; then
aix_libpath="/usr/lib:/lib"
fi
rm -f conftest.c conftest
# End _LT_AC_SYS_LIBPATH_AIX.
if test "$aix_use_runtimelinking" = yes; then
hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath"
else
if test "$host_cpu" = ia64; then
hardcode_libdir_flag_spec='${wl}-R $libdir:/usr/lib:/lib'
else
hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath"
fi
fi
;;
amigaos*)
hardcode_libdir_flag_spec='-L$libdir'
hardcode_minus_L=yes
# see comment about different semantics on the GNU ld section
ld_shlibs=no
;;
bsdi[45]*)
;;
cygwin* | mingw* | pw32* | cegcc*)
# When not using gcc, we currently assume that we are using
# Microsoft Visual C++.
# hardcode_libdir_flag_spec is actually meaningless, as there is
# no search path for DLLs.
hardcode_libdir_flag_spec=' '
libext=lib
;;
darwin* | rhapsody*)
hardcode_direct=no
if test "$GCC" = yes ; then
:
else
case $cc_basename in
xlc*)
;;
*)
ld_shlibs=no
;;
esac
fi
;;
dgux*)
hardcode_libdir_flag_spec='-L$libdir'
;;
freebsd1*)
ld_shlibs=no
;;
freebsd2.2*)
hardcode_libdir_flag_spec='-R$libdir'
hardcode_direct=yes
;;
freebsd2*)
hardcode_direct=yes
hardcode_minus_L=yes
;;
freebsd* | dragonfly*)
hardcode_libdir_flag_spec='-R$libdir'
hardcode_direct=yes
;;
hpux9*)
hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir'
hardcode_libdir_separator=:
hardcode_direct=yes
# hardcode_minus_L: Not really in the search PATH,
# but as the default location of the library.
hardcode_minus_L=yes
;;
hpux10*)
if test "$with_gnu_ld" = no; then
hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir'
hardcode_libdir_separator=:
hardcode_direct=yes
# hardcode_minus_L: Not really in the search PATH,
# but as the default location of the library.
hardcode_minus_L=yes
fi
;;
hpux11*)
if test "$with_gnu_ld" = no; then
hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir'
hardcode_libdir_separator=:
case $host_cpu in
hppa*64*|ia64*)
hardcode_direct=no
;;
*)
hardcode_direct=yes
# hardcode_minus_L: Not really in the search PATH,
# but as the default location of the library.
hardcode_minus_L=yes
;;
esac
fi
;;
irix5* | irix6* | nonstopux*)
hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
hardcode_libdir_separator=:
;;
netbsd*)
hardcode_libdir_flag_spec='-R$libdir'
hardcode_direct=yes
;;
newsos6)
hardcode_direct=yes
hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
hardcode_libdir_separator=:
;;
openbsd*)
if test -f /usr/libexec/ld.so; then
hardcode_direct=yes
if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
hardcode_libdir_flag_spec='${wl}-rpath,$libdir'
else
case "$host_os" in
openbsd[01].* | openbsd2.[0-7] | openbsd2.[0-7].*)
hardcode_libdir_flag_spec='-R$libdir'
;;
*)
hardcode_libdir_flag_spec='${wl}-rpath,$libdir'
;;
esac
fi
else
ld_shlibs=no
fi
;;
os2*)
hardcode_libdir_flag_spec='-L$libdir'
hardcode_minus_L=yes
;;
osf3*)
hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
hardcode_libdir_separator=:
;;
osf4* | osf5*)
if test "$GCC" = yes; then
hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
else
# Both cc and cxx compiler support -rpath directly
hardcode_libdir_flag_spec='-rpath $libdir'
fi
hardcode_libdir_separator=:
;;
solaris*)
hardcode_libdir_flag_spec='-R$libdir'
;;
sunos4*)
hardcode_libdir_flag_spec='-L$libdir'
hardcode_direct=yes
hardcode_minus_L=yes
;;
sysv4)
case $host_vendor in
sni)
hardcode_direct=yes # is this really true???
;;
siemens)
hardcode_direct=no
;;
motorola)
hardcode_direct=no #Motorola manual says yes, but my tests say they lie
;;
esac
;;
sysv4.3*)
;;
sysv4*MP*)
if test -d /usr/nec; then
ld_shlibs=yes
fi
;;
sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*)
;;
sysv5* | sco3.2v5* | sco5v6*)
hardcode_libdir_flag_spec='`test -z "$SCOABSPATH" && echo ${wl}-R,$libdir`'
hardcode_libdir_separator=':'
;;
uts4*)
hardcode_libdir_flag_spec='-L$libdir'
;;
*)
ld_shlibs=no
;;
esac
fi
# Check dynamic linker characteristics
# Code taken from libtool.m4's _LT_SYS_DYNAMIC_LINKER.
# Unlike libtool.m4, here we don't care about _all_ names of the library, but
# only about the one the linker finds when passed -lNAME. This is the last
# element of library_names_spec in libtool.m4, or possibly two of them if the
# linker has special search rules.
library_names_spec= # the last element of library_names_spec in libtool.m4
libname_spec='lib$name'
case "$host_os" in
aix3*)
library_names_spec='$libname.a'
;;
aix[4-9]*)
library_names_spec='$libname$shrext'
;;
amigaos*)
library_names_spec='$libname.a'
;;
beos*)
library_names_spec='$libname$shrext'
;;
bsdi[45]*)
library_names_spec='$libname$shrext'
;;
cygwin* | mingw* | pw32* | cegcc*)
shrext=.dll
library_names_spec='$libname.dll.a $libname.lib'
;;
darwin* | rhapsody*)
shrext=.dylib
library_names_spec='$libname$shrext'
;;
dgux*)
library_names_spec='$libname$shrext'
;;
freebsd1*)
;;
freebsd* | dragonfly*)
case "$host_os" in
freebsd[123]*)
library_names_spec='$libname$shrext$versuffix' ;;
*)
library_names_spec='$libname$shrext' ;;
esac
;;
gnu*)
library_names_spec='$libname$shrext'
;;
hpux9* | hpux10* | hpux11*)
case $host_cpu in
ia64*)
shrext=.so
;;
hppa*64*)
shrext=.sl
;;
*)
shrext=.sl
;;
esac
library_names_spec='$libname$shrext'
;;
interix[3-9]*)
library_names_spec='$libname$shrext'
;;
irix5* | irix6* | nonstopux*)
library_names_spec='$libname$shrext'
case "$host_os" in
irix5* | nonstopux*)
libsuff= shlibsuff=
;;
*)
case $LD in
*-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") libsuff= shlibsuff= ;;
*-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") libsuff=32 shlibsuff=N32 ;;
*-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") libsuff=64 shlibsuff=64 ;;
*) libsuff= shlibsuff= ;;
esac
;;
esac
;;
linux*oldld* | linux*aout* | linux*coff*)
;;
linux* | k*bsd*-gnu)
library_names_spec='$libname$shrext'
;;
knetbsd*-gnu)
library_names_spec='$libname$shrext'
;;
netbsd*)
library_names_spec='$libname$shrext'
;;
newsos6)
library_names_spec='$libname$shrext'
;;
nto-qnx*)
library_names_spec='$libname$shrext'
;;
openbsd*)
library_names_spec='$libname$shrext$versuffix'
;;
os2*)
libname_spec='$name'
shrext=.dll
library_names_spec='$libname.a'
;;
osf3* | osf4* | osf5*)
library_names_spec='$libname$shrext'
;;
rdos*)
;;
solaris*)
library_names_spec='$libname$shrext'
;;
sunos4*)
library_names_spec='$libname$shrext$versuffix'
;;
sysv4 | sysv4.3*)
library_names_spec='$libname$shrext'
;;
sysv4*MP*)
library_names_spec='$libname$shrext'
;;
sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
library_names_spec='$libname$shrext'
;;
uts4*)
library_names_spec='$libname$shrext'
;;
esac
sed_quote_subst='s/\(["`$\\]\)/\\\1/g'
escaped_wl=`echo "X$wl" | sed -e 's/^X//' -e "$sed_quote_subst"`
shlibext=`echo "$shrext" | sed -e 's,^\.,,'`
escaped_libname_spec=`echo "X$libname_spec" | sed -e 's/^X//' -e "$sed_quote_subst"`
escaped_library_names_spec=`echo "X$library_names_spec" | sed -e 's/^X//' -e "$sed_quote_subst"`
escaped_hardcode_libdir_flag_spec=`echo "X$hardcode_libdir_flag_spec" | sed -e 's/^X//' -e "$sed_quote_subst"`
LC_ALL=C sed -e 's/^\([a-zA-Z0-9_]*\)=/acl_cv_\1=/' <@]
)],
,
[enable_sample="no"]
)
if test "${enable_sample}" = "yes"; then
AC_SUBST([ENABLE_SAMPLE], [True])
else
AC_SUBST([ENABLE_SAMPLE], [False])
fi
# check for systemd
PKG_PROG_PKG_CONFIG
AC_ARG_WITH([systemdsystemunitdir],
AS_HELP_STRING([--with-systemdsystemunitdir=DIR], [Directory for systemd service files]),
[], [with_systemdsystemunitdir=$($PKG_CONFIG --variable=systemdsystemunitdir systemd)])
if test "x$with_systemdsystemunitdir" != xno; then
AC_SUBST([systemdsystemunitdir], [$with_systemdsystemunitdir])
fi
AC_ARG_WITH(
[spice-html5],
[AS_HELP_STRING([--with-spice-html5],
[Build Kimchi with spice-html5 @<:@default=no@:>@])],
,
[with_spice_html5="no"]
)
AM_CONDITIONAL([WITH_SPICE], [test "x$with_spice_html5" = xyes])
AC_ARG_WITH(
[spice-web-client],
[AS_HELP_STRING([--with-spice-web-client],
[Build Kimchi with spice-web-client @<:@default=no@:>@])],
,
[with_spice_web_client="no"]
)
AM_CONDITIONAL([WITH_SPICE_WEB_CLIENT], [test "x$with_spice_web_client" = xyes])
AC_CONFIG_FILES([
po/Makefile.in
po/gen-pot
Makefile
docs/Makefile
distros.d/Makefile
control/Makefile
control/vm/Makefile
model/Makefile
ui/Makefile
ui/config/Makefile
ui/css/Makefile
ui/images/Makefile
ui/js/Makefile
ui/spice-html5/Makefile
ui/spice-html5/css/Makefile
ui/spice-html5/pages/Makefile
ui/spice-html5/thirdparty/Makefile
ui/spice-web-client/Makefile
ui/spice-web-client/application/Makefile
ui/spice-web-client/keymaps/Makefile
ui/spice-web-client/lib/Makefile
ui/spice-web-client/lib/images/Makefile
ui/spice-web-client/network/Makefile
ui/spice-web-client/process/Makefile
ui/spice-web-client/resources/Makefile
ui/spice-web-client/spiceobjects/Makefile
ui/spice-web-client/spiceobjects/generated/Makefile
ui/spice-web-client/spiceproxy/Makefile
ui/spice-web-client/swcanvas/Makefile
ui/pages/Makefile
ui/pages/help/Makefile
ui/pages/tabs/Makefile
ui/pages/help/en_US/Makefile
ui/pages/help/de_DE/Makefile
ui/pages/help/es_ES/Makefile
ui/pages/help/fr_FR/Makefile
ui/pages/help/it_IT/Makefile
ui/pages/help/ja_JP/Makefile
ui/pages/help/ko_KR/Makefile
ui/pages/help/pt_BR/Makefile
ui/pages/help/ru_RU/Makefile
ui/pages/help/zh_CN/Makefile
ui/pages/help/zh_TW/Makefile
ui/serial/Makefile
ui/serial/libs/Makefile
ui/serial/html/Makefile
contrib/Makefile
contrib/DEBIAN/Makefile
contrib/DEBIAN/control
contrib/kimchi.spec.fedora
contrib/kimchi.spec.suse
tests/Makefile
xmlutils/Makefile
],[
chmod +x po/gen-pot
])
AC_OUTPUT
================================================
FILE: contrib/DEBIAN/Makefile.am
================================================
# Copyright IBM Corp, 2013-2016
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
CLEANFILES = control
================================================
FILE: contrib/DEBIAN/control.in
================================================
Package: @PACKAGE_NAME@
Version: @PACKAGE_VERSION@
Section: base
Priority: optional
Architecture: all
@UBUNTU_DEPS@
Maintainer: Aline Manera
Description: Kimchi web application
================================================
FILE: contrib/Makefile.am
================================================
#
# Kimchi
#
# Copyright IBM Corp, 2013-2015
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
SUBDIRS = DEBIAN
EXTRA_DIST = \
check_i18n.py \
kimchid.service.fedora \
kimchi.spec.fedora.in \
make-deb.sh.in \
$(NULL)
make-deb.sh: make-deb.sh.in $(top_builddir)/config.status
$(AM_V_GEN)sed \
-e 's|[@]PACKAGE_VERSION[@]|$(PACKAGE_VERSION)|g' \
-e 's|[@]PACKAGE_RELEASE[@]|$(PACKAGE_RELEASE)|g' \
< $< > $@-t && \
chmod a+x $@-t && \
mv $@-t $@
BUILT_SOURCES = make-deb.sh
CLEANFILES = kimchi.spec.fedora kimchi.spec.suse kimchi.spec make-deb.sh
================================================
FILE: contrib/check_i18n.py
================================================
#!/usr/bin/env python3
#
# Project Kimchi
#
# Copyright IBM Corp, 2014-2016
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
import importlib
import os
import re
import sys
# Match all conversion specifier with mapping key
PATTERN = re.compile(
r"""%\([^)]+\) # Mapping key
[#0\-+]? # Conversion flags (optional)
(\d+|\*)? # Minimum field width (optional)
(\.(\d+|\*))? # Precision (optional)
[lLh]? # Length modifier (optional)
[cdeEfFgGioursxX%] # Conversion type""",
re.VERBOSE,
)
BAD_PATTERN = re.compile(r'%\([^)]*?\)')
def load_i18n_module(i18nfile):
mname = i18nfile.replace('/', '.').rstrip('.py').lstrip('src.')
return importlib.import_module(mname)
def check_string_formatting(messages):
for k, v in messages.items():
if BAD_PATTERN.findall(PATTERN.sub(' ', v)):
print('bad i18n string formatting:')
print(f' {k}: {v}')
exit(1)
def check_obsolete_messages(path, messages):
def find_message_key(path, k):
for root, dirs, files in os.walk(path):
for f in files:
fname = os.path.join(root, f)
if (
not fname.endswith('i18n.py')
and fname.endswith('.py')
or fname.endswith('.json')
):
with open(fname) as f:
string = ''.join(f.readlines())
if k in string:
return True
return False
for k in messages.keys():
if not find_message_key(path, k):
print(f' {k} is obsolete, it is no longer in use')
exit(1)
def main():
print('Checking for invalid i18n string...')
for f in sys.argv[1:]:
messages = load_i18n_module(f).messages
check_string_formatting(messages)
check_obsolete_messages(os.path.dirname(f), messages)
print('Checking for invalid i18n string successfully')
if __name__ == '__main__':
main()
================================================
FILE: contrib/kimchi.spec.fedora.in
================================================
Name: kimchi
Version: @PACKAGE_VERSION@
Release: @PACKAGE_RELEASE@%{?dist}
Summary: Kimchi server application
BuildRoot: %{_topdir}/BUILD/%{name}-%{version}-%{release}
BuildArch: noarch
Group: System Environment/Base
License: LGPL/ASL2
Source0: %{name}-%{version}.tar.gz
@FEDORA_DEPS@
%if 0%{?fedora} >= 15 || 0%{?rhel} >= 7
%global with_systemd 1
%endif
%description
Web application to manage KVM/Qemu virtual machines
%prep
%setup -q
%build
%if 0%{?rhel} >= 6 || 0%{?fedora} >= 19
%configure
%else
%configure --with-spice-html5
%endif
make
%install
rm -rf %{buildroot}
make DESTDIR=%{buildroot} install
%clean
rm -rf $RPM_BUILD_ROOT
%files
%attr(-,root,root)
%{python3_sitelib}/wok/plugins/kimchi/
%{_datadir}/kimchi/doc/
%{_prefix}/share/locale/*/LC_MESSAGES/kimchi.mo
%{_datadir}/wok/plugins/kimchi/
%{_sysconfdir}/wok/plugins.d/kimchi.conf
%{_sysconfdir}/kimchi/
%{_sharedstatedir}/kimchi/
%{_sysconfdir}/systemd/system/wokd.service.d/kimchi.conf
%changelog
* Thu Jun 18 2015 Lucio Correia 2.0
- Run kimchi as a plugin
* Thu Feb 26 2015 Frédéric Bonnard 1.4.0
- Add man page for kimchid
* Tue Feb 11 2014 Crístian Viana 1.1.0
- Add help pages and XSLT dependency
* Tue Jul 16 2013 Adam Litke 0.1.0-1
- Adapted for autotools build
* Thu Apr 04 2013 Aline Manera 0.0-1
- First build
================================================
FILE: contrib/kimchi.spec.suse.in
================================================
Name: kimchi
Version: @PACKAGE_VERSION@
Release: @PACKAGE_RELEASE@%{?dist}
Summary: Kimchi server application
BuildRoot: %{_topdir}/BUILD/%{name}-%{version}-%{release}
BuildArch: noarch
Group: System Environment/Base
License: LGPL/ASL2
Source0: %{name}-%{version}.tar.gz
@SUSE_DEPS@
%if 0%{?suse_version} > 1140
%global with_systemd 1
%endif
%description
Web application to manage KVM/Qemu virtual machines
%prep
%setup -q
%build
%configure --with-spice-html5
make
%install
rm -rf %{buildroot}
make DESTDIR=%{buildroot} install
%clean
rm -rf $RPM_BUILD_ROOT
%files
%attr(-,root,root)
%{python3_sitelib}/wok/plugins/kimchi/
%{_datadir}/kimchi/doc/
%{_prefix}/share/locale/*/LC_MESSAGES/kimchi.mo
%{_datadir}/wok/plugins/kimchi/
%{_sysconfdir}/wok/plugins.d/kimchi.conf
%{_sysconfdir}/kimchi/
%{_var}/lib/kimchi/
%{_sysconfdir}/systemd/system/wokd.service.d/kimchi.conf
%changelog
* Thu Jun 18 2015 Lucio Correia 2.0
- Run kimchi as a plugin
* Thu Feb 26 2015 Frédéric Bonnard 1.4.0
- Add man page for kimchid
* Tue Feb 11 2014 Crístian Viana 1.1.0
- Add help pages and XSLT dependency
* Thu Jul 18 2013 Adam Litke 0.1.0-1
- Adapted for autotools build
- Split Suse and Fedora spec files
* Thu Apr 04 2013 Aline Manera 0.0-1
- First build
================================================
FILE: contrib/kimchid.service.debian
================================================
[Unit]
Requires=wokd.service
Wants=libvirtd.service
After=libvirtd.service wokd.service
[Service]
Nice=0
PrivateTmp=no
================================================
FILE: contrib/kimchid.service.fedora
================================================
[Unit]
Requires=wokd.service
Wants=libvirtd.service
After=libvirtd.service wokd.service
[Service]
Nice=0
PrivateTmp=no
================================================
FILE: contrib/make-deb.sh.in
================================================
#!/bin/bash
#
# Project Kimchi
#
# Copyright IBM Corp, 2013-2016
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
VERSION="@PACKAGE_VERSION@"
RELEASE="@PACKAGE_RELEASE@"
if [ ! -f configure ]; then
echo "Please run this script from the top of the package tree"
exit 1
fi
TMPDIR=`mktemp -d`
make DESTDIR=$TMPDIR install-deb
dpkg-deb -b $TMPDIR kimchi-${VERSION}-${RELEASE}.noarch.deb
rm -rf $TMPDIR
================================================
FILE: control/Makefile.am
================================================
#
# Kimchi
#
# Copyright IBM Corp, 2015-2016
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
SUBDIRS = vm
control_PYTHON = *.py
controldir = $(pythondir)/wok/plugins/kimchi/control
install-data-local:
$(MKDIR_P) $(DESTDIR)$(controldir)
================================================
FILE: control/__init__.py
================================================
#
# Project Kimchi
#
# Copyright IBM Corp, 2015-2016
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
import os
from wok.control.utils import load_url_sub_node
sub_nodes = load_url_sub_node(os.path.dirname(__file__), __name__)
================================================
FILE: control/cpuinfo.py
================================================
#
# Project Kimchi
#
# Copyright IBM Corp, 2015-2017
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
from wok.control.base import Resource
class CPUInfo(Resource):
def __init__(self, model):
super(CPUInfo, self).__init__(model)
self.admin_methods = ['GET']
self.uri_fmt = '/host/cpuinfo'
@property
def data(self):
return {'threading_enabled': self.info['guest_threads_enabled'],
'sockets': self.info['sockets'],
'cores': self.info['cores_available'],
'threads_per_core': self.info['threads_per_core']
}
================================================
FILE: control/groups.py
================================================
#
# Project Kimchi
#
# Copyright IBM Corp, 2015-2017
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
from wok.control.base import SimpleCollection
from wok.control.utils import UrlSubNode
@UrlSubNode('groups', True)
class Groups(SimpleCollection):
def __init__(self, model):
super(Groups, self).__init__(model)
================================================
FILE: control/host.py
================================================
#
# Project Kimchi
#
# Copyright IBM Corp, 2015-2017
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
import platform
from wok.control.base import Collection
from wok.control.base import Resource
from wok.control.base import SimpleCollection
from wok.control.utils import UrlSubNode
from wok.exception import NotFoundError
from wok.plugins.kimchi.control.cpuinfo import CPUInfo
from wok.plugins.kimchi.utils import is_s390x
ARCH = platform.machine()
@UrlSubNode('host', True)
class Host(Resource):
def __init__(self, model, id=None):
super(Host, self).__init__(model, id)
self.admin_methods = ['GET', 'POST']
self.uri_fmt = '/host/%s'
self.devices = Devices(self.model)
self.cpuinfo = CPUInfo(self.model)
self.partitions = Partitions(self.model)
self.vgs = VolumeGroups(self.model)
@property
def data(self):
return {'arch': ARCH}
class VolumeGroups(Collection):
def __init__(self, model):
super(VolumeGroups, self).__init__(model)
self.uri_fmt = '/host/vgs'
self.admin_methods = ['GET']
self.resource = VolumeGroup
class VolumeGroup(Resource):
def __init__(self, model, id=None):
super(VolumeGroup, self).__init__(model, id)
self.uri_fmt = '/host/vgs/%s'
self.admin_methods = ['GET']
@property
def data(self):
return self.info
class VMHolders(SimpleCollection):
def __init__(self, model, device_id):
super(VMHolders, self).__init__(model)
self.model_args = (device_id,)
class Devices(Collection):
def __init__(self, model):
super(Devices, self).__init__(model)
self.resource = Device
class Device(Resource):
def __init__(self, model, id):
super(Device, self).__init__(model, id)
self.vm_holders = VMHolders(self.model, id)
@property
def data(self):
return self.info
class Partitions(Collection):
def __init__(self, model):
super(Partitions, self).__init__(model)
self.admin_methods = ['GET']
self.resource = Partition
# Defining get_resources in order to return list of partitions in UI
# sorted by their path
def _get_resources(self, flag_filter):
res_list = super(Partitions, self)._get_resources(flag_filter)
res_list = list(filter(lambda x: x.info.get('available', False), res_list))
if is_s390x():
# On s390x arch filter out the DASD block devices which
# don't have any partition(s). This is necessary because
# DASD devices without any partitions are not valid
# block device(s) for operations like pvcreate on s390x
res_list = list(
filter(
lambda x: (
x.info['name'].startswith(
'dasd') and x.info['type'] == 'part'
) or
(not x.info['name'].startswith('dasd')),
res_list,
)
)
res_list.sort(key=lambda x: x.info['path'])
return res_list
class Partition(Resource):
def __init__(self, model, id):
self.admin_methods = ['GET']
super(Partition, self).__init__(model, id)
@property
def data(self):
if not self.info.get('available', False):
raise NotFoundError('KCHPART0001E', {'name': self.info['name']})
return self.info
================================================
FILE: control/interfaces.py
================================================
#
# Project Kimchi
#
# Copyright IBM Corp, 2015-2017
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
from wok.control.base import Collection
from wok.control.base import Resource
from wok.control.utils import UrlSubNode
@UrlSubNode('interfaces', True)
class Interfaces(Collection):
def __init__(self, model):
super(Interfaces, self).__init__(model)
self.admin_methods = ['GET']
self.resource = Interface
class Interface(Resource):
def __init__(self, model, ident):
super(Interface, self).__init__(model, ident)
self.admin_methods = ['GET']
self.uri_fmt = '/interfaces/%s'
@property
def data(self):
return self.info
================================================
FILE: control/networks.py
================================================
#
# Project Kimchi
#
# Copyright IBM Corp, 2015-2017
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
from wok.control.base import Collection
from wok.control.base import Resource
from wok.control.utils import UrlSubNode
NETWORKS_REQUESTS = {
'POST': {'default': 'KCHNET0001L'},
}
NETWORK_REQUESTS = {
'DELETE': {'default': 'KCHNET0002L'},
'PUT': {'default': 'KCHNET0003L'},
'POST': {
'activate': 'KCHNET0004L',
'deactivate': 'KCHNET0005L',
},
}
@UrlSubNode('networks', True)
class Networks(Collection):
def __init__(self, model):
super(Networks, self).__init__(model)
self.admin_methods = ['POST']
self.resource = Network
# set user log messages and make sure all parameters are present
self.log_map = NETWORKS_REQUESTS
self.log_args.update({'connection': '', 'name': ''})
class Network(Resource):
def __init__(self, model, ident):
super(Network, self).__init__(model, ident)
self.admin_methods = ['PUT', 'POST', 'DELETE']
self.uri_fmt = '/networks/%s'
self.activate = self.generate_action_handler('activate')
self.deactivate = self.generate_action_handler('deactivate',
destructive=True)
self.log_map = NETWORK_REQUESTS
@property
def data(self):
return {'name': self.ident,
'vms': self.info['vms'],
'in_use': self.info['in_use'],
'autostart': self.info['autostart'],
'connection': self.info['connection'],
'interfaces': self.info['interfaces'],
'subnet': self.info['subnet'],
'dhcp': self.info['dhcp'],
'state': self.info['state'],
'persistent': self.info['persistent']}
================================================
FILE: control/ovsbridges.py
================================================
#
# Project Kimchi
#
# Copyright IBM Corp, 2016
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
from wok.control.base import SimpleCollection
from wok.control.utils import UrlSubNode
@UrlSubNode('ovsbridges', True)
class OVSBridges(SimpleCollection):
def __init__(self, model):
super(OVSBridges, self).__init__(model)
================================================
FILE: control/storagepools.py
================================================
#
# Project Kimchi
#
# Copyright IBM Corp, 2015-2017
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
import cherrypy
from wok.control.base import Collection
from wok.control.base import Resource
from wok.control.utils import get_class_name
from wok.control.utils import model_fn
from wok.control.utils import UrlSubNode
from wok.control.utils import validate_params
from wok.plugins.kimchi.control.storagevolumes import IsoVolumes
from wok.plugins.kimchi.control.storagevolumes import StorageVolumes
from wok.plugins.kimchi.model.storagepools import ISO_POOL_NAME
STORAGEPOOLS_REQUESTS = {'POST': {'default': 'KCHPOOL0001L'}}
STORAGEPOOL_REQUESTS = {
'DELETE': {'default': 'KCHPOOL0002L'},
'PUT': {'default': 'KCHPOOL0003L'},
'POST': {'activate': 'KCHPOOL0004L', 'deactivate': 'KCHPOOL0005L'},
}
@UrlSubNode('storagepools', True)
class StoragePools(Collection):
def __init__(self, model):
super(StoragePools, self).__init__(model)
self.admin_methods = ['POST']
self.resource = StoragePool
isos = IsoPool(model)
setattr(self, ISO_POOL_NAME, isos)
# set user log messages and make sure all parameters are present
self.log_map = STORAGEPOOLS_REQUESTS
self.log_args.update({'name': '', 'type': ''})
def create(self, params, *args):
try:
create = getattr(self.model, model_fn(self, 'create'))
except AttributeError:
error = 'Create is not allowed for %s' % get_class_name(self)
raise cherrypy.HTTPError(405, error)
validate_params(params, self, 'create')
args = self.model_args + [params]
name = create(*args)
args = self.resource_args + [name]
res = self.resource(self.model, *args)
res.lookup()
resp = res.get()
if 'task_id' in res.data:
cherrypy.response.status = 202
else:
cherrypy.response.status = 201
return resp
def _get_resources(self, filter_params):
try:
res_list = super(StoragePools, self)._get_resources(filter_params)
# Append reserved pools
isos = getattr(self, ISO_POOL_NAME)
isos.lookup()
res_list.append(isos)
except AttributeError:
pass
return res_list
class StoragePool(Resource):
def __init__(self, model, ident):
super(StoragePool, self).__init__(model, ident)
self.admin_methods = ['PUT', 'POST', 'DELETE']
self.uri_fmt = '/storagepools/%s'
self.activate = self.generate_action_handler('activate')
self.deactivate = self.generate_action_handler(
'deactivate', destructive=True)
self.storagevolumes = StorageVolumes(self.model, ident)
self.log_map = STORAGEPOOL_REQUESTS
@property
def data(self):
res = {
'name': self.ident,
'state': self.info['state'],
'capacity': self.info['capacity'],
'allocated': self.info['allocated'],
'available': self.info['available'],
'path': self.info['path'],
'source': self.info['source'],
'type': self.info['type'],
'nr_volumes': self.info['nr_volumes'],
'autostart': self.info['autostart'],
'persistent': self.info['persistent'],
'in_use': self.info['in_use'],
}
val = self.info.get('task_id')
if val:
res['task_id'] = val
return res
class IsoPool(Resource):
def __init__(self, model):
super(IsoPool, self).__init__(model, ISO_POOL_NAME)
self.storagevolumes = IsoVolumes(self.model, ISO_POOL_NAME)
@property
def data(self):
return {
'name': self.ident,
'state': self.info['state'],
'type': self.info['type'],
}
================================================
FILE: control/storageservers.py
================================================
#
# Project Kimchi
#
# Copyright IBM Corp, 2015-2017
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
from wok import template
from wok.control.base import Collection
from wok.control.base import Resource
from wok.control.utils import get_class_name
from wok.control.utils import model_fn
from wok.control.utils import UrlSubNode
@UrlSubNode('storageservers', True)
class StorageServers(Collection):
def __init__(self, model):
super(StorageServers, self).__init__(model)
self.admin_methods = ['GET']
self.resource = StorageServer
class StorageServer(Resource):
def __init__(self, model, ident):
super(StorageServer, self).__init__(model, ident)
self.admin_methods = ['GET']
self.storagetargets = StorageTargets(self.model, self.ident)
@property
def data(self):
return self.info
class StorageTargets(Collection):
def __init__(self, model, server):
super(StorageTargets, self).__init__(model)
self.admin_methods = ['GET']
self.server = server
self.resource_args = [self.server]
self.model_args = [self.server]
def get(self, filter_params):
res_list = []
get_list = getattr(self.model, model_fn(self, 'get_list'))
res_list = get_list(*self.model_args, **filter_params)
return template.render(get_class_name(self), res_list)
================================================
FILE: control/storagevolumes.py
================================================
#
# Project Kimchi
#
# Copyright IBM Corp, 2015-2016
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
from wok import template
from wok.control.base import AsyncCollection
from wok.control.base import Collection
from wok.control.base import Resource
from wok.control.utils import get_class_name
from wok.control.utils import model_fn
STORAGEVOLUMES_REQUESTS = {'POST': {'default': 'KCHVOL0001L'}}
STORAGEVOLUME_REQUESTS = {
'DELETE': {'default': 'KCHVOL0002L'},
'PUT': {'default': 'KCHVOL0003L'},
'POST': {'wipe': 'KCHVOL0004L', 'resize': 'KCHVOL0005L', 'clone': 'KCHVOL0006L'},
}
class StorageVolumes(AsyncCollection):
def __init__(self, model, pool):
super(StorageVolumes, self).__init__(model)
self.resource = StorageVolume
self.pool = pool
self.resource_args = [self.pool]
self.model_args = [self.pool]
self.log_map = STORAGEVOLUMES_REQUESTS
self.log_args.update(
{'name': '', 'pool': self.pool if self.pool else ''})
def filter_data(self, resources, fields_filter):
# filter directory from storage volumes
fields_filter.update({'type': ['file', 'block', 'network']})
return super(StorageVolumes, self).filter_data(resources, fields_filter)
class StorageVolume(Resource):
def __init__(self, model, pool, ident):
super(StorageVolume, self).__init__(model, ident)
self.pool = pool
self.ident = ident
self.info = {}
self.model_args = [self.pool, self.ident]
self.uri_fmt = '/storagepools/%s/storagevolumes/%s'
self.resize = self.generate_action_handler('resize', ['size'])
self.wipe = self.generate_action_handler('wipe')
self.clone = self.generate_action_handler_task('clone')
# set user log messages and make sure all parameters are present
self.log_map = STORAGEVOLUME_REQUESTS
self.log_args.update(
{'pool': self.pool if self.pool else '', 'size': ''})
@property
def data(self):
res = {
'name': self.ident,
'type': self.info['type'],
'capacity': self.info['capacity'],
'allocation': self.info['allocation'],
'path': self.info['path'],
'used_by': self.info['used_by'],
'format': self.info['format'],
'isvalid': self.info['isvalid'],
'has_permission': self.info['has_permission'],
}
for key in ('os_version', 'os_distro', 'bootable', 'base'):
val = self.info.get(key)
if val:
res[key] = val
return res
class IsoVolumes(Collection):
def __init__(self, model, pool):
super(IsoVolumes, self).__init__(model)
self.pool = pool
def get(self, filter_params):
res_list = []
try:
get_list = getattr(self.model, model_fn(self, 'get_list'))
res_list = get_list(*self.model_args)
except AttributeError:
pass
return template.render(get_class_name(self), res_list)
================================================
FILE: control/templates.py
================================================
#
# Project Kimchi
#
# Copyright IBM Corp, 2015-2017
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
import os
from wok.control.base import Collection
from wok.control.base import Resource
from wok.control.utils import UrlSubNode
TEMPLATES_REQUESTS = {
'POST': {'default': 'KCHTMPL0001L'},
}
TEMPLATE_REQUESTS = {
'DELETE': {'default': 'KCHTMPL0002L'},
'PUT': {'default': 'KCHTMPL0003L'},
'POST': {
'clone': 'KCHTMPL0004L',
},
}
@UrlSubNode('templates', True)
class Templates(Collection):
def __init__(self, model):
super(Templates, self).__init__(model)
self.admin_methods = ['GET', 'POST']
self.resource = Template
# set user log messages and make sure all parameters are present
self.log_map = TEMPLATES_REQUESTS
self.log_args.update({'name': ''})
class Template(Resource):
def __init__(self, model, ident):
super(Template, self).__init__(model, ident)
self.admin_methods = ['PUT', 'POST', 'DELETE']
self.uri_fmt = '/templates/%s'
self.clone = self.generate_action_handler('clone')
self.log_map = TEMPLATE_REQUESTS
@property
def data(self):
info = {
'name': self.ident,
'icon': self.info['icon'],
'invalid': self.info['invalid'],
'os_distro': self.info['os_distro'],
'os_version': self.info['os_version'],
'memory': self.info['memory'],
'cdrom': self.info.get('cdrom', None),
'disks': self.info['disks'],
'networks': self.info.get('networks', []),
'folder': self.info.get('folder', []),
'graphics': self.info['graphics'],
'cpu_info': self.info.get('cpu_info')
}
if os.uname()[4] in ['s390x', 's390']:
info['interfaces'] = self.info.get('interfaces', [])
info['console'] = self.info.get('console', '')
return info
================================================
FILE: control/users.py
================================================
#
# Project Kimchi
#
# Copyright IBM Corp, 2015-2017
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
from wok.control.base import SimpleCollection
from wok.control.utils import get_class_name
from wok.control.utils import model_fn
from wok.control.utils import UrlSubNode
from wok.template import render
@UrlSubNode('users', True)
class Users(SimpleCollection):
def __init__(self, model):
super(Users, self).__init__(model)
def get(self, filter_params):
res_list = []
get_list = getattr(self.model, model_fn(self, 'get_list'))
res_list = get_list(*self.model_args, **filter_params)
return render(get_class_name(self), res_list)
================================================
FILE: control/vm/Makefile.am
================================================
#
# Kimchi
#
# Copyright IBM Corp, 2015-2016
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
vm_PYTHON = *.py
vmdir = $(pythondir)/wok/plugins/kimchi/control/vm
install-data-local:
$(MKDIR_P) $(DESTDIR)$(vmdir)
================================================
FILE: control/vm/__init__.py
================================================
#
# Project Kimchi
#
# Copyright IBM Corp, 2015-2016
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
import os
from wok.control.utils import load_url_sub_node
sub_nodes = load_url_sub_node(os.path.dirname(__file__), __name__)
================================================
FILE: control/vm/hostdevs.py
================================================
#
# Project Kimchi
#
# Copyright IBM Corp, 2015-2016
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
from wok.control.base import AsyncCollection
from wok.control.base import AsyncResource
from wok.control.utils import UrlSubNode
VMHOSTDEVS_REQUESTS = {'POST': {'default': 'KCHVMHDEV0001L'}}
VMHOSTDEV_REQUESTS = {'DELETE': {'default': 'KCHVMHDEV0002L'}}
@UrlSubNode('hostdevs')
class VMHostDevs(AsyncCollection):
def __init__(self, model, vmid):
super(VMHostDevs, self).__init__(model)
self.resource = VMHostDev
self.vmid = vmid
self.resource_args = [self.vmid]
self.model_args = [self.vmid]
# set user log messages and make sure all parameters are present
self.log_map = VMHOSTDEVS_REQUESTS
self.log_args.update(
{'name': '', 'vmid': self.vmid if self.vmid else ''})
class VMHostDev(AsyncResource):
def __init__(self, model, vmid, ident):
super(VMHostDev, self).__init__(model, ident)
self.vmid = vmid
self.ident = ident
self.model_args = [self.vmid, self.ident]
# set user log messages and make sure all parameters are present
self.log_map = VMHOSTDEV_REQUESTS
self.log_args.update({'vmid': self.vmid if self.vmid else ''})
@property
def data(self):
return self.info
================================================
FILE: control/vm/ifaces.py
================================================
#
# Project Kimchi
#
# Copyright IBM Corp, 2015-2016
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
from wok.control.base import Collection
from wok.control.base import Resource
from wok.control.utils import UrlSubNode
VMIFACES_REQUESTS = {'POST': {'default': 'KCHVMIF0001L'}}
VMIFACE_REQUESTS = {
'DELETE': {'default': 'KCHVMIF0002L'},
'PUT': {'default': 'KCHVMIF0003L'},
}
@UrlSubNode('ifaces')
class VMIfaces(Collection):
def __init__(self, model, vm):
super(VMIfaces, self).__init__(model)
self.resource = VMIface
self.vm = vm
self.resource_args = [self.vm]
self.model_args = [self.vm]
# set user log messages and make sure all parameters are present
self.log_map = VMIFACES_REQUESTS
self.log_args.update({'network': '', 'vm': self.vm if self.vm else ''})
class VMIface(Resource):
def __init__(self, model, vm, ident):
super(VMIface, self).__init__(model, ident)
self.vm = vm
self.ident = ident
self.info = {}
self.model_args = [self.vm, self.ident]
self.uri_fmt = '/vms/%s/ifaces/%s'
# set user log messages and make sure all parameters are present
self.log_map = VMIFACE_REQUESTS
self.log_args.update({'vm': self.vm if self.vm else ''})
@property
def data(self):
return self.info
================================================
FILE: control/vm/snapshots.py
================================================
#
# Project Kimchi
#
# Copyright IBM Corp, 2015-2016
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
from wok.control.base import AsyncCollection
from wok.control.base import Resource
from wok.control.utils import UrlSubNode
VMSNAPSHOTS_REQUESTS = {'POST': {'default': 'KCHSNAP0001L'}}
VMSNAPSHOT_REQUESTS = {
'DELETE': {'default': 'KCHSNAP0002L'},
'POST': {'revert': 'KCHSNAP0003L'},
}
@UrlSubNode('snapshots')
class VMSnapshots(AsyncCollection):
def __init__(self, model, vm):
super(VMSnapshots, self).__init__(model)
self.resource = VMSnapshot
self.vm = vm
self.resource_args = [self.vm]
self.model_args = [self.vm]
self.current = CurrentVMSnapshot(model, vm)
# set user log messages and make sure all parameters are present
self.log_map = VMSNAPSHOTS_REQUESTS
self.log_args.update({'vm': self.vm if self.vm else '', 'name': ''})
class VMSnapshot(Resource):
def __init__(self, model, vm, ident):
super(VMSnapshot, self).__init__(model, ident)
self.vm = vm
self.ident = ident
self.model_args = [self.vm, self.ident]
self.uri_fmt = '/vms/%s/snapshots/%s'
self.revert = self.generate_action_handler('revert')
# set user log messages and make sure all parameters are present
self.log_map = VMSNAPSHOT_REQUESTS
self.log_args.update({'vm': self.vm if self.vm else ''})
@property
def data(self):
return self.info
class CurrentVMSnapshot(Resource):
def __init__(self, model, vm):
super(CurrentVMSnapshot, self).__init__(model)
self.vm = vm
self.model_args = [self.vm]
self.uri_fmt = '/vms/%s/snapshots/current'
@property
def data(self):
return self.info
================================================
FILE: control/vm/storages.py
================================================
#
# Project Kimchi
#
# Copyright IBM Corp, 2015-2016
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
from wok.control.base import Collection
from wok.control.base import Resource
from wok.control.utils import UrlSubNode
VMSTORAGES_REQUESTS = {'POST': {'default': 'KCHVMSTOR0001L'}}
VMSTORAGE_REQUESTS = {
'DELETE': {'default': 'KCHVMSTOR0002L'},
'PUT': {'default': 'KCHVMSTOR0003L'},
}
@UrlSubNode('storages')
class VMStorages(Collection):
def __init__(self, model, vm):
super(VMStorages, self).__init__(model)
self.resource = VMStorage
self.vm = vm
self.resource_args = [self.vm]
self.model_args = [self.vm]
# set user log messages and make sure all parameters are present
self.log_map = VMSTORAGES_REQUESTS
self.log_args.update(
{'vm': self.vm if self.vm else '', 'path': '', 'type': ''})
class VMStorage(Resource):
def __init__(self, model, vm, ident):
super(VMStorage, self).__init__(model, ident)
self.vm = vm
self.ident = ident
self.info = {}
self.model_args = [self.vm, self.ident]
self.uri_fmt = '/vms/%s/storages/%s'
# set user log messages and make sure all parameters are present
self.log_map = VMSTORAGE_REQUESTS
self.log_args.update({'vm': self.vm if self.vm else ''})
@property
def data(self):
return self.info
================================================
FILE: control/vms.py
================================================
#
# Project Kimchi
#
# Copyright IBM Corp, 2015-2017
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
from wok.control.base import AsyncCollection
from wok.control.base import Resource
from wok.control.utils import internal_redirect
from wok.control.utils import UrlSubNode
from wok.plugins.kimchi.control.vm import sub_nodes
VMS_REQUESTS = {
'POST': {
'default': 'KCHVM0001L',
},
}
VM_REQUESTS = {
'DELETE': {'default': 'KCHVM0002L'},
'PUT': {'default': 'KCHVM0003L'},
'POST': {
'start': 'KCHVM0004L',
'poweroff': 'KCHVM0005L',
'shutdown': 'KCHVM0006L',
'reset': 'KCHVM0007L',
'connect': 'KCHVM0008L',
'clone': 'KCHVM0009L',
'migrate': 'KCHVM0010L',
'suspend': 'KCHVM0011L',
'resume': 'KCHVM0012L',
'serial': 'KCHVM0013L',
},
}
@UrlSubNode('vms', True)
class VMs(AsyncCollection):
def __init__(self, model):
super(VMs, self).__init__(model)
self.resource = VM
self.admin_methods = ['POST']
# set user log messages and make sure all parameters are present
self.log_map = VMS_REQUESTS
self.log_args.update({'name': '', 'template': ''})
class VM(Resource):
def __init__(self, model, ident):
super(VM, self).__init__(model, ident)
self.screenshot = VMScreenShot(model, ident)
self.virtviewerfile = VMVirtViewerFile(model, ident)
self.uri_fmt = '/vms/%s'
for ident, node in sub_nodes.items():
setattr(self, ident, node(model, self.ident))
self.start = self.generate_action_handler('start')
self.poweroff = self.generate_action_handler('poweroff',
destructive=True)
self.shutdown = self.generate_action_handler('shutdown',
destructive=True)
self.reset = self.generate_action_handler('reset',
destructive=True)
self.connect = self.generate_action_handler('connect')
self.clone = self.generate_action_handler_task('clone')
self.migrate = self.generate_action_handler_task('migrate',
['remote_host',
'user',
'password',
'enable_rdma'])
self.suspend = self.generate_action_handler('suspend')
self.resume = self.generate_action_handler('resume')
self.serial = self.generate_action_handler('serial')
# set user log messages and make sure all parameters are present
self.log_map = VM_REQUESTS
self.log_args.update({'remote_host': ''})
@property
def data(self):
return self.info
class VMScreenShot(Resource):
def __init__(self, model, ident):
super(VMScreenShot, self).__init__(model, ident)
def get(self):
self.lookup()
internal_uri = self.info.replace('plugins/kimchi', '')
raise internal_redirect(internal_uri)
class VMVirtViewerFile(Resource):
def __init__(self, model, ident):
super(VMVirtViewerFile, self).__init__(model, ident)
@property
def data(self):
internal_uri = self.info.replace('plugins/kimchi', '')
raise internal_redirect(internal_uri)
================================================
FILE: dependencies.yaml
================================================
development-deps:
common:
- gcc
- make
- autoconf
- automake
- git
- python3-pip
- python3-requests
- python3-mock
ubuntu:
- gettext
- pkgconf
- xsltproc
- python3-dev
- pep8
- pyflakes
- python3-yaml
fedora:
- gettext-devel
- rpm-build
- libxslt
- gcc-c++
- python3-devel
- python3-pep8
- python3-pyflakes
- rpmlint
- python3-pyyaml
opensuse-leap:
- gettext-tools
- rpm-build
- libxslt-tools
- gcc-c++
- python3-devel
- python3-pep8
- python3-pyflakes
- rpmlint
- python3-PyYAML
- python3-distro
runtime-deps:
common:
- python3-configobj
- python3-lxml
- python3-magic
- python3-paramiko
- python3-ldap
- spice-html5
- novnc
- qemu-kvm
ubuntu:
- python3-libvirt
- python3-parted
- python3-ethtool
- python3-guestfs
- python3-pil
- python3-cherrypy3
- libvirt0
- libvirt-daemon-system
- libvirt-clients
- nfs-common
- sosreport
- open-iscsi
- libguestfs-tools
- libnl-route-3-dev
fedora:
- python3-libvirt
- python3-pyparted
- python3-ethtool
- python3-pillow
- python3-cherrypy
- python3-libguestfs
- libvirt
- libvirt-daemon-config-network
- iscsi-initiator-utils
- libguestfs-tools
- sos
- nfs-utils
opensuse-leap:
- python3-libvirt-python
- python3-ethtool
- python3-Pillow
- python3-CherryPy
- python3-libguestfs
- parted-devel
- libvirt
- libvirt-daemon-config-network
- open-iscsi
- guestfs-tools
- nfs-client
- gcc
- python3-devel
================================================
FILE: disks.py
================================================
#
# Project Kimchi
#
# Copyright IBM Corp, 2015-2017
#
# Code derived from Ginger Base project
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
import os.path
import re
from parted import Device as PDevice
from parted import Disk as PDisk
from wok.exception import NotFoundError
from wok.exception import OperationFailed
from wok.stringutils import encode_value
from wok.utils import run_command
from wok.utils import wok_log
def _get_dev_node_path(maj_min):
""" Returns device node path given the device number 'major:min' """
dm_name = '/sys/dev/block/%s/dm/name' % maj_min
if os.path.exists(dm_name):
with open(dm_name) as dm_f:
content = dm_f.read().rstrip('\n')
return '/dev/mapper/' + content
uevent = '/sys/dev/block/%s/uevent' % maj_min
with open(uevent) as ueventf:
content = ueventf.read()
data = dict(re.findall(r'(\S+)=(".*?"|\S+)', content.replace('\n', ' ')))
return '/dev/%s' % data['DEVNAME']
def _get_lsblk_devs(keys, devs=None):
if devs is None:
devs = []
out, err, returncode = run_command(
['lsblk', '-Pbo'] + [','.join(keys)] + devs)
if returncode != 0:
if 'not a block device' in err:
raise NotFoundError('KCHDISK00002E')
else:
raise OperationFailed('KCHDISK00001E', {'err': err})
return _parse_lsblk_output(out, keys)
def _get_dev_major_min(name):
maj_min = None
keys = ['NAME', 'MAJ:MIN']
try:
dev_list = _get_lsblk_devs(keys)
except Exception:
raise
for dev in dev_list:
if dev['name'].split()[0] == name:
maj_min = dev['maj:min']
break
else:
raise NotFoundError('KCHDISK00003E', {'device': name})
return maj_min
def _is_dev_leaf(devNodePath, name=None, devs=None, devtype=None):
try:
if devs and devtype != 'mpath':
for dev in devs:
if encode_value(name) == dev['pkname']:
return False
return True
# By default, lsblk prints a device information followed by children
# device information
childrenCount = len(_get_lsblk_devs(['NAME'], [devNodePath])) - 1
except OperationFailed as e:
# lsblk is known to fail on multipath devices
# Assume these devices contain children
wok_log.error('Error getting device info for %s: %s', devNodePath, e)
return False
return childrenCount == 0
def _is_dev_extended_partition(devType, devNodePath):
if devType != 'part':
return False
if devNodePath.startswith('/dev/mapper'):
try:
dev_maj_min = _get_dev_major_min(devNodePath.split('/')[-1])
parent_sys_path = '/sys/dev/block/' + dev_maj_min + '/slaves'
parent_dm_name = os.listdir(parent_sys_path)[0]
parent_maj_min = (
open(parent_sys_path + '/' + parent_dm_name + '/dev')
.readline()
.rstrip()
)
diskPath = _get_dev_node_path(parent_maj_min)
except Exception as e:
wok_log.error(
'Error dealing with dev mapper device: ' + devNodePath)
raise OperationFailed('KCHDISK00001E', {'err': e.message})
else:
diskPath = devNodePath.rstrip('0123456789')
device = PDevice(diskPath)
try:
extended_part = PDisk(device).getExtendedPartition()
except NotImplementedError as e:
wok_log.warning(
'Error getting extended partition info for dev %s type %s: %s',
devNodePath,
devType,
e.message,
)
# Treate disk with unsupported partiton table as if it does not
# contain extended partitions.
return False
if extended_part and extended_part.path == devNodePath:
return True
return False
def _parse_lsblk_output(output, keys):
# output is on format key="value",
# where key can be NAME, TYPE, FSTYPE, SIZE, MOUNTPOINT, etc
lines = output.rstrip('\n').split('\n')
r = []
for line in lines:
d = {}
for key in keys:
expression = r"%s=\".*?\"" % key
match = re.search(expression, line)
field = match.group()
k, v = field.split('=', 1)
d[k.lower()] = v[1:-1]
r.append(d)
return r
def _is_available(name, devtype, fstype, mountpoint, majmin, devs=None):
devNodePath = _get_dev_node_path(majmin)
# Only list unmounted and unformated and leaf and (partition or disk)
# leaf means a partition, a disk has no partition, or a disk not held
# by any multipath device. Physical volume belongs to no volume group
# is also listed. Extended partitions should not be listed.
if fstype == 'LVM2_member':
has_VG = True
else:
has_VG = False
if (
devtype in ['part', 'disk', 'mpath'] and
fstype in ['', 'LVM2_member'] and
mountpoint == '' and
not has_VG and
_is_dev_leaf(devNodePath, name, devs, devtype) and
not _is_dev_extended_partition(devtype, devNodePath)
):
return True
return False
def get_partitions_names(check=False):
names = set()
keys = ['NAME', 'TYPE', 'FSTYPE', 'MOUNTPOINT', 'MAJ:MIN']
# output is on format key="value",
# where key can be NAME, TYPE, FSTYPE, MOUNTPOINT
for dev in _get_lsblk_devs(keys):
# split()[0] to avoid the second part of the name, after the
# whiteline
name = dev['name'].split()[0]
if check and not _is_available(
name, dev['type'], dev['fstype'], dev['mountpoint'], dev['maj:min']
):
continue
names.add(name)
return list(names)
def get_partition_details(name):
majmin = _get_dev_major_min(name)
dev_path = _get_dev_node_path(majmin)
keys = ['TYPE', 'FSTYPE', 'SIZE', 'MOUNTPOINT', 'MAJ:MIN', 'PKNAME']
try:
dev = _get_lsblk_devs(keys, [dev_path])[0]
except Exception:
wok_log.error('Error getting partition info for %s', name)
return {}
dev['available'] = _is_available(
name, dev['type'], dev['fstype'], dev['mountpoint'], majmin
)
if dev['mountpoint']:
# Sometimes the mountpoint comes with [SWAP] or other
# info which is not an actual mount point. Filtering it
regexp = re.compile(r'\[.*\]')
if regexp.search(dev['mountpoint']) is not None:
dev['mountpoint'] = ''
dev['path'] = dev_path
dev['name'] = name
return dev
def vgs():
"""
lists all volume groups in the system. All size units are in bytes.
[{'vgname': 'vgtest', 'size': 999653638144L, 'free': 0}]
"""
cmd = [
'vgs',
'--units',
'b',
'--nosuffix',
'--noheading',
'--unbuffered',
'--options',
'vg_name,vg_size,vg_free',
]
out, err, rc = run_command(cmd)
if rc != 0:
raise OperationFailed('KCHDISK00004E', {'err': err})
if not out:
return []
# remove blank spaces and create a list of VGs
vgs = map(lambda v: v.strip(), out.strip('\n').split('\n'))
# create a dict based on data retrieved from vgs
return map(
lambda l: {'vgname': l[0], 'size': int(l[1]), 'free': int(l[2])},
[fields.split() for fields in vgs],
)
def lvs(vgname=None):
"""
lists all logical volumes found in the system. It can be filtered by
the volume group. All size units are in bytes.
[{'lvname': 'lva', 'path': '/dev/vgtest/lva', 'size': 12345L},
{'lvname': 'lvb', 'path': '/dev/vgtest/lvb', 'size': 12345L}]
"""
cmd = [
'lvs',
'--units',
'b',
'--nosuffix',
'--noheading',
'--unbuffered',
'--options',
'lv_name,lv_path,lv_size,vg_name',
]
out, err, rc = run_command(cmd)
if rc != 0:
raise OperationFailed('KCHDISK00004E', {'err': err})
if not out:
return []
# remove blank spaces and create a list of LVs filtered by vgname, if
# provided
lvs = filter(
lambda f: vgname is None or vgname in f,
map(lambda v: v.strip(), out.strip('\n').split('\n')),
)
# create a dict based on data retrieved from lvs
return map(
lambda l: {'lvname': l[0], 'path': l[1], 'size': int(l[2])},
[fields.split() for fields in lvs],
)
def pvs(vgname=None):
"""
lists all physical volumes in the system. It can be filtered by the
volume group. All size units are in bytes.
[{'pvname': '/dev/sda3',
'size': 469502001152L,
'uuid': 'kkon5B-vnFI-eKHn-I5cG-Hj0C-uGx0-xqZrXI'},
{'pvname': '/dev/sda2',
'size': 21470642176L,
'uuid': 'CyBzhK-cQFl-gWqr-fyWC-A50Y-LMxu-iHiJq4'}]
"""
cmd = [
'pvs',
'--units',
'b',
'--nosuffix',
'--noheading',
'--unbuffered',
'--options',
'pv_name,pv_size,pv_uuid,vg_name',
]
out, err, rc = run_command(cmd)
if rc != 0:
raise OperationFailed('KCHDISK00004E', {'err': err})
if not out:
return []
# remove blank spaces and create a list of PVs filtered by vgname, if
# provided
pvs = filter(
lambda f: vgname is None or vgname in f,
map(lambda v: v.strip(), out.strip('\n').split('\n')),
)
# create a dict based on data retrieved from pvs
return map(
lambda l: {'pvname': l[0], 'size': int(l[1]), 'uuid': l[2]},
[fields.split() for fields in pvs],
)
================================================
FILE: distroloader.py
================================================
#
# Project Kimchi
#
# Copyright IBM Corp, 2015-2016
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
#
import glob
import json
import os
from wok.exception import NotFoundError
from wok.exception import OperationFailed
from wok.plugins.kimchi import config
from wok.utils import wok_log
ARCHS = {'x86_64': ['x86_64', 'amd64', 'i686', 'x86', 'i386'],
'amd64': ['x86_64', 'amd64', 'i686', 'x86', 'i386'],
'ppc64': ['ppc', 'ppc64'],
'ppc64le': ['ppc64', 'ppc64le'],
's390x': ['s390', 's390x']}
class DistroLoader(object):
def __init__(self, location=None):
self.location = location or config.get_distros_store()
def _get_json_info(self, fname):
msg_args = {'filename': fname}
if not os.path.isfile(fname):
msg = 'DistroLoader: failed to find distro file: %s' % fname
wok_log.error(msg)
raise NotFoundError('KCHDL0001E', msg_args)
try:
with open(fname) as f:
data = json.load(f)
return data
except ValueError:
msg = 'DistroLoader: failed to parse distro file: %s' % fname
wok_log.error(msg)
raise OperationFailed('KCHDL0002E', msg_args)
def get(self):
arch_list = ARCHS.get(os.uname()[4])
all_json_files = glob.glob('%s/%s' % (self.location, '*.json'))
distros = []
for f in all_json_files:
distros.extend(self._get_json_info(f))
# Return all remote ISOs arch not found
return dict([(distro['name'], distro) for distro in distros if
(arch_list is None or distro['os_arch'] in arch_list)])
================================================
FILE: distros.d/Makefile.am
================================================
#
# Kimchi
#
# Copyright IBM Corp, 2015-2016
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
distrosdir = $(sysconfdir)/kimchi/distros.d
dist_distros_DATA = *.json
================================================
FILE: distros.d/debian.json
================================================
[
{
"name": "Debian 10",
"os_distro": "debian",
"os_arch": "x86_64",
"os_version": "10",
"path": "https://cdimage.debian.org/debian-cd/current/i386/iso-cd/debian-10.2.0-i386-netinst.iso"
}
]
================================================
FILE: distros.d/fedora.json
================================================
[
{
"name": "Fedora 30",
"os_distro": "fedora",
"os_arch": "x86_64",
"os_version": "30",
"path": "https://muug.ca/mirror/fedora/linux/releases/30/Everything/x86_64/iso/Fedora-Everything-netinst-x86_64-30-1.2.iso"
},
{
"name": "Fedora 31",
"os_distro": "fedora",
"os_arch": "x86_64",
"os_version": "31",
"path": "https://muug.ca/mirror/fedora/linux/releases/31/Everything/x86_64/iso/Fedora-Everything-netinst-x86_64-31-1.9.iso"
}
]
================================================
FILE: distros.d/gentoo.json
================================================
[
{
"name": "gentoo-20140826",
"os_distro": "gentoo",
"os_arch": "x86_64",
"os_version": "20191206",
"path": "https://distfiles.gentoo.org/releases/x86/autobuilds/20191206T214502Z/install-x86-minimal-20191206T214502Z.iso"
}
]
================================================
FILE: distros.d/opensuse.json
================================================
[
{
"name": "OpenSUSE LEAP 15.1",
"os_distro": "opensuse",
"os_arch": "x86_64",
"os_version": "15.1",
"path": "https://download.opensuse.org/distribution/leap/15.1/iso/openSUSE-Leap-15.1-NET-x86_64.iso"
}
]
================================================
FILE: distros.d/ubuntu.json
================================================
[
{
"name": "Ubuntu 19.04",
"os_distro": "ubuntu",
"os_arch": "x86_64",
"os_version": "19.04",
"path": "https://releases.ubuntu.com/19.04/ubuntu-19.04-desktop-amd64.iso"
},
{
"name": "Ubuntu 19.10",
"os_distro": "ubuntu",
"os_arch": "x86_64",
"os_version": "19.10",
"path": "https://releases.ubuntu.com/19.10/ubuntu-19.10-desktop-amd64.iso"
}
]
================================================
FILE: docs/API.md
================================================
## Project Kimchi REST API Specification
The Kimchi API provides all functionality to the application and may be used
directly by external tools. In the following sections you will find the
specification of all Collections and Resource types that are supported and the
URIs where they can be accessed. In order to use the API effectively, please
the following general conventions:
* The **Content Type** of the API is JSON. When making HTTP requests to this
API you should specify the following headers:
* Accept: application/json
* Content-type: application/json
* A **Collection** is a group of Resources of a given type.
* A **GET** request retrieves a list of summarized Resource representations
This summary *may* include all or some of the Resource properties but
*must* include a link to the full Resource representation.
* A **POST** request will create a new Resource in the Collection. The set
of Resource properties *must* be specified as a JSON object in the request
body.
* No other HTTP methods are supported for Collections
* A **Resource** is a representation of a singular object in the API (eg.
Virtual Machine).
* A **GET** request retrieves the full Resource representation.
* A **DELETE** request will delete the Resource. This request *may* contain
a JSON object which specifies optional parameters.
* A **PUT** request is used to modify the properties of a Resource (eg.
Change the name of a Virtual Machine). This kind of request *must not*
alter the live state of the Resource. Only *actions* may alter live state.
* A **POST** request commits an *action* upon a Resource (eg. Start a
Virtual Machine). This request is made to a URI relative to the Resource
URI. Available *actions* are described within the *actions* property of a
Resource representation. The request body *must* contain a JSON object
which specifies parameters.
* URIs begin with '/plugins/kimchi' to indicate the root of Kimchi plugin.
* Variable segments in the URI begin with a ':' and should replaced with the
appropriate resource identifier.
### Collection: Tasks
**URI:** /plugins/kimchi/tasks
**Methods:**
* **GET**: Retrieve a summarized list of current Kimchi specific Tasks (stored
in Kimchi's object store)
### Resource: Task
**URI:** /plugins/kimchi/tasks/*:id*
A task represents an asynchronous operation that is being performed by the
server.
**Methods:**
* **GET**: Retrieve the full description of the Task
* id: The Task ID is used to identify this Task in the API.
* status: The current status of the Task
* running: The task is running
* finished: The task has finished successfully
* failed: The task failed
* message: Human-readable details about the Task status
* target_uri: Resource URI related to the Task
* **POST**: *See Task Actions*
**Actions (POST):**
*No actions defined*
### Collection: Virtual Machines
**URI:** /plugins/kimchi/vms
**Methods:**
* **GET**: Retrieve a summarized list of all defined Virtual Machines
* **POST**: Create a new Virtual Machine
* name *(optional)*: The name of the VM. Used to identify the VM in this
API. If omitted, a name will be chosen based on the template used.
* persistent: If 'true', vm will persist after a Power Off or host reboot.
All virtual machines created by Kimchi are persistent.
* template: The URI of a Template to use when building the VM
* storagepool *(optional)*: Assign a specific Storage Pool to the new VM
* graphics *(optional)*: Specify the graphics paramenter for this vm
* type: The type of graphics. It can be VNC or spice or None.
* vnc: Graphical display using the Virtual Network
Computing protocol
* spice: Graphical display using the Simple Protocol for
Independent Computing Environments
* null: Graphics is disabled or type not supported
* listen: The network which the vnc/spice server listens on.
* description: VM description
* title: VM title
### Resource: Virtual Machine
**URI:** /plugins/kimchi/vms/*:name*
**Methods:**
* **GET**: Retrieve the full description of a Virtual Machine
* name: The name of the VM. Used to identify the VM in this API
* state: Indicates the current state in the VM lifecycle
* running: The VM is powered on
* paused: The VMs virtual CPUs are paused
* shutoff: The VM is powered off
* stats: Virtual machine statistics:
* cpu_utilization: A number between 0 and 100 which indicates the
percentage of CPU utilization.
* mem_utilization: A number between 0 and 100 which indicates the
percentage of memory utilization.
* net_throughput: Expresses total network throughput for reads and
writes across all virtual interfaces (kb/s).
* net_throughput_peak: The highest recent value of 'net_throughput'.
* io_throughput: Expresses the total IO throughput for reads and
writes across all virtual disks (kb/s).
* io_throughput_peak: The highest recent value of 'io_throughput'.
* uuid: UUID of the VM.
* memory: The memory parameters of the VM in the unit of MiB.
* current: The amount of memory that is assigned to the VM.
* maxmemory: The maximum total of memory that the VM can have. Amount
over current will be used exclusively for memory hotplug
* cpu_info: CPU-specific information.
* vcpus: The number of CPUs assigned to the VM
* maxvcpus: The maximum number of CPUs that can be assigned to the VM
* topology: Processor topology, includes:
* sockets - The maximum number of sockets to use.
* cores - The number of cores per socket.
* threads - The number of threads per core.
* screenshot: A link to a recent capture of the screen in PNG format
* icon: A link to an icon that represents the VM
* graphics: A dict to show detail of VM graphics.
* type: The type of graphics. It can be VNC or spice or None.
* vnc: Graphical display using the Virtual Network
Computing protocol
* spice: Graphical display using the Simple Protocol for
Independent Computing Environments
* null: Graphics is disabled or type not supported
* listen: The network which the vnc/spice server listens on.
* port: The real port number of the graphics, vnc or spice. Users
can use this port to connect to the vm with general vnc/spice
clients.
* passwd: console password
* passwdValidTo: lifetime for the console password.
* users: A list of system users who have permission to access the VM.
Default is: empty (i.e. only root-users may access).
* groups: A list of system groups whose users have permission to access
the VM. Default is: empty (i.e. no groups given access).
* bootorder: list of devices in boot order
* description: VM description
* title: VM title
* autostart: show if autostart is enabled.
* **DELETE**: Remove the Virtual Machine
* **PUT**: update the parameters of existing VM
* name: New name for this VM (only applied for shutoff VM)
* users: New list of system users.
* groups: New list of system groups.
* memory: New memory parameters of the VM in the unit of MiB.
Provide one or both.
* current: New amount of memory that will be assigned to the VM.
* maxmemory: New maximum total of memory that the VM can have.
* graphics: A dict to show detail of VM graphics.
* passwd *(optional)*: console password. When omitted a random password
willbe generated.
* passwdValidTo *(optional)*: lifetime for the console password. When
omitted the password will be valid just
for 30 seconds.
* type *(optional)*: graphics type. VNC or Spice.
* cpu_info *(optional)*: CPU-specific information.
* maxvcpus *(optional)*: The maximum number of vCPUs that can be
assigned to the VM. If topology is specified, maxvcpus must be a
product of sockets, cores and threads.
* vcpus *(optional)*: The number of vCPUs assigned to the VM. Default
is 1, unless a CPU topology is specified. In that case, vcpus
must be a multiple of a product of cores and threads, and will
default to maxvcpus value.
* topology *(optional)*: Specify sockets, threads, and cores to run the
virtual CPU threads on. All three are required.
* sockets - The maximum number of sockets to use.
* cores - The number of cores per socket.
* threads - The number of threads per core.
* bootorder: guest bootorder, types accepted: hd, cdrom, network or fd
* bootmenu: prompts guest bootmenu. Bool type.
* description: VM description
* title: VM title
* autostart: enable/disable guest autostart (true or false params).
* **POST**: *See Virtual Machine Actions*
**Actions (POST):**
* start: Power on a VM
* poweroff: Power off a VM forcefully. Note this action may produce undesirable
results, for example unflushed disk cache in the guest.
* shutdown: Shut down a VM graceful. This action issue shutdown request to guest.
And the guest will react this request. Note the guest OS may ignore
the request.
* reset: Reset a VM immediately without the guest OS shutdown.
It emulates the power reset button on a machine. Note that there is a
risk of data loss caused by reset without the guest OS shutdown.
* connect: Prepare the connection for spice or vnc
* clone: Create a new VM identical to this VM. The new VM's name, UUID and
network MAC addresses will be generated automatically. Each existing
disks will be copied to a new volume in the same storage pool. If
there is no available space on that storage pool to hold the new
volume, it will be created on the pool 'default'. This action returns
a Task.
* suspend: Suspend an active domain. The process is frozen without further
access to CPU resources and I/O but the memory used by the domain at
the hypervisor level will stay allocated.
* resume: Resume a suspended domain. The process is restarted from the state
where it was frozen by calling "suspend".
* migrate: Migrate a virtual machine to a remote server, only support live
mode without block migration.
* remote_host: IP address or hostname of the remote server.
* user *(optional)*: User to log on at the remote server.
* password *(optional)*: password of the user in the remote server.
* enable_rdma *(optional)*: boolean. If set to True, the migration will use RDMA transport.
### Sub-resource: Virtual Machine Screenshot
**URI:** /plugins/kimchi/vms/*:name*/screenshot
Represents a snapshot of the Virtual Machine's primary monitor.
**Methods:**
* **GET**: Redirect to the latest screenshot of a Virtual Machine in PNG format
### Sub-collection: Virtual Machine storages
**URI:** /plugins/kimchi/vms/*:name*/storages
* **GET**: Retrieve a summarized list of all storages of specified guest
* **POST**: Attach a new storage or virtual drive to specified virtual machine.
* type: The type of the storage (currently support 'cdrom' and 'disk').
* path: Path of cdrom iso.
* pool: Storage pool which disk image file locate in.
* vol: Storage volume name of disk image.
* dir_path: s390x specific attribute to attach direct storage without libvirt
* format: s390x specific attribute specify the format of direct storage
* size: s390x specific attribute to specify the size of direct storage
### Sub-resource: storage
**URI:** /plugins/kimchi/vms/*:name*/storages/*:dev*
* **GET**: Retrieve storage information
* dev: The name of the storage in the vm.
* type: The type of the storage (currently support 'cdrom' and 'disk').
* path: Path of cdrom iso or disk image file.
* bus: Bus type of disk attached.
* **PUT**: Update storage information
* path: Path of cdrom iso. Can not be blank. Now just support cdrom type.
* **DELETE**: Remove the storage.
**Actions (POST):**
### Sub-collection: Virtual Machine Passthrough Devices
**URI:** /plugins/kimchi/vms/*:name*/hostdevs
* **GET**: Retrieve a summarized list of all directly assigned host device of
specified guest.
* **POST**: Directly assign a host device to guest.
* name: The name of the host device to be assigned to vm.
### Sub-resource: Device
**URI:** /plugins/kimchi/vms/*:name*/hostdevs/*:dev*
* **GET**: Retrieve assigned device information
* name: The name of the assigned device.
* type: The type of the assigned device.
* **DELETE**: Detach the host device from VM.
### Sub-collection: Virtual Machine Snapshots
**URI:** /plugins/kimchi/vms/*:name*/snapshots
* **POST**: Create a new snapshot on a VM.
* name: The snapshot name (optional, defaults to a value based on the
current time).
* **GET**: Retrieve a list of snapshots on a VM.
### Sub-resource: Snapshot
**URI:** /plugins/kimchi/vms/*:name*/snapshots/*:snapshot*
* **GET**: Retrieve snapshot information.
* created: The time when the snapshot was created
(in seconds, since the epoch).
* name: The snapshot name.
* parent: The name of the parent snapshot, or an empty string if there is
no parent.
* state: The corresponding domain's state when the snapshot was created.
* **DELETE**: Delete snapshot. If the snapshot has any children, they will be
merged automatically with the snapshot's parent.
* **POST**: See "Snapshot actions (POST)"
**Snapshot Actions (POST):**
* revert: Revert the domain to the given snapshot.
### Sub-resource: Current snapshot
**URI:** /plugins/kimchi/vms/*:name*/snapshots/current
* **GET**: Retrieve current snapshot information for the virtual machine.
### Sub-resource: Virt-Viewer File
**URI:** /plugins/kimchi/vms/*:name*/virtviewerfile
* **GET**: Retrieve the Virt-Viewer launcher file to connect to the
graphics of this virtual machine. Virtual machine must
be running.
### Collection: Templates
**URI:** /plugins/kimchi/templates
**Methods:**
* **GET**: Retrieve a summarized list of all defined Templates
* **POST**: Create a new Template
* name: The name of the Template. Used to identify the Template in this API
* source_media: dictionary. The type of media to be used in the installation.
* type: the type of the media. Values: 'netboot' and 'disk'.
* path: applicable for type = 'disk' only. Indicates the path of the
source media.
* os_distro *(optional)*: The operating system distribution
* os_version *(optional)*: The version of the operating system distribution
* memory *(optional)*: The memory parameters of the template, specify one
or both. Default values are 1024MiB:
* current: The amount of memory that will be assigned to the VM.
* maxmemory: The maximum total of memory that the VM can have. Amount
over current will be used exclusively for memory hotplug
* networks *(optional)*: list of networks will be assigned to the new VM.
Default is '[default]'
* disks *(optional)*: An array of requested disks with the following optional fields
(either *size* or *volume* must be specified):
* index: The device index
* size: The device size in GB
* format: Format of the image. Valid formats: qcow, qcow2, qed, raw, vmdk, vpc
* pool: Storage pool information
* name: URI of the storagepool where disk will be created
* graphics *(optional)*: The graphics paramenters of this template
* type: The type of graphics. It can be VNC or spice or None.
* vnc: Graphical display using the Virtual Network
Computing protocol
* spice: Graphical display using the Simple Protocol for
Independent Computing Environments
* null: Graphics is disabled or type not supported
* listen: The network which the vnc/spice server listens on.
* cpu_info *(optional)*: CPU-specific information.
* maxvcpus *(optional)*: The maximum number of vCPUs that can be
assigned to the VM. If topology is specified, maxvcpus must be a
product of sockets, cores and threads.
* vcpus *(optional)*: The number of vCPUs assigned to the VM. Default
is 1, unless a CPU topology is specified. In that case, vcpus
must be a multiple of a product of cores and threads, and will
default to maxvcpus value.
* topology *(optional)*: Specify sockets, threads, and cores to run the
virtual CPU threads on. All three are required.
* sockets - The maximum number of sockets to use.
* cores - The number of cores per socket.
* threads - The number of threads per core.
### Sub-Collection: Virtual Machine Network Interfaces
**URI:** /plugins/kimchi/vms/*:name*/ifaces
Represents all network interfaces attached to a Virtual Machine.
**Methods:**
* **GET**: Retrieve a summarized list of all network interfaces attached to a Virtual Machine.
* **POST**: attach a network interface to VM
* model *(optional)*: model of emulated network interface card. It can be one of these models:
ne2k_pci, i82551, i82557b, i82559er, rtl8139, e1000, pcnet and virtio.
When model is missing, libvirt will set 'rtl8139' as default value.
* network *(optional)*: the name of resource network, it is required when the
interface type is network.
* source: *Only valid for s390x architecture & only applicable for type macvtap or ovs*. The host network interface. It should be the host network interface name (Ethernet, Bond, VLAN) for type 'macvtap' or host openvswitch bridge interface name for type 'ovs'.
* type: The type of VM network interface that libvirt supports.
Kimchi supports 'network' type for architecture other than s390x/s390. For s390x/s390 ’macvtap’ or ‘ovs’ are additionally supported. Type should be 'macvtap' for host network interface (Ethernet, Bond, VLAN) to be connected as direct MacVTap; or 'ovs' for openvswitch host network interface to be connected as virtual switch to a VM.
* mode *(optional)*: *Only valid for s390x architecture & only applicable for type macvtap*. Supported values ’bridge’ or ‘vepa’. This indicates whether packets will be delivered directly to target device(bridge) or to the external bridge(vepa-capable bridge).
* bridge: If packets have a destination on the host from which they originated, they are delivered directly to the target. For direct delivery, both origin and destination devices need to be in bridge mode. If either the origin or destination is in vepa mode, VEPA-capable bridge is required.
* vepa: All packets are sent to the external bridge. If packets have a destination on the host from which they originated, the VEPA-capable bridge will return the packets to the host.
### Sub-Resource: Virtual Machine Network Interface
**URI:** /plugins/kimchi/vms/*:name*/ifaces/*:mac*
A interface represents available network interface on VM.
**Methods:**
* **GET**: Retrieve the full description of the VM network interface
* bridge *(optional)*: the name of resource bridge, only be available when the
interface type is bridge.
* mac: Media Access Control Address of the VM interface.
* ips: A list of IP addresses associated with this MAC.
* model *(optional)*: model of emulated network interface card. It will be one of these models:
ne2k_pci, i82551, i82557b, i82559er, rtl8139, e1000, pcnet and virtio.
* network *(optional)*: the name of resource network, only be available when the
interface type is network.
* source *(optional)*: *Only valid for s390x architecture & only applicable for type macvtap or ovs*. The host network interface. It should be the host network interface name (Ethernet, Bond, VLAN) for type 'macvtap' or host openvswitch bridge interface name for type 'ovs'.
* type: The type of VM network interface that libvirt supports.
It will be one of these types: 'network', 'bridge', 'user','ethernet',
'direct', 'hostdev', 'mcast', 'server' and 'client' for architecture other than s390x/s390.
For s390x/s390 additional type supported are 'macvtap', 'ovs'. Type should be 'macvtap' for host network interface (Ethernet, Bond, VLAN) to be connected as direct MacVTap; or 'ovs' for openvswitch host network interface to be connected as virtual switch to a VM.
* mode *(optional)*: *Only valid for s390x architecture & only applicable for type macvtap*. Supported values ’bridge’ or ‘vepa’. This indicates whether packets will be delivered directly to target device(bridge) or to the external bridge(vepa-capable bridge).
* bridge: If packets have a destination on the host from which they originated, they are delivered directly to the target. For direct delivery, both origin and destination devices need to be in bridge mode. If either the origin or destination is in vepa mode, VEPA-capable bridge is required.
* vepa: All packets are sent to the external bridge. If packets have a destination on the host from which they originated, the VEPA-capable bridge will return the packets to the host.
* **DELETE**: detach the network interface from VM
* **PUT**: update the parameters of existing VM interface.
* model *(optional)*: model of emulated network interface card. It will be one of these models:
ne2k_pci, i82551, i82557b, i82559er, rtl8139, e1000, pcnet and virtio.
This change is only on the persisted VM configuration.
* network *(optional)*: the name of resource network, only be available when the
interface type is network.
This change is on the active VM instance and persisted VM configuration.
**Actions (POST):**
*No actions defined*
### Resource: Template
**URI:** /plugins/kimchi/templates/*:name*
**Methods:**
* **GET**: Retrieve the full description of a Template
* name: A name for this template
* folder: A virtual path which can be used to organize Templates in a user
interface. The format is an array of path components.
* icon: A URI to a PNG image representing this template
* os_distro: The operating system distribution
* os_version: The version of the operating system distribution
* memory: The memory parameters of the template, that will be assigned to
the VM in the unit of MiB.
* current: The amount of memory that will be assigned to the VM.
* maxmemory: The maximum total of memory that the VM can have. Amount
over current will be used exclusively for memory hotplug
* cdrom: A volume name or URI to an ISO image
* storagepool: URI of the storagepool where template allocates vm storage.
* path *(optional and only valid for s390x architecture)*: Storage path to store virtual disks without libvirt.
* networks *(optional)*: list of networks will be assigned to the new VM.
* interfaces *(optional)*: list of host network interfaces will be assigned to the new VM. Only applicable for s390x or s390 architecture.
* type: Type of host network interface. Type should be 'macvtap' for host network interface (Ethernet, Bond, VLAN) to be connected as direct MacVTap; or 'ovs' for openvswitch host network interface to be connected as virtual switch to a VM.
* name: The host network interface. It should be the host network interface (Ethernet, Bond, VLAN) for type 'macvtap' or host openvswitch bridge interface for type 'ovs'.
* mode *(optional)*: Only applicable for interface type macvtap, to indicates whether packets will be delivered directly to target device(bridge) or to the external bridge(vepa-capable bridge).
* bridge: If packets have a destination on the host from which they originated, they are delivered directly to the target. For direct delivery, both origin and destination devices need to be in bridge mode. If either the origin or destination is in vepa mode, VEPA-capable bridge is required.
* vepa: All packets are sent to the external bridge. If packets have a destination on the host from which they originated, the VEPA-capable bridge will return the packets to the host.
* disks: An array of requested disks with the following optional fields
(either *size* or *volume* must be specified):
* index: The device index
* size: The device size in GB
* volume: A volume name that contains the initial disk contents
* format: Format of the image. Valid formats: qcow, qcow2, qed, raw, vmdk, vpc.
* pool: Information about the pool where disk or volume will be created
* name: URI of the storagepool
* type: Type of the storagepool (dir, nfs, scsci, iscsi, etc)
* graphics: A dict of graphics paramenters of this template
* type: The type of graphics. It can be VNC or spice or None.
* vnc: Graphical display using the Virtual Network
Computing protocol
* spice: Graphical display using the Simple Protocol for
Independent Computing Environments
* null: Graphics is disabled or type not supported
* listen: The network which the vnc/spice server listens on.
* invalid: A dict indicates which paramenters of this template are invalid.
* networks *(optional)*: An array of invalid network names.
* cdrom *(optional)*: An array of invalid cdrom names.
* disks *(optional)*: An array of invalid volume names.
* storagepools *(optional)*: An array of invalid storagepool names.
* cpu_info: CPU-specific information.
* vcpus: The number of CPUs assigned to the VM
* maxvcpus: The maximum number of CPUs that can be assigned to the VM
* topology: Processor topology, includes:
* sockets - The maximum number of sockets to use.
* cores - The number of cores per socket.
* threads - The number of threads per core.
* **DELETE**: Remove the Template
* **POST**: *See Template Actions*
* **PUT**: update the parameters of existed template
* name: A name for this template
* folder: A virtual path which can be used to organize Templates in the user
interface. The format is an array of path components.
* icon: A URI to a PNG image representing this template
* os_distro: The operating system distribution
* os_version: The version of the operating system distribution
* memory: The memory parameters of the template, specify one or both of:
* current: The amount of memory that will be assigned to the VM.
* maxmemory: The maximum total of memory that the VM can have. Amount
over current will be used exclusively for memory hotplug
* cdrom: A volume name or URI to an ISO image
* networks *(optional)*: list of networks will be assigned to the new VM.
* interfaces *(optional)*: list of host network interfaces will be assigned to the new VM. Only applicable for s390x or s390 architecture.
* type: Type of host network interface. Type should be 'macvtap' for host network interface (Ethernet, Bond, VLAN) to be connected as direct MacVTap; or 'ovs' for openvswitch host network interface to be connected as virtual switch to a VM.
* name: The host network interface. It should be the host network interface (Ethernet, Bond, VLAN) for type 'macvtap' or host openvswitch bridge interface for type 'ovs'.
* mode *(optional)*: Only applicable for interface type macvtap, to indicates whether packets will be delivered directly to target device(bridge) or to the external bridge(vepa-capable bridge).
* bridge: If packets have a destination on the host from which they originated, they are delivered directly to the target. For direct delivery, both origin and destination devices need to be in bridge mode. If either the origin or destination is in vepa mode, VEPA-capable bridge is required.
* vepa: All packets are sent to the external bridge. If packets have a destination on the host from which they originated, the VEPA-capable bridge will return the packets to the host.
* disks: An array of requested disks with the following optional fields
(either *size* or *volume* must be specified):
* index: The device index
* size: The device size in GB
* volume: A volume name that contains the initial disk contents
* format: Format of the image. Valid formats: qcow, qcow2, qed, raw, vmdk, vpc.
* pool: Storage pool information
* name: URI of the storagepool where template allocates vm disk.
* path *(optional and only valid for s390x architecture)*: Either pool or path to store the virtual disks should be specified.
* graphics *(optional)*: A dict of graphics paramenters of this template
* type: The type of graphics. It can be VNC or spice or None.
* vnc: Graphical display using the Virtual Network
Computing protocol
* spice: Graphical display using the Simple Protocol for
Independent Computing Environments
* null: Graphics is disabled or type not supported
* listen: The network which the vnc/spice server listens on.
* cpu_info *(optional)*: CPU-specific information.
* maxvcpus *(optional)*: The maximum number of vCPUs that can be
assigned to the VM. If topology is specified, maxvcpus must be a
product of sockets, cores and threads.
* vcpus *(optional)*: The number of vCPUs assigned to the VM. Default
is 1, unless a CPU topology is specified. In that case, vcpus
must be a multiple of a product of cores and threads, and will
default to maxvcpus value.
* topology *(optional)*: Specify sockets, threads, and cores to run the
virtual CPU threads on. All three are required.
* sockets - The maximum number of sockets to use.
* cores - The number of cores per socket.
* threads - The number of threads per core.
**Actions (POST):**
* clone: clone a template from an existing template with different name.
It will provide a reasonable default name with "-cloneN" as suffix
for the new clone template. The "N" means the number of clone times.
### Collection: Storage Pools
**URI:** /plugins/kimchi/storagepools
**Methods:**
* **GET**: Retrieve a summarized list of all defined Storage Pools
* **POST**: Create a new Storage Pool
* name: The name of the Storage Pool. It corresponds to the VG name while
creating a logical storage pool from an existing VG.
* type: The type of the defined Storage Pool.
Supported types: 'dir', 'kimchi-iso', 'netfs', 'logical', 'iscsi', 'scsi'
* path: The path of the defined Storage Pool.
For 'kimchi-iso' pool refers to targeted deep scan path.
Pool types: 'dir', 'kimchi-iso'.
* source: Dictionary containing source information of the pool.
* host: IP or hostname of server for a pool backed from a remote host.
Pool types: 'netfs', 'iscsi'.
* path: Export path on NFS server for NFS pool.
Pool types: 'netfs'.
* devices: Array of devices to be used in the Storage Pool
Pool types: 'logical'.
* target: Target IQN of an iSCSI pool.
Pool types: 'iscsi'.
* port *(optional)*: Listening port of a remote storage server.
Pool types: 'iscsi'.
* auth *(optional)*: Storage back-end authentication information.
Pool types: 'iscsi'.
* username: Login username of the iSCSI target.
* password: Login password of the iSCSI target.
* adapter_name: SCSI host name.
* from_vg: Indicate if a logical pool will be created from an
existing VG or not.
### Resource: Storage Pool
**URI:** /plugins/kimchi/storagepools/*:name*
**Methods:**
* **GET**: Retrieve the full description of a Storage Pool
* name: The name of the Storage Pool
Used to identify the Storage Pool in this API
'kimchi_isos' is a reserved storage pool
which aggregates all ISO images
across all active storage pools into a single view.
* state: Indicates the current state of the Storage Pool
* active: The Storage Pool is ready for use
* inactive: The Storage Pool is not available
* path: The path of the defined Storage Pool
* type: The type of the Storage Pool
* capacity: The total space which can be used to store volumes
The unit is Bytes
* allocated: The amount of space which is being used to store volumes
The unit is Bytes
* available: Free space available for creating new volumes in the pool
* nr_volumes: The number of storage volumes for active pools, 0 for inactive pools
* autostart: Whether the storage pool will be enabled
automatically when the system boots
* persistent: True, when pool persist after a system reboot or be stopped.
All storage pools created by Kimchi are persistent.
* source: Source of the storage pool,
* addr: mount address of this storage pool(for 'netfs' pool)
* path: export path of this storage pool(for 'netfs' pool)
* **PUT**: Set whether the Storage Pool should be enabled automatically when the
system boots
* autostart: Toggle the autostart flag of the VM. This flag sets whether
the Storage Pool should be enabled automatically when the
system boots
* disks: Adds one or more disks to the pool (for 'logical' pool only)
* **DELETE**: Remove the Storage Pool
* **POST**: *See Storage Pool Actions*
**Actions (POST):**
* activate: Activate an inactive Storage Pool
* deactivate: Deactivate an active Storage Pool
### Collection: Storage Volumes
**URI:** /plugins/kimchi/storagepools/*:poolname*/storagevolumes
**Methods:**
* **GET**: Retrieve a summarized list of all defined Storage Volumes
in the defined Storage Pool
* **POST**: Create a new Storage Volume in the Storage Pool
The return resource is a task resource * See Resource: Task *
Only one of 'capacity', 'url' can be specified.
* name: The name of the Storage Volume
* capacity: The total space which can be used to store volumes
The unit is bytes
* format: The format of the defined Storage Volume. Only used when creating
a storage volume with 'capacity'.
* upload: True to start an upload process. False, otherwise.
Only used when creating a storage volume 'capacity' parameter.
* file: File to be uploaded, passed through form data
### Resource: Storage Volume
**URI:** /plugins/kimchi/storagepools/*:poolname*/storagevolumes/*:name*
**Methods:**
* **GET**: Retrieve the full description of a Storage Volume
* name: The name of the Storage Volume
Used to identify the Storage Volume in this API
* type: The type of the Storage Volume
* capacity: The total space which can be used to store data
The unit is Bytes
* allocation: The amount of space which is being used to store data
The unit is Bytes
* format: The format of the file or volume
* path: Full path of the volume on the host filesystem.
* os_distro *(optional)*: os distribution of the volume, for iso volume only.
* os_version *(optional)*: os version of the volume, for iso volume only.
* bootable *(optional)*: True if iso image is bootable and not corrupted.
* used_by: Name of vms which use this volume.
* isvalid: True if is a valid volume.
* has_permission: qemu/libvirt user has the right permission to
to use the image
* **DELETE**: Remove the Storage Volume
* **POST**: *See Storage Volume Actions*
* **PUT**: Upload storage volume chunk
* chunk_size: Chunk size of the slice in Bytes.
* chunk: Actual data of uploaded file
**Actions (POST):**
* resize: Resize a Storage Volume
* size: resize the total space which can be used to store data
The unit is bytes
* wipe: Wipe a Storage Volume
* clone: Clone a Storage Volume.
* pool: The name of the destination pool (optional).
* name: The new storage volume name (optional).
### Collection: Interfaces
**URI:** /plugins/kimchi/interfaces
**Methods:**
* **GET**: Retrieve a summarized list of current Interfaces
* Parameters: _inuse: Filter interfaces list with availability. Currently supports true | false.
'true' option lists interfaces used by virtual networks,'false' option lists all
interfaces which are not currently in use by virtual networks.
### Resource: Interface
**URI:** /plugins/kimchi/interfaces/*:name*
A interface represents available interface on host.
**Methods:**
* **GET**: Retrieve the full description of the Interface
* name: The name of the interface.
* status: The current status of the Interface.
* active: The interface is active.
* inactive: The interface is inactive.
* ipaddr: The ip address assigned to this interface in subnet.
* netmask: Is used to divide an IP address into subnets and specify the
networks available hosts
* type: The net device type of the interface.
* nic: Network interface controller that connects a computer to a
computer network
* vlan: A logical interface that represents a VLAN in all Layer 3
activities the unit may participate in
* bonding: The combination of network interfaces on one host for redundancy
and/or increased throughput.
* bridge: A network device that connects multiple network segments.
* module: the name of the kernel module used to load this interface. Returns
'unknown' if not applicable (ex: interface is a vlan).
* **POST**: *See Interface Actions*
**Actions (POST):**
*No actions defined*
### Collection: Networks
**URI:** /plugins/kimchi/networks
**Methods:**
* **GET**: Retrieve a summarized list of all defined Networks
* **POST**: Create a new Network
* name: The name of the Network
* connection: Specifies how this network should be connected to the other
networks visible to this host.
* isolated: Create a private, isolated virtual network.
* nat: Outgoing traffic will be routed through the host.
* macvtap: All traffic on this network will be bridged through the
specified interface.
* vepa: All traffic will be forward to one or more physical devices
directly connected to a VEPA-enabled switch.
* passthrough: A connection of this type uses a "direct" connection in
"passthrough" mode to connect each guest to the network.
Each guest will use one of the available physical
devices included in this network. Only one device can
be used for each guest - libvirt will keep track of which
interfaces are in use. Thus, a network of type 'passthrough'
with N devices will support the maximum of N guests
running at the same time.
* bridge: All traffic on this network will be bridged through a Linux
bridged, which is created upon specified interface in case
it is not already a Linux bridge.
* subnet *(optional)*: Network segment in slash-separated format with ip address and
prefix or netmask used to create nat network.
* interfaces *(optional)*: An array of network interfaces of the host.
For "macvtap" and "bridge" connections, only
one interface will be allowed in this array.
* vlan_id *(optional)*: VLAN tagging ID for the macvtap bridge network.
### Resource: Network
**URI:** /plugins/kimchi/networks/*:name*
**Methods:**
* **GET**: Retrieve the full description of a Network
* name: The name of the Network
Used to identify the Network in this API
* state: Indicates the current state of the Network
* active: The Network is ready for use
* inactive: The Network is not available
* autostart: Network autostart onboot
* in_use: Indicates ('true') if some guest is attached to this network and 'false' otherwise.
* vms: all vms attached to this network
* subnet: Network segment in slash-separated format with ip address and prefix
* dhcp: DHCP services on the virtual network is enabled.
* start: start boundary of a pool of addresses to be provided to DHCP clients.
* end: end boundary of a pool of addresses to be provided to DHCP clients.
* connection: Specifies how this network should be connected to the other networks
visible to this host.
* isolated: A private, isolated virtual network.
The VMs attached to it can not be reached by the systems
outside of this network and vice versa.
* nat: Outgoing traffic will be routed through the host.
The VM attached to it will have internet access via the host but
other computers will not be able to connect to the VM.
* bridge: Aggregated Public Network.
The VM that joines this network is seen as a peer on this network
and it may offer network services such as HTTP or SSH.
* interfaces: An array of bridge network interfaces that belongs to this network
All traffic on this network will be bridged through the first
interface. The interface is a bridge or ethernet/bonding device.
* persistent: If 'true', network will persist after a system reboot or be stopped.
All networks created by Kimchi are persistent.
* **DELETE**: Remove the Network
* **POST**: *See Network Actions*
* **PUT**: Update the Network. The network type cannot be changed.
* name *(optional)*: The new name of the Network
* subnet *(optional)*: Network segment in slash-separated format with ip address and prefix.
Applies only to NAT and isolated networks
* interfaces *(optional)*: An array of network interfaces that belongs to this network.
Applies only to bridge, macvtap and VEPA networks. For bridge and macvtap,
only one interface is allowed. For VEPA, you can specify multiple interfaces.
* vlan_id *(optional)*: VLAN tagging ID for the bridge network.
**Actions (POST):**
* activate: Activate an inactive Network
* deactivate: Deactivate an active Network
### Resource: Configuration
**URI:** /plugins/kimchi/config
Contains information about Kimchi configuration.
**Methods:**
* **GET**: Retrieve configuration information
* version: The version of the kimchi service
* with_spice_web_client: True is buit with spice web client support
* **POST**: *See Configuration Actions*
**Actions (POST):**
*No actions defined*
### Resource: Capabilities
**URI:** /plugins/kimchi/config/capabilities
Contains information about the host capabilities: iso streaming, screenshot
creation.
**Methods:**
* **GET**: Retrieve capabilities information
* libvirt_stream_protocols: list of which network protocols are accepted
for iso streaming by libvirt
* qemu_spice: True, if QEMU supports Spice; False, otherwise
* qemu_stream: True, if QEMU supports ISO streaming; False, otherwise
* screenshot: True, if libvirt stream functionality can create screenshot
file without problems; False, otherwise or None if the functionality was
not tested yet
* system_report_tool: True if the is some debug report tool installed on
the system; False, otherwise.
* update_tool: True if there is a compatible package manager for the
system; False, otherwise
* repo_mngt_tool: 'deb', 'yum' or None - when the repository management
tool is not identified
* **POST**: *See Configuration Actions*
**Actions (POST):**
*No actions defined*
### Collection: Storage Servers
**URI:** /plugins/kimchi/storageservers
**Methods:**
* **GET**: Retrieve a summarized list of used storage servers.
* Parameters:
* _target_type: Filter server list with given type, currently support
'netfs' and 'iscsi'.
### Resource: Storage Server
**URI:** /plugins/kimchi/storageservers/*:host*
**Methods:**
* **GET**: Retrieve description of a Storage Server
* host: IP or host name of storage server
* port: port of storage server, only for "iscsi"
### Collection: Storage Targets
**URI:** /plugins/kimchi/storageservers/*:name*/storagetargets
**Methods:**
* **GET**: Retrieve a list of available storage targets.
* Parameters:
* _target_type: Filter target list with given type, currently support
'netfs' and 'iscsi'.
* _server_port: Filter target list with given server port,
currently support 'iscsi'.
* Response: A list with storage targets information.
* host: IP or host name of storage server of this target.
* target_type: Type of storage target, supported: 'nfs'.
* target: Storage target path.
### Collection: Distros
**URI:** /plugins/kimchi/config/distros
**Methods:**
* **GET**: Retrieve a summarized list of all Distros
### Resource: Distro
**URI:** /plugins/kimchi/config/distros/*:name*
Contains information about the OS distribution.
**Methods:**
* **GET**: Retrieve a OS distribution information.
* name: The name of the Distro.
* os_distro: The operating system distribution.
* os_version: The version of the operating system distribution.
* path: A URI to an ISO image.
**Actions (POST):**
*No actions defined*
### Resource: Users
**URI:** /plugins/kimchi/users
List of available users.
**Methods:**
* **GET**: Retrieve list of available users.
* Parameters:
* _user_id: Validate whether user exists.
Essential for 'ldap' authentication.
### Resource: Groups
**URI:** /plugins/kimchi/groups
List of available groups.
**Methods:**
* **GET**: Retrieve list of available groups, only support 'pam' authentication.
### Collection: Devices
**URI:** /plugins/kimchi/host/devices
**Methods:**
* **GET**: Retrieves list of host devices (Node Devices).
* Parameters:
* _cap: Filter node device list with given node device capability.
To list Fibre Channel SCSI Host devices, use "_cap=fc_host".
Other available values are "fc_host", "net", "pci", "scsi",
"storage", "system", "usb" and "usb_device".
* _passthrough: Filter devices eligible to be assigned to guest
directly. Possible values are "true" and "false".
* _passthrough_affected_by: Filter the affected devices in the same
group of a certain directly assigned device.
The value should be the name of a device.
* _available_only: Filter to list only the host devices that are not
attached to a VM.
### Resource: Device
**URI:** /plugins/kimchi/host/devices/*:name*
**Methods:**
* **GET**: Retrieve information of a single host device.
* device_type: Type of the device, supported types are "net", "pci", "scsi",
"storage", "system", "usb" and "usb_device".
* name: The name of the device.
* path: Path of device in sysfs.
* parent: The name of the parent parent device.
* adapter: Host adapter information of a "scsi_host" or "fc_host" device.
* type: The capability type of the scsi_host device (fc_host, vport_ops).
* wwnn: The HBA Word Wide Node Name. Empty if pci device is not fc_host.
* wwpn: The HBA Word Wide Port Name. Empty if pci device is not fc_host.
* domain: Domain number of a "pci" device.
* bus: Bus number of a "pci" device.
* slot: Slot number of a "pci" device.
* function: Function number of a "pci" device.
* vendor: Vendor information of a "pci" device.
* id: Vendor id of a "pci" device.
* description: Vendor description of a "pci" device.
* product: Product information of a "pci" device.
* id: Product id of a "pci" device.
* description: Product description of a "pci" device.
* iommuGroup: IOMMU group number of a "pci" device. Would be None/null if
host does not enable IOMMU support.
* multifunction: True if the device belongs to a multi-function adapter.
* vga3d: True if the device is a 3D graphic card.
### Sub-collection: VMs with the device assigned.
**URI:** /plugins/kimchi/host/devices/*:name*/vmholders
* **GET**: Retrieve a summarized list of all VMs holding the device.
### Sub-resource: VM holder
**URI:** /plugins/kimchi/host/devices/*:name*/vmholders/*:vm*
* **GET**: Retrieve information of the VM which is holding the device
* name: The name of the VM.
* state: The power state of the VM. Could be "running" and "shutdown".
### Collection: Partitions
**URI:** /plugins/kimchi/host/partitions
**Methods:**
* **GET**: Retrieves a detailed list of all partitions of the host.
### Resource: Partition
**URI:** /plugins/kimchi/host/partitions/*:name*
**Methods:**
* **GET**: Retrieve the description of a single Partition:
* name: The name of the partition. Used to identify it in this API
* path: The device path of this partition.
* type: The type of the partition:
* part: a standard partition
* lvm: a partition that belongs to a lvm
* fstype: The file system type of the partition
* size: The total size of the partition, in bytes
* mountpoint: If the partition is mounted, represents the mountpoint.
Otherwise blank.
* available: false, if the partition is in use by system; true, otherwise.
### Collection: Volume Groups
**URI:** /plugins/kimchi/host/vgs
**Methods:**
* **GET**: Retrieves a detailed list of all volume groups in the host.
### Resource: Volume Group
**URI:** /plugins/kimchi/host/vgs/*:name*
**Methods:**
* **GET**: Retrieve the description of a single Volume Group:
* name: The volume group name. Used to identify it in this API.
* lvs: The logical volumes associated to this volume group.
* pvs: The phisical volumes associated to this volume group.
* free: Amount of free space in the volume group.
* size: Total size of the volume group.
### Simple Collection: OVSBridges
**URI:** /plugins/kimchi/ovsbridges
**Methods:**
* **GET**: Return list of OVS bridges of the host.
================================================
FILE: docs/CI.md
================================================
# How to setup Kimchi CI
Due to nested virtualization requirements, most of CI tools does not offer the minimum requirement to test kimchi. To solve this, we have an integration with [Google Cloud](https://cloud.google.com/), which create an instance and trigger the tests.
# Create a service account in GCP
To run the tests, its necessary to create a service account with the following iam roles:
* `roles/iam.serviceAccountUser`
* `roles/compute.admin`
Here is a script to help
```
# create account
$ gcloud iam service-accounts create [SA-NAME] \
--description "[SA-DESCRIPTION]" \
--display-name "[SA-DISPLAY-NAME]"
# create the key to be store as a secret
$ gcloud iam service-accounts keys create ~/key.json \
--iam-account [SA-NAME]@[PROJECT-ID].iam.gserviceaccount.com
# add iam roles
$ gcloud projects add-iam-policy-binding [PROJECT-ID] --member=serviceAccount:[SA-EMAIL] --role=roles/iam.serviceAccountUser
$ gcloud projects add-iam-policy-binding [PROJECT-ID] --member=serviceAccount:[SA-EMAIL] --role=roles/compute.admin
```
# Setting up secrets
The code for the CI is already at our repo, you just need to set some Github Actions Secrets, the procedure is described here: https://help.github.com/en/actions/automating-your-workflow-with-github-actions/creating-and-using-encrypted-secrets#creating-encrypted-secrets
1) Create a secret named `GCP_PROJECT` with the project ID
2) Create a secret named `GCP_SA_EMAIL` with the service account email
3) Create a secret named `GCP_SA_KEY` with the service account json with base64: `cat my-key.json | base64`
# Testing the CI
Create a PR to see if the PR works
================================================
FILE: docs/Makefile.am
================================================
#
# Kimchi
#
# Copyright IBM Corp, 2013-2016
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
docdir = $(datadir)/kimchi/doc
EXTRA_DIST = \
README.md.tmpl \
$(NULL)
FEDORA_DEV_DEPS=$(shell grep "^[^\#;]" ../fedora-dev-deps.list)
FEDORA_RUNTIME_DEPS=$(shell grep "^[^\#;]" ../fedora-runtime-deps.list)
UBUNTU_DEV_DEPS=$(shell grep "^[^\#;]" ../ubuntu-dev-deps.list)
UBUNTU_RUNTIME_DEPS=$(shell grep "^[^\#;]" ../ubuntu-runtime-deps.list)
OPENSUSE_DEV_DEPS=$(shell grep "^[^\#;]" ../opensuse-leap-dev-deps.list)
OPENSUSE_RUNTIME_DEPS=$(shell grep "^[^\#;]" ../opensuse-leap-runtime-deps.list)
all:
sed -e "s|[@]FEDORA_DEV_DEPS[@]|$(FEDORA_DEV_DEPS)|g" \
-e "s|[@]FEDORA_RUNTIME_DEPS[@]|$(FEDORA_RUNTIME_DEPS)|g" \
-e "s|[@]UBUNTU_DEV_DEPS[@]|`echo $(UBUNTU_DEV_DEPS)`|g" \
-e "s|[@]UBUNTU_RUNTIME_DEPS[@]|`echo $(UBUNTU_RUNTIME_DEPS)`|g" \
-e "s|[@]OPENSUSE_DEV_DEPS[@]|`echo $(OPENSUSE_DEV_DEPS)`|g" \
-e "s|[@]OPENSUSE_RUNTIME_DEPS[@]|`echo $(OPENSUSE_RUNTIME_DEPS)`|g" README.md.tmpl > README.md ;
dist_doc_DATA = $(wildcard *.md) $(wildcard *.png) $(NULL)
================================================
FILE: docs/README.md
================================================
* [What is Kimchi?](#what-is-kimchi)
* [Browser Support](https://github.com/kimchi-project/wok/#browser-support)
* [Desktop Browser Support](https://github.com/kimchi-project/wok/#desktop-browser-support)
* [Mobile Browser Support](https://github.com/kimchi-project/wok/#mobile-browser-support)
* [Linux Support](https://github.com/kimchi-project/wok/#linux-support)
* [Getting started](#getting-started)
* [JFrog Repositories](#jfrog-repositories)
* [Install Dependencies](#install-dependencies)
* [Build and Install](#build-and-install)
* [Starting up Wok](https://github.com/kimchi-project/wok/#starting-up-wok)
* [Troubleshooting](#troubleshooting)
* [Testing](#testing)
* [Usage](#usage)
* [Contributing to Kimchi Project](#contributing-to-kimchi-project)
# What is Kimchi?
Kimchi is an HTML5 based management tool for KVM. It is designed to make it as
easy as possible to get started with KVM and create your first guest.
Kimchi runs as a [Wok](https://github.com/kimchi-project/wok/wiki) plugin.
Kimchi manages KVM guests through libvirt. The management interface is accessed
over the web using a browser that supports HTML5.
# Getting Started
The latest packages available can be found at https://github.com/kimchi-project/kimchi/releases/latest
* If you want to use the repositories, check [JFrog Repositories](#jfrog-repositories)
If you prefer to install Kimchi from source code, follow the steps below!
# JFrog Repositories
Thanks to the initiative from JFrog and Google Cloud Platform to host our open source project for free, you can know
use the JFrog Repositories to install Kimchi and Wok. You may not find the packages in some distributions yet, we are working to make it available to all distributions.
Check all the available repositories here:
* **CentOS**: https://kimchi.jfrog.io/kimchi/centos/
* **Debian**: https://kimchi.jfrog.io/kimchi/debian
* **Fedora**: https://kimchi.jfrog.io/kimchi/fedora/
* **OpenSuse**: https://kimchi.jfrog.io/kimchi/opensuse/
* **RHEL**: https://kimchi.jfrog.io/kimchi/rhel/
* **SUSE**: https://kimchi.jfrog.io/kimchi/suse/
* **Ubuntu**: https://kimchi.jfrog.io/kimchi/ubuntu
* **Staging Area**: https://kimchi.jfrog.io/kimchi/staging/

## Install Dependencies
First of all, make sure to [Wok](https://github.com/kimchi-project/wok/#getting-started)
installed in your system.
To add Kimchi plugin, please make sure to have all the dependencies installed
before starting up the wokd service.
### Fedora
**Development Dependencies**
sudo dnf install -y gcc make autoconf automake git python3-pip python3-requests python3-mock gettext-devel rpm-build libxslt gcc-c++ python3-devel python3-pep8 python3-pyflakes rpmlint python3-pyyaml
sudo -H pip3 install -r requirements-dev.txt
**Runtime Dependencies**
sudo dnf install -y python3-configobj python3-lxml python3-magic python3-paramiko python3-ldap spice-html5 novnc qemu-kvm python3-libvirt python3-pyparted python3-ethtool python3-pillow python3-cherrypy python3-libguestfs libvirt libvirt-daemon-config-network iscsi-initiator-utils libguestfs-tools sos nfs-utils
sudo -H pip3 install -r requirements-FEDORA.txt
## Debian / Ubuntu
**Development Dependencies**
sudo apt install -y gcc make autoconf automake git python3-pip python3-requests python3-mock gettext pkgconf xsltproc python3-dev pep8 pyflakes python3-yaml
sudo -H pip3 install -r requirements-dev.txt
**Runtime Dependencies**
sudo apt install -y python3-configobj python3-lxml python3-magic python3-paramiko python3-ldap spice-html5 novnc qemu-kvm python3-libvirt python3-parted python3-ethtool python3-guestfs python3-pil python3-cherrypy3 libvirt0 libvirt-daemon-system libvirt-clients nfs-common sosreport open-iscsi libguestfs-tools libnl-route-3-dev
sudo -H pip3 install -r requirements-UBUNTU.txt
## openSUSE LEAP
**Development Dependencies**
sudo zypper install -y gcc make autoconf automake git python3-pip python3-requests python3-mock gettext-tools rpm-build libxslt-tools gcc-c++ python3-devel python3-pep8 python3-pyflakes rpmlint python3-PyYAML python3-distro
sudo -H pip3 install -r requirements-dev.txt
**Runtime Dependencies**
sudo zypper install -y python3-configobj python3-lxml python3-magic python3-paramiko python3-ldap spice-html5 novnc qemu-kvm python3-libvirt-python python3-ethtool python3-Pillow python3-CherryPy python3-libguestfs parted-devel libvirt libvirt-daemon-config-network open-iscsi guestfs-tools nfs-client gcc python3-devel
sudo -H pip3 install -r requirements-OPENSUSE-LEAP.txt
## Build and Install
sudo ./autogen.sh --system
make
# Optional if running from the source tree
sudo make install
# Or, to make installable .deb packages
make deb
# Or, for RPM packages
make rpm
If you are looking for stable versions, there are some packages available at https://github.com/kimchi-project/kimchi/releases
## Testing
make check-local
sudo make check
After all tests are executed, a summary will be displayed containing any
errors/failures which might have occurred.
## Usage
Connect your browser to https://localhost:8001. You should see a screen like:

By default, wok uses PAM to authenticate users so you can log in with the same username
and password that you would use to log in to the machine itself. Once logged in
you will see a screen like:

This shows you the list of running guests including a live screenshot of
the guest session. You can use the action buttons to shutdown the guests
or connect to the display in a new window.
To create a new guest, click on the "+" button in the upper right corner.
In Kimchi, all guest creation is done through templates.
You can view or modify templates by clicking on the Templates link in the
top navigation bar.
The template screen looks like:

From this view, you can change the parameters of a template or create a
new template using the "+" button in the upper right corner.
To create a template, you need an ISO or image file on your host or use a remote one.
If you are willing to use your own ISO, please copy it to out of box storage
pool (default path is: /var/lib/kimchi/isos).
## Troubleshooting
#### Server access
Please, check [Wok configuration](https://github.com/kimchi-project/wok/#troubleshooting)
if you are getting problems to access Wok server.
#### Missing Virtualization tab
If you follow all the steps to get Wok and Kimchi running and even though you can not see
the virtualization tab, it means something went wrong.
You can get more details about it when running wok with `--environment=dev`.
sudo python3 /usr/bin/wokd --environment=dev
There will be a message like:
Failed to import plugin wok.plugins.kimchi.Kimchi, error: XXX
If the log shows details of a missing dependency, like this:
Failed to import plugin wok.plugins.kimchi.Kimchi, error: No module named 'ipaddr'
You have to install this dependency manually due to changes in upstream. For that change ${RELEASE_NUMBER} to your version of the release:
sudo -H pip3 install https://github.com/kimchi-project/kimchi/raw/${RELEASE_NUMBER}/requirements-FEDORA.txt
#### NFS storage pool
Please, check the NFS export path permission is configured like below:
1. Export path need to be squashed as kvm gid and libvirt uid:
/my_export_path *(all_squash,anongid=, anonuid=,rw,sync)
So that root user can create volume with right user/group.
2. Set libvirt user and kvm group for export path, in order to make sure all
mapped user can get into the mount point.
# Contributing to Kimchi Project
There are a lof of ways to contribute to the Kimchi Project:
* Issues can be reported at [Github](https://github.com/kimchi-project/kimchi/issues)
* Patches are always welcome! Please, follow [these instructions](https://github.com/kimchi-project/kimchi/wiki/How-to-Contribute)
on how to send patches to the mailing list (kimchi-devel@ovirt.org) or submit a pull request.
Find more information about Wok Project at https://github.com/kimchi-project/kimchi/wiki
================================================
FILE: docs/README.md.tmpl
================================================
* [What is Kimchi?](#what-is-kimchi)
* [Browser Support](https://github.com/kimchi-project/wok/#browser-support)
* [Desktop Browser Support](https://github.com/kimchi-project/wok/#desktop-browser-support)
* [Mobile Browser Support](https://github.com/kimchi-project/wok/#mobile-browser-support)
* [Linux Support](https://github.com/kimchi-project/wok/#linux-support)
* [Getting started](#getting-started)
* [JFrog Repositories](#jfrog-repositories)
* [Install Dependencies](#install-dependencies)
* [Build and Install](#build-and-install)
* [Starting up Wok](https://github.com/kimchi-project/wok/#starting-up-wok)
* [Troubleshooting](#troubleshooting)
* [Testing](#testing)
* [Usage](#usage)
* [Contributing to Kimchi Project](#contributing-to-kimchi-project)
# What is Kimchi?
Kimchi is an HTML5 based management tool for KVM. It is designed to make it as
easy as possible to get started with KVM and create your first guest.
Kimchi runs as a [Wok](https://github.com/kimchi-project/wok/wiki) plugin.
Kimchi manages KVM guests through libvirt. The management interface is accessed
over the web using a browser that supports HTML5.
# Getting Started
The latest packages available can be found at https://github.com/kimchi-project/kimchi/releases/latest
* If you want to use the repositories, check [JFrog Repositories](#jfrog-repositories)
If you prefer to install Kimchi from source code, follow the steps below!
# JFrog Repositories
Thanks to the initiative from JFrog and Google Cloud Platform to host our open source project for free, you can know
use the JFrog Repositories to install Kimchi and Wok. You may not find the packages in some distributions yet, we are working to make it available to all distributions.
Check all the available repositories here:
* **CentOS**: https://kimchi.jfrog.io/kimchi/centos/
* **Debian**: https://kimchi.jfrog.io/kimchi/debian
* **Fedora**: https://kimchi.jfrog.io/kimchi/fedora/
* **OpenSuse**: https://kimchi.jfrog.io/kimchi/opensuse/
* **RHEL**: https://kimchi.jfrog.io/kimchi/rhel/
* **SUSE**: https://kimchi.jfrog.io/kimchi/suse/
* **Ubuntu**: https://kimchi.jfrog.io/kimchi/ubuntu
* **Staging Area**: https://kimchi.jfrog.io/kimchi/staging/

## Install Dependencies
First of all, make sure to [Wok](https://github.com/kimchi-project/wok/#getting-started)
installed in your system.
To add Kimchi plugin, please make sure to have all the dependencies installed
before starting up the wokd service.
### Fedora
**Development Dependencies**
sudo dnf install -y @FEDORA_DEV_DEPS@
sudo -H pip3 install -r requirements-dev.txt
**Runtime Dependencies**
sudo dnf install -y @FEDORA_RUNTIME_DEPS@
sudo -H pip3 install -r requirements-FEDORA.txt
## Debian / Ubuntu
**Development Dependencies**
sudo apt install -y @UBUNTU_DEV_DEPS@
sudo -H pip3 install -r requirements-dev.txt
**Runtime Dependencies**
sudo apt install -y @UBUNTU_RUNTIME_DEPS@
sudo -H pip3 install -r requirements-UBUNTU.txt
## openSUSE LEAP
**Development Dependencies**
sudo zypper install -y @OPENSUSE_DEV_DEPS@
sudo -H pip3 install -r requirements-dev.txt
**Runtime Dependencies**
sudo zypper install -y @OPENSUSE_RUNTIME_DEPS@
sudo -H pip3 install -r requirements-OPENSUSE-LEAP.txt
## Build and Install
sudo ./autogen.sh --system
make
# Optional if running from the source tree
sudo make install
# Or, to make installable .deb packages
make deb
# Or, for RPM packages
make rpm
If you are looking for stable versions, there are some packages available at https://github.com/kimchi-project/kimchi/releases
## Testing
make check-local
sudo make check
After all tests are executed, a summary will be displayed containing any
errors/failures which might have occurred.
## Usage
Connect your browser to https://localhost:8001. You should see a screen like:

By default, wok uses PAM to authenticate users so you can log in with the same username
and password that you would use to log in to the machine itself. Once logged in
you will see a screen like:

This shows you the list of running guests including a live screenshot of
the guest session. You can use the action buttons to shutdown the guests
or connect to the display in a new window.
To create a new guest, click on the "+" button in the upper right corner.
In Kimchi, all guest creation is done through templates.
You can view or modify templates by clicking on the Templates link in the
top navigation bar.
The template screen looks like:

From this view, you can change the parameters of a template or create a
new template using the "+" button in the upper right corner.
To create a template, you need an ISO or image file on your host or use a remote one.
If you are willing to use your own ISO, please copy it to out of box storage
pool (default path is: /var/lib/kimchi/isos).
## Troubleshooting
#### Server access
Please, check [Wok configuration](https://github.com/kimchi-project/wok/#troubleshooting)
if you are getting problems to access Wok server.
#### Missing Virtualization tab
If you follow all the steps to get Wok and Kimchi running and even though you can not see
the virtualization tab, it means something went wrong.
You can get more details about it when running wok with `--environment=dev`.
sudo python3 /usr/bin/wokd --environment=dev
There will be a message like:
Failed to import plugin wok.plugins.kimchi.Kimchi, error: XXX
If the log shows details of a missing dependency, like this:
Failed to import plugin wok.plugins.kimchi.Kimchi, error: No module named 'ipaddr'
You have to install this dependency manually due to changes in upstream. For that change ${RELEASE_NUMBER} to your version of the release:
sudo -H pip3 install https://github.com/kimchi-project/kimchi/raw/${RELEASE_NUMBER}/requirements-FEDORA.txt
#### NFS storage pool
Please, check the NFS export path permission is configured like below:
1. Export path need to be squashed as kvm gid and libvirt uid:
/my_export_path *(all_squash,anongid=, anonuid=,rw,sync)
So that root user can create volume with right user/group.
2. Set libvirt user and kvm group for export path, in order to make sure all
mapped user can get into the mount point.
# Contributing to Kimchi Project
There are a lof of ways to contribute to the Kimchi Project:
* Issues can be reported at [Github](https://github.com/kimchi-project/kimchi/issues)
* Patches are always welcome! Please, follow [these instructions](https://github.com/kimchi-project/kimchi/wiki/How-to-Contribute)
on how to send patches to the mailing list (kimchi-devel@ovirt.org) or submit a pull request.
Find more information about Wok Project at https://github.com/kimchi-project/kimchi/wiki
================================================
FILE: i18n.py
================================================
#
# Project Kimchi
#
# Copyright IBM Corp, 2015-2017
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
import gettext
_ = gettext.gettext
messages = {
'KCHAPI0001E': _('Unknown parameter %(value)s'),
'KCHAUTH0004E': _('User %(user_id)s not found with given LDAP settings.'),
'KCHPART0001E': _('Partition %(name)s does not exist in the host'),
'KCHDISK00001E': _('Error while accessing dev mapper device, %(err)s'),
'KCHDISK00002E': _('Block device not found.'),
'KCHDISK00003E': _('Block device %(device)s not found.'),
'KCHDISK00004E': _('Unable to retrieve LVM information. Details: %(err)s'),
'KCHDEVS0001E': _('Unknown "_cap" specified'),
'KCHDEVS0002E': _('"_passthrough" should be "true" or "false"'),
'KCHDEVS0003E': _('"_passthrough_affected_by" should be a device name string'),
'KCHDEVS0004E': _('"_available_only" should be "true" or "false"'),
'KCHDL0001E': _('Unable to find distro file: %(filename)s'),
'KCHDL0002E': _('Unable to parse distro file: %(filename)s. Make sure, it is a JSON file.'),
'KCHISCSI0001E': _('Unable to login to iSCSI host target %(portal)s. Details: %(err)s'),
'KCHISCSI0002E': _('Unable to login to iSCSI host %(host)s target %(target)s'),
'KCHISO0001E': _('Unable to find ISO file %(filename)s'),
'KCHISO0002E': _('The ISO file %(filename)s is not bootable'),
'KCHISO0003E': _('The ISO file %(filename)s does not have a valid El Torito boot record'),
'KCHISO0004E': _('Invalid El Torito validation entry in ISO %(filename)s'),
'KCHISO0005E': _('Invalid El Torito boot indicator in ISO %(filename)s'),
'KCHISO0006E': _('Unexpected volume type for primary volume in ISO %(filename)s'),
'KCHISO0007E': _('Bad format while reading volume descriptor in ISO %(filename)s'),
'KCHISO0008E': _("The hypervisor doesn't have permission to use this ISO %(filename)s. "
'Consider moving it under /var/lib/libvirt, or set the search permission '
"to file access control lists for '%(user)s' user if possible, or add the "
"'%(user)s' to the ISO path group, or (not recommended) 'chmod -R o+x 'path_to_iso'."
'Details: %(err)s'),
'KCHISO0009E': _('Unable to access remote ISO. Details: %(err)s'),
'KCHIMG0001E': _('Error probing image OS information: %(err)s'),
'KCHIMG0003E': _('Unable to read image file %(filename)s'),
'KCHIMG0004E': _('Image file must be an existing file on system. %(filename)s is not a valid input.'),
'KCHVM0001E': _('Virtual machine %(name)s already exists'),
'KCHVM0002E': _('Virtual machine %(name)s does not exist'),
'KCHVM0004E': _('Unable to retrieve screenshot for stopped virtual machine %(name)s'),
'KCHVM0005E': _('Remote ISO image is not supported by this server.'),
'KCHVM0006E': _('Screenshot is not supported on virtual machine %(name)s'),
'KCHVM0007E': _('Unable to create virtual machine %(name)s. Details: %(err)s'),
'KCHVM0008E': _('Unable to update virtual machine %(name)s. Details: %(err)s'),
'KCHVM0009E': _('Unable to retrieve virtual machine %(name)s. Details: %(err)s'),
'KCHVM0010E': _('Unable to connect to powered off virtual machine %(name)s.'),
'KCHVM0011E': _('Virtual machine name must be a string without slashes (/)'),
'KCHVM0012E': _('Invalid template URI %(value)s specified for virtual machine'),
'KCHVM0013E': _('Invalid storage pool URI %(value)s specified for virtual machine'),
'KCHVM0014E': _('Supported virtual machine graphics are Spice or VNC'),
'KCHVM0015E': _('Graphics address to listen on must be IPv4 or IPv6'),
'KCHVM0016E': _('Specify a template to create a virtual machine from'),
'KCHVM0019E': _('Unable to start virtual machine %(name)s. Details: %(err)s'),
'KCHVM0020E': _('Unable to power off virtual machine %(name)s. Details: %(err)s'),
'KCHVM0021E': _('Unable to delete virtual machine %(name)s. Details: %(err)s'),
'KCHVM0022E': _('Unable to reset virtual machine %(name)s. Details: %(err)s'),
'KCHVM0023E': _('User name list must be an array'),
'KCHVM0024E': _('User name must be a string'),
'KCHVM0025E': _('Group name list must be an array'),
'KCHVM0026E': _('Group name must be a string'),
'KCHVM0027E': _("User(s) '%(users)s' do not exist"),
'KCHVM0028E': _("Group(s) '%(groups)s' do not exist"),
'KCHVM0029E': _('Unable to shutdown virtual machine %(name)s. Details: %(err)s'),
'KCHVM0031E': _('The guest console password must be a string.'),
'KCHVM0032E': _('The life time for the guest console password must be a number.'),
'KCHVM0033E': _("Virtual machine '%(name)s' must be stopped before cloning it."),
'KCHVM0034E': _("Insufficient disk space to clone virtual machine '%(name)s'"),
'KCHVM0035E': _("Unable to clone VM '%(name)s'. Details: %(err)s"),
'KCHVM0036E': _('Invalid operation for non-persistent virtual machine %(name)s'),
'KCHVM0037E': _("Cannot suspend VM '%(name)s' because it is not running."),
'KCHVM0038E': _("Unable to suspend VM '%(name)s'. Details: %(err)s"),
'KCHVM0039E': _("Cannot resume VM '%(name)s' because it is not paused."),
'KCHVM0040E': _("Unable to resume VM '%(name)s'. Details: %(err)s"),
'KCHVM0041E': _('Memory assigned is higher then the maximum allowed in the host: %(maxmem)sMib.'),
'KCHVM0042E': _("Guest '%(name)s' does not support live memory update. Please, with the guest offline, set Maximum Memory with a value greater then Memory to enable this feature."),
'KCHVM0043E': _('Only increase memory is allowed in active VMs'),
'KCHVM0045E': _('There are not enough free slots to add a new memory device.'),
'KCHVM0046E': _("Host's libvirt or qemu version does not support memory devices and memory hotplug. Libvirt must be >= 1.2.14 and QEMU must be >= 2.1."),
'KCHVM0047E': _('Error attaching memory device. Details: %(error)s'),
'KCHVM0048E': _('Cannot start %(name)s. Virtual machine is already running.'),
'KCHVM0049E': _('Cannot power off %(name)s. Virtual machine is shut off.'),
'KCHVM0050E': _('Cannot shutdown %(name)s. Virtual machine is shut off.'),
'KCHVM0051E': _('Cannot reset %(name)s. Virtual machine is already shut off.'),
'KCHVM0052E': _('Boot order must be a list. Devices accepted: hd, cdrom, fd or network.'),
'KCHVM0053E': _('Bootmenu must be boolean. Values accepted: true of false.'),
'KCHVM0054E': _('Graphic type not valid. Values accepted: vnc or spice.'),
'KCHVM0055E': _('Migrate to localhost %(host)s is not allowed.'),
'KCHVM0056E': _('To migrate a virtual machine to the remote host %(host)s the user %(user)s must have password-less login to the remote host.'),
'KCHVM0057E': _('Can not migrate virtual machine %(name)s when its in %(state)s state.'),
'KCHVM0058E': _('Failed to migrate virtual machine %(name)s due error: %(err)s'),
'KCHVM0059E': _('User name of the remote server must be a string.'),
'KCHVM0060E': _('Destination host of the migration must be a string.'),
'KCHVM0061E': _('Unable to create file %(path)s at %(host)s using user %(user)s.'),
'KCHVM0062E': _('Unable to read disk size of %(path)s, error: %(error)s'),
'KCHVM0063E': _('Unable to create disk image %(path)s at %(host)s using user %(user)s. Error: %(error)s'),
'KCHVM0064E': _('Unable to migrate virtual machine to remote host %(host)s with arch %(destarch)s using localhost with arch %(srcarch)s.'),
'KCHVM0065E': _('Unable to migrate virtual machine to remote host %(host)s with hypervisor %(desthyp)s because localhost uses hypervisor %(srchyp)s.'),
'KCHVM0066E': _('Unable to determine remote host hypervisor and architecture. Error: %(error)s'),
'KCHVM0067E': _('Unable to migrate virtual machine: subcores per core setting from localhostand remote host %(host)s differs.'),
'KCHVM0068E': _('Unable to setup password-less login at remote host %(host)s using user %(user)s. Error: %(error)s'),
'KCHVM0069E': _('Password field must be a string.'),
'KCHVM0070E': _("Error creating local host ssh rsa key of user 'root'."),
'KCHVM0071E': _('%(param)s value (%(mem)sMiB) must be aligned to %(alignment)sMiB.'),
'KCHVM0073E': _('Unable to update the following parameters while the VM is offline: %(params)s'),
'KCHVM0074E': _('Unable to update the following parameters while the VM is online: %(params)s'),
'KCHVM0076E': _('VM %(name)s must have serial and console defined to open a web serial console'),
'KCHVM0077E': _('Impossible to get the serial console of %(name)s'),
'KCHVM0078E': _('Memory or Maximum Memory value is higher than amount supported by the host: %(memHost)sMiB.'),
'KCHVM0079E': _('Memory or Maximum Memory value is higher than maximum amount recommended: %(value)sTiB'),
'KCHVM0080E': _('Cannot update Maximum Memory when guest is running.'),
'KCHVM0081E': _('Impossible to create %(dir)s directory.'),
'KCHVM0082E': _('Either the guest %(name)s did not start to listen to the serial or it is not configured to use the serial console.'),
'KCHVM0083E': _('Unable to retrieve Virt Viewer file for stopped virtual machine %(name)s'),
'KCHVM0084E': _('Error occured while retrieving the Virt Viewer file for virtual machine %(name)s : %(err)s'),
'KCHVM0085E': _('Virtual machine title must be a string'),
'KCHVM0086E': _('Virtual machine description must be a string'),
'KCHVM0087E': _('console parameter is only supported for s390x/s390 architecture.'),
'KCHVM0088E': _('invalid console type, supported types are sclp/virtio.'),
'KCHVM0089E': _('Unable to setup password-less login at remote host %(host)s using user %(user)s: remote directory %(sshdir)s does not exist.'),
'KCHVM0090E': _('Unable to create a password-less libvirt connection to the remote libvirt daemon at host %(host)s with the user %(user)s. Please verify the remote server libvirt configuration. More information: http://libvirt.org/auth.html .'),
'KCHVM0091E': _("'enable_rdma' must be of type boolean (true or false)."),
'KCHVMHDEV0001E': _('VM %(vmid)s does not contain directly assigned host device %(dev_name)s.'),
'KCHVMHDEV0002E': _('The host device %(dev_name)s is not allowed to directly assign to VM.'),
'KCHVMHDEV0003E': _('No IOMMU groups found. Host PCI pass through needs IOMMU group to function correctly. '
'Please enable Intel VT-d or AMD IOMMU in your BIOS, then verify the Kernel is compiled with IOMMU support. '
"For Intel CPU, add 'intel_iommu=on' to GRUB_CMDLINE_LINUX parameter in /etc/default/grub file. "
"For AMD CPU, add 'iommu=pt iommu=1'."),
'KCHVMHDEV0004E': _('"name" should be a device name string'),
'KCHVMHDEV0005E': _('The device %(name)s is probably in use by the host. Unable to attach it to the guest.'),
'KCHVMHDEV0006E': _('Hot-(un)plug of device %(name)s is not supported.'),
'KCHVMHDEV0007E': _('Failed to attach %(device)s to %(vm)s'),
'KCHVMHDEV0008E': _('VM %(vmid)s does not have a USB controller to accept PCI hotplug.'),
'KCHVMIF0001E': _('Interface %(iface)s does not exist in virtual machine %(name)s'),
'KCHVMIF0002E': _('Network %(network)s specified for virtual machine %(name)s does not exist'),
'KCHVMIF0004E': _('Supported virtual machine interfaces type are network, ovs and macvtap.Type ovs and macvtap are only supported for s390x/s390 architecture.'),
'KCHVMIF0005E': _('Network name for virtual machine interface must be a string'),
'KCHVMIF0006E': _('Invalid network model card specified for virtual machine interface'),
'KCHVMIF0007E': _('Specify type and network to add a new virtual machine interface'),
'KCHVMIF0008E': _('MAC Address must respect this format FF:FF:FF:FF:FF:FF'),
'KCHVMIF0009E': _('MAC Address %(mac)s already exists in virtual machine %(name)s'),
'KCHVMIF0010E': _('Invalid MAC Address'),
'KCHVMIF0011E': _('Cannot change MAC address of a running virtual machine'),
'KCHVMIF0012E': _('Type macvtap and ovs are only supported on s390x/s390 architecture.'),
'KCHVMIF0013E': _('Source attribute is only supported on s390x/s390 architecture.'),
'KCHVMIF0014E': _('If source is provided, only type supported are macvtap and ovs.'),
'KCHVMIF0015E': _('For type macvtap and ovs, source has to be provided'),
'KCHVMIF0016E': _('Source name for virtual machine interface must be string'),
'KCHVMIF0017E': _('Invalid source mode. Valid options are: bridge or vepa.'),
'KCHTMPL0001E': _('Template %(name)s already exists'),
'KCHTMPL0002E': _('Source media %(path)s not found'),
'KCHTMPL0003E': _("Network '%(network)s' specified for template %(template)s does not exist"),
'KCHTMPL0004E': _('Storage pool %(pool)s specified for template %(template)s does not exist'),
'KCHTMPL0006E': _("Invalid parameter '%(param)s' specified for CDROM."),
'KCHTMPL0007E': _('Network %(network)s specified for template %(template)s is not active'),
'KCHTMPL0008E': _('Template name must be a string'),
'KCHTMPL0009E': _('Template icon must be a path to the image'),
'KCHTMPL0010E': _('Template distribution must be a string'),
'KCHTMPL0011E': _('Template distribution version must be a string'),
'KCHTMPL0012E': _('The number of CPUs must be an integer greater than 0'),
'KCHTMPL0013E': _('Amount of memory and maximum memory (MB) must be an integer greater than 512'),
'KCHTMPL0014E': _('Template CDROM must be a local or remote ISO file'),
'KCHTMPL0015E': _('Invalid storage pool URI %(value)s specified for template'),
'KCHTMPL0016E': _('Specify a path to source media (ISO, disk or remote ISO) to create a template'),
'KCHTMPL0017E': _('All networks for the template must be specified in a list.'),
'KCHTMPL0018E': _('Specify a volume to a template when storage pool is iSCSI or SCSI'),
'KCHTMPL0019E': _('The volume %(volume)s is not in storage pool %(pool)s'),
'KCHTMPL0020E': _('Unable to create template due error: %(err)s'),
'KCHTMPL0021E': _('Unable to delete template due error: %(err)s'),
'KCHTMPL0022E': _('Disk size must be an integer greater than 1GB.'),
'KCHTMPL0024E': _('Cannot identify base image %(path)s format'),
'KCHTMPL0026E': _('When specifying CPU topology, each element must be an integer greater than zero.'),
'KCHTMPL0027E': _('Invalid disk image format. Valid formats: qcow, qcow2, qed, raw, vmdk, vpc.'),
'KCHTMPL0028E': _("When setting template disks, following parameters are required: 'index', 'pool name', 'format', 'size' or 'volume' (for scsi/iscsi pools)"),
'KCHTMPL0029E': _("Disk format must be 'raw', for logical, iscsi, and scsi pools."),
'KCHTMPL0030E': _("Memory expects an object with one or both parameters: 'current' and 'maxmemory'"),
'KCHTMPL0031E': _('Memory value (%(mem)sMiB) must be equal or lesser than maximum memory value (%(maxmem)sMiB)'),
'KCHTMPL0032E': _('Unable to update template due error: %(err)s'),
'KCHTMPL0033E': _("Parameter 'disks' requires at least one disk object"),
'KCHTMPL0034E': _("Invalid interface type. Type should be 'macvtap' for host network interface (Ethernet, Bond, VLAN) to be connected as direct MacVTap or 'ovs' for openvswitch host network interface to be connected as virtual switch to a VM."),
'KCHTMPL0035E': _('Interface name should be string.'),
'KCHTMPL0036E': _('Invalid interface mode. Valid options are: bridge or vepa.'),
'KCHTMPL0037E': _("Interfaces should be list of interfaces. Each interface should have name, type and mode(optional, only applicable for interfcae type 'macvtap'."),
'KCHTMPL0038E': _("Interface expects an object with parameters: 'name', 'type' and 'mode'. Name should be name of host network interface (Ethernet, Bond, VLAN) for type 'macvtap' or the name of host openvswitch bridge interface for type 'ovs'. Mode (optional) is only applicable for interface type 'macvtap' to indicates whether packets will be delivered directly to target device (bridge) or to the external bridge (vepa-capable bridge)."),
'KCHTMPL0039E': _('Interfaces parameter only supported on s390x or s390 architecture.'),
'KCHTMPL0040E': _('Storage without libvirt pool is not supported on this architecture'),
'KCHTMPL0041E': _('Error while creating the virtual disk for the guest. Details: %(err)s'),
'KCHTMPL0042E': _("When setting template disks without libvirt, following parameters are required: 'index', 'format', 'path', 'size'"),
'KCHTMPL0043E': _('console parameter is only supported for s390x/s390 architecture.'),
'KCHTMPL0044E': _('invalid console type, supported types are sclp/virtio.'),
'KCHPOOL0001E': _('Storage pool %(name)s already exists'),
'KCHPOOL0002E': _('Storage pool %(name)s does not exist'),
'KCHPOOL0004E': _('Specify %(item)s in order to create the storage pool %(name)s'),
'KCHPOOL0005E': _('Unable to delete active storage pool %(name)s'),
'KCHPOOL0006E': _('Unable to list storage pools. Details: %(err)s'),
'KCHPOOL0007E': _('Unable to create storage pool %(name)s. Details: %(err)s'),
'KCHPOOL0009E': _('Unable to activate storage pool %(name)s. Details: %(err)s'),
'KCHPOOL0010E': _('Unable to deactivate storage pool %(name)s. Details: %(err)s'),
'KCHPOOL0011E': _('Unable to delete storage pool %(name)s. Details: %(err)s'),
'KCHPOOL0012E': _('Unable to create NFS Pool as export path %(path)s may block during mount'),
'KCHPOOL0013E': _('Unable to create NFS Pool as export path %(path)s mount failed'),
'KCHPOOL0014E': _('Unsupported storage pool type: %(type)s'),
'KCHPOOL0015E': _('Error while retrieving storage pool XML to %(pool)s'),
'KCHPOOL0016E': _('Storage pool name must be a string without slashes (/)'),
'KCHPOOL0017E': _('Supported storage pool types are dir, netfs, logical, iscsi, isci and kimchi-iso'),
'KCHPOOL0018E': _('Storage pool path must be a string'),
'KCHPOOL0019E': _('Storage pool host must be a IP or hostname'),
'KCHPOOL0020E': _('Storage pool device must be the absolute path to the block device'),
'KCHPOOL0021E': _('Storage pool devices parameter must be a list'),
'KCHPOOL0022E': _('Target IQN of an iSCSI pool must be a string'),
'KCHPOOL0023E': _('Port of a remote storage server must be an integer between 1 and 65535'),
'KCHPOOL0024E': _('iSCSI target username must be a string'),
'KCHPOOL0025E': _('iSCSI target password must be a string'),
'KCHPOOL0026E': _('Specify name and type to create a storage pool'),
'KCHPOOL0027E': _('%(disk)s is not a valid disk/partition. Could not add it to the pool %(pool)s.'),
'KCHPOOL0028E': _('Unable to extend logical pool %(pool)s. Details: %(err)s'),
'KCHPOOL0029E': _('The parameter disks only can be updated for logical storage pool.'),
'KCHPOOL0030E': _('The SCSI host adapter name must be a string.'),
'KCHPOOL0031E': _('The storage pool kimchi_isos is reserved for internal use'),
'KCHPOOL0032E': _('Unable to activate NFS storage pool %(name)s. NFS server %(server)s is unreachable.'),
'KCHPOOL0033E': _('Unable to deactivate NFS storage pool %(name)s. NFS server %(server)s is unreachable.'),
'KCHPOOL0034E': _('Unable to deactivate pool %(name)s as it is associated with some templates'),
'KCHPOOL0035E': _('Unable to delete pool %(name)s as it is associated with some templates'),
'KCHPOOL0036E': _("A volume group named '%(name)s' already exists. Please, choose another name to create the logical pool."),
'KCHPOOL0037E': _('Unable to update database with deep scan information due error: %(err)s'),
'KCHPOOL0038E': _("No volume group '%(name)s' found. Please, specify an existing volume group to create the logical pool from."),
'KCHPOOL0039E': _('Unable to delete pool %(name)s as it is associated with guests: %(vms)s'),
'KCHVOL0001E': _('Storage volume %(name)s already exists'),
'KCHVOL0002E': _('Storage volume %(name)s does not exist in storage pool %(pool)s'),
'KCHVOL0003E': _('Unable to create storage volume %(volume)s because storage pool %(pool)s is not active'),
'KCHVOL0004E': _('Specify %(item)s in order to create storage volume %(volume)s'),
'KCHVOL0006E': _('Unable to list storage volumes because storage pool %(pool)s is not active'),
'KCHVOL0007E': _('Unable to create storage volume %(name)s in storage pool %(pool)s. Details: %(err)s'),
'KCHVOL0009E': _('Unable to wipe storage volumes %(name)s. Details: %(err)s'),
'KCHVOL0010E': _('Unable to delete storage volume %(name)s. Details: %(err)s'),
'KCHVOL0011E': _('Unable to resize storage volume %(name)s. Details: %(err)s'),
'KCHVOL0012E': _('Storage type %(type)s does not support volume create and delete'),
'KCHVOL0013E': _('Storage volume name must be a string'),
'KCHVOL0014E': _('Storage volume allocation must be an integer number'),
'KCHVOL0015E': _('Storage volume format not supported. Valid formats: qcow, qcow2, qed, raw, vmdk, vpc.'),
'KCHVOL0016E': _('Storage volume requires a volume name'),
'KCHVOL0017E': _('Unable to update database with storage volume information due error: %(err)s'),
'KCHVOL0018E': _('Only one of parameter %(param)s can be specified'),
'KCHVOL0019E': _('Create volume from %(param)s is not supported'),
'KCHVOL0020E': _('Storage volume capacity must be an integer number.'),
'KCHVOL0021E': _('Storage volume URL must be http://, https://, ftp:// or ftps://.'),
'KCHVOL0022E': _('Unable to access file %(url)s. Please, check it.'),
'KCHVOL0023E': _("Unable to clone storage volume '%(name)s' in pool '%(pool)s'. Details: %(err)s"),
'KCHVOL0024E': _('Specify chunk data and its size to upload a file.'),
'KCHVOL0025E': _("In order to upload a storage volume, specify the 'upload' parameter."),
'KCHVOL0026E': _('Unable to upload chunk data as it does not match with requested chunk size.'),
'KCHVOL0027E': _('The storage volume %(vol)s is not under an upload process.'),
'KCHVOL0028E': _('The upload chunk data will exceed the storage volume size.'),
'KCHVOL0029E': _('Unable to upload chunk data to storage volume. Details: %(err)s.'),
'KCHIFACE0001E': _('Interface %(name)s does not exist'),
'KCHIFACE0002E': _('Failed to list interfaces. Invalid _inuse parameter. Supported options for _inuse are: %(supported_inuse)s'),
'KCHNET0001E': _('Network %(name)s already exists'),
'KCHNET0002E': _('Network %(name)s does not exist'),
'KCHNET0003E': _('Subnet %(subnet)s specified for network %(network)s is not valid.'),
'KCHNET0004E': _('Specify a network interface to create bridged or macvtap networks.'),
'KCHNET0005E': _('Unable to delete or update active network %(name)s'),
'KCHNET0006E': _('Interface %(iface)s specified for network %(network)s is already in use'),
'KCHNET0007E': _('Interface should be bare NIC, bonding or bridge device.'),
'KCHNET0008E': _('Unable to create or update network %(name)s. Details: %(err)s'),
'KCHNET0009E': _("Unable to find a free IP address for network '%(name)s'"),
'KCHNET0010E': _('The interface %(iface)s already exists.'),
'KCHNET0011E': _("Network name must be a string without slashes (/) or quotes (\")"),
'KCHNET0012E': _('Supported network types are isolated, NAT, macvtap, bridge, vepa and passthrough.'),
'KCHNET0013E': _('Network subnet must be a string with IP address and prefix or netmask'),
'KCHNET0014E': _('Network interfaces must be an array.'),
'KCHNET0015E': _('Network VLAN ID must be an integer between 1 and 4094'),
'KCHNET0016E': _('Specify name and type to create a Network'),
'KCHNET0017E': _('Unable to delete or update network %(name)s as it is linked to some virtual machines (%(vms)s) and/or templates (%(tmpls)s).'),
'KCHNET0018E': _('Unable to deactivate network %(name)s as it is linked to are some virtual machines (%(vms)s) and/or templates (%(tmpls)s).'),
'KCHNET0019E': _('Bridge device %(name)s can not be the trunk device of a VLAN.'),
'KCHNET0020E': _('Failed to activate interface %(iface)s: %(err)s.'),
'KCHNET0021E': _('Failed to activate interface %(iface)s. Please check the physical link status.'),
'KCHNET0022E': _('Failed to start network %(name)s. Details: %(err)s'),
'KCHNET0024E': _('Unable to redefine interface %(name)s. Details: %(err)s'),
'KCHNET0025E': _('Unable to create bridge %(name)s. Details: %(err)s'),
'KCHNET0027E': _('Unable to create bridge with NetworkManager enabled. Disable it and try again.'),
'KCHNET0028E': _('Interface should be bare NIC or bonding.'),
'KCHNET0029E': _('Network interfaces parameter must contain at least one interface.'),
'KCHNET0030E': _("Only one interface is allowed for 'bridge' and 'macvtap' networks."),
'KCHNET0031E': _('Subnet is not a valid parameter for this type of virtual network.'),
'KCHNET0032E': _('VLAN ID and interfaces are not valid parameters for this type of virtual network.'),
'KCHSR0001E': _('Storage server %(server)s was not used by Kimchi'),
'KCHDISTRO0001E': _("Distro '%(name)s' does not exist"),
'KCHHOST0003E': _("Node device '%(name)s' not found"),
'KCHHOST0004E': _('Conflicting flag filters specified.'),
'KCHUTILS0003E': _('Unable to choose a virtual machine name'),
'KCHUTILS0006E': _('Cannot upgrade objectstore data.'),
'KCHVMSTOR0002E': _("Invalid storage type. Types supported: 'cdrom', 'disk'"),
'KCHVMSTOR0003E': _("The path '%(value)s' is not a valid local/remote path for the device"),
'KCHVMSTOR0006E': _('Only CDROM path can be update.'),
'KCHVMSTOR0007E': _('The storage device %(dev_name)s does not exist in the virtual machine %(vm_name)s'),
'KCHVMSTOR0008E': _('Error while creating new storage device: %(error)s'),
'KCHVMSTOR0009E': _('Error while updating storage device: %(error)s'),
'KCHVMSTOR0010E': _('Error while removing storage device: %(error)s'),
'KCHVMSTOR0011E': _('Do not support IDE device hot plug'),
'KCHVMSTOR0012E': _('Specify type and path or type and pool/volume to add a new virtual machine disk'),
'KCHVMSTOR0013E': _('Specify path to update virtual machine disk'),
'KCHVMSTOR0014E': _('Controller type %(type)s limitation of %(limit)s devices reached'),
'KCHVMSTOR0015E': _('Cannot retrieve disk path information for given pool/volume: %(error)s'),
'KCHVMSTOR0016E': _('Volume already in use by other virtual machine.'),
'KCHVMSTOR0017E': _('Only one of path or pool/volume can be specified to add a new virtual machine disk'),
'KCHVMSTOR0018E': _('Volume chosen with format %(format)s does not fit in the storage type %(type)s'),
'KCHVMSTOR0019E': _('On s390x arch one of pool, path of dir_path must be specified'),
'KCHVMSTOR0020E': _("On s390x arch 'format' must be specified while attaching disk to virtual machine"),
'KCHVMSTOR0021E': _('Virtual disk already exists on the system: %(disk_path)s'),
'KCHSNAP0002E': _("Unable to create snapshot '%(name)s' on virtual machine '%(vm)s'. Details: %(err)s"),
'KCHSNAP0003E': _("Snapshot '%(name)s' does not exist on virtual machine '%(vm)s'."),
'KCHSNAP0004E': _("Unable to retrieve snapshot '%(name)s' on virtual machine '%(vm)s'. Details: %(err)s"),
'KCHSNAP0005E': _("Unable to list snapshots on virtual machine '%(vm)s'. Details: %(err)s"),
'KCHSNAP0006E': _("Unable to delete snapshot '%(name)s' on virtual machine '%(vm)s'. Details: %(err)s"),
'KCHSNAP0008E': _("Unable to retrieve current snapshot of virtual machine '%(vm)s'. Details: %(err)s"),
'KCHSNAP0009E': _("Unable to revert virtual machine '%(vm)s' to snapshot '%(name)s'. Details: %(err)s"),
'KCHSNAP0010E': _("Unable to create snapshot of virtual machine '%(vm)s' because it contains a disk with format '%(format)s'; only 'qcow2' is supported."),
'KCHCPUINF0001E': _('The number of vCPUs must be less than or equal the maximum number of vCPUs specified.'),
'KCHCPUINF0002E': _('When CPU topology is defined, maximum number of vCPUs must be a product of sockets, cores, and threads.'),
'KCHCPUINF0003E': _('This host (or current configuration) does not allow CPU topology.'),
'KCHCPUINF0004E': _('The maximum number of vCPUs is too large for this system.'),
'KCHCPUINF0005E': _("When CPU topology is defined, CPUs must be a multiple of the 'threads' number defined."),
'KCHCPUINF0007E': _('When CPU topology is specified, sockets, cores and threads are required paramaters.'),
'KCHCPUINF0008E': _("Parameter 'cpu_info' expects an object with fields among: 'vcpus', 'maxvcpus', 'topology'."),
'KCHCPUINF0009E': _("Parameter 'topology' expects an object with fields among: 'sockets', 'cores', 'threads'."),
'KCHCPUHOTP0001E': _('Unable to update Max CPU or CPU topology when guest is running.'),
'KCHCPUHOTP0002E': _('Unable to hot plug/unplug CPUs. Details: %(err)s'),
'KCHLVMS0001E': _('Invalid volume group name parameter: %(name)s.'),
'KCHCONN0001E': _('Unable to establish connection with libvirt. Please check your libvirt URI which is often defined in /etc/libvirt/libvirt.conf'),
'KCHCONN0002E': _('Libvirt service is not active. Please start the libvirt service in your host system.'),
'KCHEVENT0001E': _('Failed to register the default event implementation.'),
'KCHEVENT0002E': _('Failed to register timeout event.'),
'KCHEVENT0003E': _('Failed to Run the default event implementation.'),
'KCHEVENT0004W': _("I/O error on guest '%(vm)s': storage pool out of space for %(devAlias)s (%(srcPath)s)."),
# These messages (ending with L) are for user log purposes
'KCHNET0001L': _("Create virtual network '%(name)s' type '%(connection)s'"),
'KCHNET0002L': _("Remove virtual network '%(ident)s'"),
'KCHNET0003L': _("Update virtual network '%(ident)s'"),
'KCHNET0004L': _("Activate virtual network '%(ident)s'"),
'KCHNET0005L': _("Deactivate virtual network '%(ident)s'"),
'KCHPOOL0001L': _("Create storage pool '%(name)s' type '%(type)s'"),
'KCHPOOL0002L': _("Remove storage pool '%(ident)s'"),
'KCHPOOL0003L': _("Update storage pool '%(ident)s'"),
'KCHPOOL0004L': _("Activate storage pool '%(ident)s'"),
'KCHPOOL0005L': _("Deactivate storage pool '%(ident)s'"),
'KCHSNAP0001L': _("Create snapshot '%(name)s' at guest '%(vm)s'"),
'KCHSNAP0002L': _("Remove snapshot '%(ident)s' from guest '%(vm)s'"),
'KCHSNAP0003L': _("Revert guest '%(vm)s' to snapshot '%(ident)s'"),
'KCHTMPL0001L': _("Create template '%(name)s'"),
'KCHTMPL0002L': _("Remove template '%(ident)s'"),
'KCHTMPL0003L': _("Update template '%(ident)s'"),
'KCHTMPL0004L': _("Clone template '%(ident)s'"),
'KCHVM0001L': _("Create guest '%(name)s' from template '%(template)s'"),
'KCHVM0002L': _("Remove guest '%(ident)s'"),
'KCHVM0003L': _("Edit guest '%(ident)s'"),
'KCHVM0004L': _("Start guest '%(ident)s'"),
'KCHVM0005L': _("Power off guest '%(ident)s'"),
'KCHVM0006L': _("Shutdown guest '%(ident)s'"),
'KCHVM0007L': _("Restart guest '%(ident)s'"),
'KCHVM0008L': _("Connect to guest '%(ident)s' through novnc/spice"),
'KCHVM0009L': _("Clone guest '%(ident)s'"),
'KCHVM0010L': _("Migrate guest '%(ident)s' to '%(remote_host)s'"),
'KCHVM0011L': _("Suspend guest '%(ident)s'"),
'KCHVM0012L': _("Resume guest '%(ident)s'"),
'KCHVM0013L': _("Connect to guest '%(ident)s' through serial"),
'KCHVMHDEV0001L': _("Attach host device '%(name)s' to guest '%(vmid)s'"),
'KCHVMHDEV0002L': _("Detach host device '%(ident)s' from guest '%(vmid)s'"),
'KCHVMIF0001L': _("Attach network interface '%(network)s' to guest '%(vm)s'"),
'KCHVMIF0002L': _("Detach network interface '%(ident)s' from guest '%(vm)s'"),
'KCHVMIF0003L': _("Update network interface '%(ident)s' at guest '%(vm)s'"),
'KCHVMSTOR0001L': _("Attach %(type)s storage '%(path)s' to guest '%(vm)s'"),
'KCHVMSTOR0002L': _("Remove storage '%(ident)s' from guest '%(vm)s'"),
'KCHVMSTOR0003L': _("Update storage '%(ident)s' at guest '%(vm)s'"),
'KCHVOL0001L': _("Create storage volume '%(name)s' at pool '%(pool)s'"),
'KCHVOL0002L': _("Remove storage volume '%(ident)s' from pool '%(pool)s'"),
'KCHVOL0003L': _("Update storage volume '%(ident)s' at pool '%(pool)s'"),
'KCHVOL0004L': _("Wipe storage volume '%(ident)s' off pool '%(pool)s'"),
'KCHVOL0005L': _("Resize storage volume '%(ident)s' at pool '%(pool)s' with size %(size)s"),
'KCHVOL0006L': _("Clone storage volume '%(ident)s' at pool '%(pool)s'"),
}
================================================
FILE: imageinfo.py
================================================
#
# Kimchi
#
# Copyright IBM Corp, 2015-2016
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
import json
import os
import sys
from wok.exception import ImageFormatError
from wok.exception import InvalidParameter
from wok.exception import TimeoutExpired
from wok.utils import run_command
from wok.utils import wok_log
def probe_img_info(path):
cmd = ['qemu-img', 'info', '--output=json', path]
info = dict()
try:
out = run_command(cmd, 10)[0]
except TimeoutExpired:
wok_log.warning('Cannot decide format of base img %s', path)
return None
info = json.loads(out)
info['virtual-size'] = info['virtual-size'] >> 30
info['actual-size'] = info['actual-size'] >> 30
return info
def probe_image(image_path):
if not os.path.isfile(image_path):
raise InvalidParameter('KCHIMG0004E', {'filename': image_path})
if not os.access(image_path, os.R_OK):
raise ImageFormatError('KCHIMG0003E', {'filename': image_path})
try:
import guestfs
g = guestfs.GuestFS(python_return_dict=True)
g.add_drive_opts(image_path, readonly=1)
g.launch()
roots = g.inspect_os()
except ImportError:
return ('unknown', 'unknown')
except Exception as e:
raise ImageFormatError('KCHIMG0001E', {'err': str(e)})
if len(roots) == 0:
# If we are unable to detect the OS, still add the image
# but make distro and vendor 'unknown'
return ('unknown', 'unknown')
for root in roots:
version = '%d.%d' % (
g.inspect_get_major_version(root),
g.inspect_get_minor_version(root),
)
distro = '%s' % (g.inspect_get_distro(root))
return (distro, version)
if __name__ == '__main__':
print(probe_image(sys.argv[1]))
================================================
FILE: iscsi.py
================================================
#
# Project Kimchi
#
# Copyright IBM Corp, 2015-2016
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301USA
import subprocess
from wok.exception import OperationFailed
class TargetClient(object):
def __init__(self, target, host, port=None, auth=None):
self.portal = host + ('' if port is None else ':%s' % port)
self.target = target
self.auth = auth
self.targetCmd = ['iscsiadm', '--mode', 'node', '--targetname',
self.target, '--portal', self.portal]
def _update_db(self, Name, Value):
self._run_cmd(['--op=update', '--name', Name, '--value', Value])
def _update_auth(self):
if self.auth is None:
items = (('node.session.auth.authmethod', 'None'),
('node.session.auth.username', ''),
('node.session.auth.password', ''))
else:
items = (('node.session.auth.authmethod', 'CHAP'),
('node.session.auth.username', self.auth['username']),
('node.session.auth.password', self.auth['password']))
for name, value in items:
self._update_db(name, value)
def _run_cmd(self, cmd):
iscsiadm = subprocess.Popen(
self.targetCmd + cmd,
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
out, err = iscsiadm.communicate()
if iscsiadm.returncode != 0:
msg_args = {'portal': self.portal, 'err': err}
raise OperationFailed('KCHISCSI0001E', msg_args)
return out
def _discover(self):
iscsiadm = subprocess.Popen(
['iscsiadm', '--mode', 'discovery', '--type', 'sendtargets',
'--portal', self.portal],
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
out, err = iscsiadm.communicate()
if iscsiadm.returncode != 0:
msg_args = {'portal': self.portal, 'err': err}
raise OperationFailed('KCHISCSI0001E', msg_args)
return out
def _run_op(self, op):
self._run_cmd(['--' + op])
def login(self):
self._discover()
self._update_auth()
self._run_op('login')
def logout(self):
self._run_op('logout')
def validate(self):
try:
self.login()
except OperationFailed:
return False
self.logout()
return True
================================================
FILE: isoinfo.py
================================================
#
# Project Kimchi
#
# Copyright IBM Corp, 2015-2016
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
import contextlib
import glob
import os
import platform
import re
import stat
import struct
import sys
import urllib
from wok.exception import IsoFormatError
from wok.exception import OperationFailed
from wok.plugins.kimchi.utils import check_url_path
from wok.utils import wok_log
iso_dir = [
##
# Portions of this data from libosinfo: http://libosinfo.org/
#
# Each tuple has the following three members:
# Distro ID: Nickname for the distro or OS family
# Distro Version: A function or string that provides a specific version
# given a regular expression match on the volume id string
# Regular Expression: A regex to match against the ISO Volume ID
##
(
'openbsd',
lambda m: m.group(2),
('OpenBSD/(i386|amd64) (\\d+\\.\\d+) Install CD'),
),
('centos', lambda m: m.group(1), ('CentOS[ _-](\\d+\\.?\\d?)[ _-].+')),
(
'windows',
'2000',
(
'W2AFPP|SP1AFPP|SP2AFPP|YRMAFPP|ZRMAFPP|W2AOEM|SP1AOEM|SP2AOEM' +
'|YRMAOEM|ZRMAOEM|W2ASEL|SP2ASEL|W2SFPP|SP1SFPP|SP2SFPP|YRMSFPP' +
'|ZRMSFPP|W2SOEM|W2SOEM|SP1SOEM|SP2SOEM|YRMSOEM|ZRMSOEM|W2SSEL' +
'|SP2SSEL|W2PFPP|SP1PFPP|SP2PFPP|YRMPFPP|ZRMPFPP|W2POEM|SP1POEM' +
'|SP2POEM|YRMPOEM|ZRMPOEM|W2PSEL|SP2PSEL|W2PCCP|WIN2000|W2K_SP4'
),
),
(
'windows',
'xp',
(
'WXPFPP|WXHFPP|WXPCCP|WXHCCP|WXPOEM|WXHOEM|WXPVOL|WXPEVL|XRMPFPP' +
'|XRMHFPP|XRMPCCP|XRMHCCP|XRMPOEM|XRMHOEM|XRMPVOL|XRMSD2|X1APFPP' +
'|X1AHFPP|X1APCCP|X1APCCP|X1AHCCP|X1APOEM|X1AHOEM|X1APVOL|VRMPFPP' +
'|VRMHFPP|VRMPCCP|VRMHCCP|VRMPOEM|VRMHOEM|VRMPVOL|VRMSD2|VX2PFPP' +
'|VX2HFPP|VX2PCCP|VX2HCCP|VX2POEM|VX2HOEM|VX2PRMFPP|VX2PVOL|GRTMUPD' +
'|GRTMPFPP|GRTMPRMFPP|GRTMHFPP|GRTMHKFPP|GRTMHKNFPP|GRTMHRMFPP' +
'|GRTMPOEM|GRTMHOEM|GRTMPVOL|GRTMPKNVOL|GRTMPKVOL|GRTMPRMVOL' +
'|MX2PFPP|MRMSD2|ARMPXFPP|ARMPXCCP|ARMPXOEM|ARMPXVOL|AX2PXCFPP' +
'|AX2PXFPP|NRMPIFPP'
),
),
(
'windows',
'2003',
(
'ARMECHK|ARMEVOL|ARMSVOL|ARMWVOL|ARMEEVL|ARMSEVL|ARMWEVL|ARMEOEM' +
'|ARMDOEM|ARMSOEM|ARMWOEM|ARMEFPP|ARMDFPP|ARMSFPP|ARMWFPP|NRMECHK' +
'|NRMEVOL|NRMSVOL|NRMWVOL|NRMEEVL|NRMSEVL|NRMWEVL|NRMEOEM|NRMDOEM' +
'|NRMSOEM|NRMWOEM|NRMEFPP|NRMDFPP|NRMSFPP|NRMSFPP|CRMSVOL|CRMSXVOL' +
'|BRMEVOL|BX2DVOL|ARMEEVL|BRMEEVL|CR0SP2|ARMEICHK|ARMEIFPP|ARMEIEVL' +
'|ARMEIOEM|ARMDIOEM|ARMEXFPP|ARMDFPP|ARMSXFPP|CR0SPX2|NRMEICHK' +
'|NRMEIFPP|NRMDIFPP|NRMEIOEM|NRMDIOEM|NRMEIVOL|NRMEIEVL|BRMEXVOL' +
'|BX2DXVOL|ARMEIFPP|CR0SPI2'
),
),
(
'windows',
'2003r2',
(
'CRMEFPP|CRMSFPP|CR0SCD2|CR0ECD2|BX2SFPP|BX2EFPP|BRMECD2FRE' +
'|BRMSCD2FRE|CRMEXFPP|CRMSXFPP|CR0SCD2X|CR0ECD2X|BX2SXFPP|BX2EXFPP' +
'|BRMECD2XFRE|BRMSCD2XFRE|CRMDVOL|CRMDXVOL'
),
),
(
'windows',
'2008',
(
'KRTMSVOL|KRTMSCHK|KRMWVOL|KRMSVOL|KRTMSXVOL|KRTMSXCHK|KRMWXVOL' +
'|KRMSXVOL'
),
),
('windows', '2008r2', ('GRMSXVOL|GRMSXFRER|GRMSHXVOL|GRMSIAIVOL|SRVHPCR2')),
(
'windows',
'vista',
(
'FB1EVOL|LRMCFRE|FRTMBVOL|FRMBVOL|FRMEVOL|FB1EXVOL|LRMCXFRE' +
'|FRTMBXVOL|FRMBXVOL|FRMEXVOL|LRMEVOL|LRMEXVOL'
),
),
(
'windows',
'7',
(
'GRMCULFRER|GSP1RMCNPRFRER|GSP1RMCNULFRER|GSP1RMCULFRER' +
'|GSP1RMCPRFRER|GRMCENVOL|GRMCNENVOL|GRMCPRFRER|GSP1RMCPRVOL' +
'|GRMCULXFRER|GSP1RMCPRXFRER|GSP1RMCNHPXFRER|GRMCHPXFRER|GRMCXCHK' +
'|GSP1RMCENXVOL|GRMCENXVOL|GRMCNENXVOL|GRMCPRXFRER|GSP1RMCPRXVOL'
),
),
(
'windows',
'8',
(
'HB1_CCPA_X86FRE|HRM_CCSA_X86FRE|HRM_CCSA_X86CHK|HRM_CCSNA_X86CHK' +
'|HRM_CCSNA_X86FRE|HRM_CENA_X86FREV|HRM_CENA_X86CHKV' +
'|HRM_CENNA_X86FREV|HRM_CENNA_X86CHKV|HRM_CPRA_X86FREV' +
'|HRM_CPRNA_X86FREV|HB1_CCPA_X64FRE|HRM_CCSA_X64FRE' +
'|HRM_CCSA_X64CHK|HRM_CCSNA_X64FRE|HRM_CCSNA_X64CHK' +
'|HRM_CENNA_X64FREV|HRM_CENNA_X64CHKV|HRM_CENA_X64FREV' +
'|HRM_CENA_X64CHKV|HRM_CPRA_X64FREV|HRM_CPRNA_X64FREV'
),
),
('sles', '10', 'SLES10|SUSE-Linux-Enterprise-Server.001'),
('sles', '11', 'SUSE_SLES-11-0-0|SLE-11'),
('sles', '12', 'SLE-12'),
('sles', '15', 'SLE-15'),
('sles', lambda m: '11sp%s' % m.group(1), 'SLES-11-SP(\\d+)'),
('opensuse', lambda m: m.group(1), 'openSUSE[ -](\\d+\\.\\d+)'),
('opensuse', '11.1', 'SU1110.001'),
(
'opensuse',
'11.3',
'openSUSE-DVD-i586-Build0702..001|openSUSE-DVD-x86_64.0702..001',
),
('opensuse', '11.4', 'openSUSE-DVD-i586-Build0024|openSUSE-DVD-x86_640024'),
('opensuse', '12.1', 'openSUSE-DVD-i586-Build0039|openSUSE-DVD-x86_640039'),
('opensuse', '12.2', 'openSUSE-DVD-i586-Build0167|openSUSE-DVD-x86_640167'),
('opensuse', lambda m: m.group(1), 'openSUSE-Leap-(\\d+\\.\\d+)'),
('rhel', '4.8', 'RHEL/4-U8'),
('rhel', lambda m: m.group(2), 'RHEL(-LE)?[_/-](\\d+\\.\\d+)'),
('debian', lambda m: m.group(1), 'Debian (\\d+\\.\\d+)'),
('ubuntu', lambda m: m.group(2), '[Uu]buntu(-Server)? (\\d+\\.\\d+)'),
('fedora', lambda m: m.group(1), 'Fedora-WS-[\\D-]+-(\\d+)'),
('fedora', lambda m: m.group(1), 'Fedora-S-[\\w-]+-(\\d+)'),
('fedora', lambda m: m.group(1), 'Fedora[ -](\\d+)'),
('fedora', lambda m: m.group(1), 'Fedora.*-(\\d+)-'),
('gentoo', lambda m: m.group(1), 'Gentoo Linux \\w+ (\\d+)'),
('powerkvm', 'live_cd', 'POWERKVM_LIVECD'),
('arch', lambda m: m.group(1), 'ARCH_(\\d+)'),
]
class IsoImage(object):
"""
Scan an iso9660 image to extract the Volume ID and check for boot-ability
ISO-9660 specification:
http://www.ecma-international.org/publications/standards/Ecma-119.htm
El-Torito specification:
http://download.intel.com/support/motherboards/desktop/sb/specscdrom.pdf
"""
SECTOR_SIZE = 2048
VOL_DESC = struct.Struct('=B5sBB32s32s')
EL_TORITO_BOOT_RECORD = struct.Struct('=B5sB32s32sI')
EL_TORITO_VALIDATION_ENTRY = struct.Struct('=BBH24sHBB')
EL_TORITO_BOOT_ENTRY = struct.Struct('=BBHBBHL20x')
# Path table info starting in ISO9660 offset 132. We force little
# endian byte order (the '<' sign) because Power systems can run on
# both.
# First int is path table size, next 4 bytes are discarded (it is
# the same info but in big endian) and next int is the location.
PATH_TABLE_SIZE_LOC = struct.Struct(' path_size:
# Didn't find the '/ppc' directory. ISO is not bootable.
self.bootable = False
return
# Get the 'ppc' directory record using 'dir_loc'.
ppc_dir_offset = dir_loc * IsoImage.SECTOR_SIZE
# We need to find the sector size of this dir entry. The
# size of the File Section is located 10 bytes after
# the dir location.
DIR_SIZE_FMT = struct.Struct('<10sI')
data = self._get_iso_data(ppc_dir_offset, DIR_SIZE_FMT.size)
unused, dir_size = self._unpack(DIR_SIZE_FMT, data)
# If the dir is in the middle of a sector, the sector is
# padded zero and won't be utilized. We need to round up
# the result
dir_sectorsize = dir_size / IsoImage.SECTOR_SIZE
if dir_size % IsoImage.SECTOR_SIZE:
dir_sectorsize += 1
# Fixed-size directory record fields:
# - length of directory record (1 byte)
# - extended attr. record length (1 byte)
# - location of extend in both-endian format (8 bytes)
# - data length (size of extend) in both-endian (8 bytes)
# - recording date and time (7 bytes)
# - file flags (1 byte)
# - file unit size interleaved (1 byte)
# - interleave gap size (1 byte)
# - volume sequence number (4 bytes)
# - length of file identifier (1 byte)
#
# Of all these fields, we will use only 3 of them, 'ignoring'
# 30 bytes total.
STATIC_DIR_RECORD_FMT = struct.Struct('%(name)s262144hvmdestroyrestartrestart
"""
lock = threading.Lock()
user = None
@classmethod
def probe_user(cls):
with cls.lock:
if cls.user:
return cls.user
arch = 'ppc64' if platform.machine() == 'ppc64le' else platform.machine()
xml = cls.SIMPLE_VM_XML % {'name': KVMUSERTEST_VM_NAME, 'arch': arch}
with RollbackContext() as rollback:
with cls.lock:
conn = libvirt.open(None)
rollback.prependDefer(conn.close)
f = libvirt.VIR_DOMAIN_START_AUTODESTROY
dom = conn.createXML(xml, flags=f)
rollback.prependDefer(dom.destroy)
filename = get_libvirt_path() + '/qemu/%s.pid' % KVMUSERTEST_VM_NAME
with open(filename) as f:
pidStr = f.read()
p = psutil.Process(int(pidStr))
# bug fix #357
# in psutil 2.0 and above versions, username will be a method,
# not a string
if callable(p.username):
cls.user = p.username()
else:
cls.user = p.username
return cls.user
if __name__ == '__main__':
ut = UserTests()
print(ut.probe_user())
================================================
FILE: m4/ac_python_module.m4
================================================
dnl @synopsis AC_PYTHON_MODULE(modname[, fatal])
dnl
dnl Checks for Python module.
dnl
dnl If fatal is non-empty then absence of a module will trigger an
dnl error.
dnl
dnl @category InstalledPackages
dnl @author Andrew Collier .
dnl @version 2004-07-14
dnl @license AllPermissive
AC_DEFUN([AC_PYTHON_MODULE],[
AC_MSG_CHECKING(python module: $1)
python -c "import $1" 2>/dev/null
if test $? -eq 0;
then
AC_MSG_RESULT(yes)
eval AS_TR_CPP(HAVE_PYMOD_$1)=yes
else
AC_MSG_RESULT(no)
eval AS_TR_CPP(HAVE_PYMOD_$1)=no
#
if test -n "$2"
then
AC_MSG_ERROR(failed to find required module $1)
exit 1
fi
fi
])
================================================
FILE: m4/gettext.m4
================================================
# gettext.m4 serial 63 (gettext-0.18)
dnl Copyright (C) 1995-2010 Free Software Foundation, Inc.
dnl This file is free software; the Free Software Foundation
dnl gives unlimited permission to copy and/or distribute it,
dnl with or without modifications, as long as this notice is preserved.
dnl
dnl This file can can be used in projects which are not available under
dnl the GNU General Public License or the GNU Library General Public
dnl License but which still want to provide support for the GNU gettext
dnl functionality.
dnl Please note that the actual code of the GNU gettext library is covered
dnl by the GNU Library General Public License, and the rest of the GNU
dnl gettext package package is covered by the GNU General Public License.
dnl They are *not* in the public domain.
dnl Authors:
dnl Ulrich Drepper , 1995-2000.
dnl Bruno Haible , 2000-2006, 2008-2010.
dnl Macro to add for using GNU gettext.
dnl Usage: AM_GNU_GETTEXT([INTLSYMBOL], [NEEDSYMBOL], [INTLDIR]).
dnl INTLSYMBOL can be one of 'external', 'no-libtool', 'use-libtool'. The
dnl default (if it is not specified or empty) is 'no-libtool'.
dnl INTLSYMBOL should be 'external' for packages with no intl directory,
dnl and 'no-libtool' or 'use-libtool' for packages with an intl directory.
dnl If INTLSYMBOL is 'use-libtool', then a libtool library
dnl $(top_builddir)/intl/libintl.la will be created (shared and/or static,
dnl depending on --{enable,disable}-{shared,static} and on the presence of
dnl AM-DISABLE-SHARED). If INTLSYMBOL is 'no-libtool', a static library
dnl $(top_builddir)/intl/libintl.a will be created.
dnl If NEEDSYMBOL is specified and is 'need-ngettext', then GNU gettext
dnl implementations (in libc or libintl) without the ngettext() function
dnl will be ignored. If NEEDSYMBOL is specified and is
dnl 'need-formatstring-macros', then GNU gettext implementations that don't
dnl support the ISO C 99 formatstring macros will be ignored.
dnl INTLDIR is used to find the intl libraries. If empty,
dnl the value `$(top_builddir)/intl/' is used.
dnl
dnl The result of the configuration is one of three cases:
dnl 1) GNU gettext, as included in the intl subdirectory, will be compiled
dnl and used.
dnl Catalog format: GNU --> install in $(datadir)
dnl Catalog extension: .mo after installation, .gmo in source tree
dnl 2) GNU gettext has been found in the system's C library.
dnl Catalog format: GNU --> install in $(datadir)
dnl Catalog extension: .mo after installation, .gmo in source tree
dnl 3) No internationalization, always use English msgid.
dnl Catalog format: none
dnl Catalog extension: none
dnl If INTLSYMBOL is 'external', only cases 2 and 3 can occur.
dnl The use of .gmo is historical (it was needed to avoid overwriting the
dnl GNU format catalogs when building on a platform with an X/Open gettext),
dnl but we keep it in order not to force irrelevant filename changes on the
dnl maintainers.
dnl
AC_DEFUN([AM_GNU_GETTEXT],
[
dnl Argument checking.
ifelse([$1], [], , [ifelse([$1], [external], , [ifelse([$1], [no-libtool], , [ifelse([$1], [use-libtool], ,
[errprint([ERROR: invalid first argument to AM_GNU_GETTEXT
])])])])])
ifelse(ifelse([$1], [], [old])[]ifelse([$1], [no-libtool], [old]), [old],
[AC_DIAGNOSE([obsolete], [Use of AM_GNU_GETTEXT without [external] argument is deprecated.])])
ifelse([$2], [], , [ifelse([$2], [need-ngettext], , [ifelse([$2], [need-formatstring-macros], ,
[errprint([ERROR: invalid second argument to AM_GNU_GETTEXT
])])])])
define([gt_included_intl],
ifelse([$1], [external],
ifdef([AM_GNU_GETTEXT_][INTL_SUBDIR], [yes], [no]),
[yes]))
define([gt_libtool_suffix_prefix], ifelse([$1], [use-libtool], [l], []))
gt_NEEDS_INIT
AM_GNU_GETTEXT_NEED([$2])
AC_REQUIRE([AM_PO_SUBDIRS])dnl
ifelse(gt_included_intl, yes, [
AC_REQUIRE([AM_INTL_SUBDIR])dnl
])
dnl Prerequisites of AC_LIB_LINKFLAGS_BODY.
AC_REQUIRE([AC_LIB_PREPARE_PREFIX])
AC_REQUIRE([AC_LIB_RPATH])
dnl Sometimes libintl requires libiconv, so first search for libiconv.
dnl Ideally we would do this search only after the
dnl if test "$USE_NLS" = "yes"; then
dnl if { eval "gt_val=\$$gt_func_gnugettext_libc"; test "$gt_val" != "yes"; }; then
dnl tests. But if configure.in invokes AM_ICONV after AM_GNU_GETTEXT
dnl the configure script would need to contain the same shell code
dnl again, outside any 'if'. There are two solutions:
dnl - Invoke AM_ICONV_LINKFLAGS_BODY here, outside any 'if'.
dnl - Control the expansions in more detail using AC_PROVIDE_IFELSE.
dnl Since AC_PROVIDE_IFELSE is only in autoconf >= 2.52 and not
dnl documented, we avoid it.
ifelse(gt_included_intl, yes, , [
AC_REQUIRE([AM_ICONV_LINKFLAGS_BODY])
])
dnl Sometimes, on MacOS X, libintl requires linking with CoreFoundation.
gt_INTL_MACOSX
dnl Set USE_NLS.
AC_REQUIRE([AM_NLS])
ifelse(gt_included_intl, yes, [
BUILD_INCLUDED_LIBINTL=no
USE_INCLUDED_LIBINTL=no
])
LIBINTL=
LTLIBINTL=
POSUB=
dnl Add a version number to the cache macros.
case " $gt_needs " in
*" need-formatstring-macros "*) gt_api_version=3 ;;
*" need-ngettext "*) gt_api_version=2 ;;
*) gt_api_version=1 ;;
esac
gt_func_gnugettext_libc="gt_cv_func_gnugettext${gt_api_version}_libc"
gt_func_gnugettext_libintl="gt_cv_func_gnugettext${gt_api_version}_libintl"
dnl If we use NLS figure out what method
if test "$USE_NLS" = "yes"; then
gt_use_preinstalled_gnugettext=no
ifelse(gt_included_intl, yes, [
AC_MSG_CHECKING([whether included gettext is requested])
AC_ARG_WITH([included-gettext],
[ --with-included-gettext use the GNU gettext library included here],
nls_cv_force_use_gnu_gettext=$withval,
nls_cv_force_use_gnu_gettext=no)
AC_MSG_RESULT([$nls_cv_force_use_gnu_gettext])
nls_cv_use_gnu_gettext="$nls_cv_force_use_gnu_gettext"
if test "$nls_cv_force_use_gnu_gettext" != "yes"; then
])
dnl User does not insist on using GNU NLS library. Figure out what
dnl to use. If GNU gettext is available we use this. Else we have
dnl to fall back to GNU NLS library.
if test $gt_api_version -ge 3; then
gt_revision_test_code='
#ifndef __GNU_GETTEXT_SUPPORTED_REVISION
#define __GNU_GETTEXT_SUPPORTED_REVISION(major) ((major) == 0 ? 0 : -1)
#endif
changequote(,)dnl
typedef int array [2 * (__GNU_GETTEXT_SUPPORTED_REVISION(0) >= 1) - 1];
changequote([,])dnl
'
else
gt_revision_test_code=
fi
if test $gt_api_version -ge 2; then
gt_expression_test_code=' + * ngettext ("", "", 0)'
else
gt_expression_test_code=
fi
AC_CACHE_CHECK([for GNU gettext in libc], [$gt_func_gnugettext_libc],
[AC_TRY_LINK([#include
$gt_revision_test_code
extern int _nl_msg_cat_cntr;
extern int *_nl_domain_bindings;],
[bindtextdomain ("", "");
return * gettext ("")$gt_expression_test_code + _nl_msg_cat_cntr + *_nl_domain_bindings],
[eval "$gt_func_gnugettext_libc=yes"],
[eval "$gt_func_gnugettext_libc=no"])])
if { eval "gt_val=\$$gt_func_gnugettext_libc"; test "$gt_val" != "yes"; }; then
dnl Sometimes libintl requires libiconv, so first search for libiconv.
ifelse(gt_included_intl, yes, , [
AM_ICONV_LINK
])
dnl Search for libintl and define LIBINTL, LTLIBINTL and INCINTL
dnl accordingly. Don't use AC_LIB_LINKFLAGS_BODY([intl],[iconv])
dnl because that would add "-liconv" to LIBINTL and LTLIBINTL
dnl even if libiconv doesn't exist.
AC_LIB_LINKFLAGS_BODY([intl])
AC_CACHE_CHECK([for GNU gettext in libintl],
[$gt_func_gnugettext_libintl],
[gt_save_CPPFLAGS="$CPPFLAGS"
CPPFLAGS="$CPPFLAGS $INCINTL"
gt_save_LIBS="$LIBS"
LIBS="$LIBS $LIBINTL"
dnl Now see whether libintl exists and does not depend on libiconv.
AC_TRY_LINK([#include
$gt_revision_test_code
extern int _nl_msg_cat_cntr;
extern
#ifdef __cplusplus
"C"
#endif
const char *_nl_expand_alias (const char *);],
[bindtextdomain ("", "");
return * gettext ("")$gt_expression_test_code + _nl_msg_cat_cntr + *_nl_expand_alias ("")],
[eval "$gt_func_gnugettext_libintl=yes"],
[eval "$gt_func_gnugettext_libintl=no"])
dnl Now see whether libintl exists and depends on libiconv.
if { eval "gt_val=\$$gt_func_gnugettext_libintl"; test "$gt_val" != yes; } && test -n "$LIBICONV"; then
LIBS="$LIBS $LIBICONV"
AC_TRY_LINK([#include
$gt_revision_test_code
extern int _nl_msg_cat_cntr;
extern
#ifdef __cplusplus
"C"
#endif
const char *_nl_expand_alias (const char *);],
[bindtextdomain ("", "");
return * gettext ("")$gt_expression_test_code + _nl_msg_cat_cntr + *_nl_expand_alias ("")],
[LIBINTL="$LIBINTL $LIBICONV"
LTLIBINTL="$LTLIBINTL $LTLIBICONV"
eval "$gt_func_gnugettext_libintl=yes"
])
fi
CPPFLAGS="$gt_save_CPPFLAGS"
LIBS="$gt_save_LIBS"])
fi
dnl If an already present or preinstalled GNU gettext() is found,
dnl use it. But if this macro is used in GNU gettext, and GNU
dnl gettext is already preinstalled in libintl, we update this
dnl libintl. (Cf. the install rule in intl/Makefile.in.)
if { eval "gt_val=\$$gt_func_gnugettext_libc"; test "$gt_val" = "yes"; } \
|| { { eval "gt_val=\$$gt_func_gnugettext_libintl"; test "$gt_val" = "yes"; } \
&& test "$PACKAGE" != gettext-runtime \
&& test "$PACKAGE" != gettext-tools; }; then
gt_use_preinstalled_gnugettext=yes
else
dnl Reset the values set by searching for libintl.
LIBINTL=
LTLIBINTL=
INCINTL=
fi
ifelse(gt_included_intl, yes, [
if test "$gt_use_preinstalled_gnugettext" != "yes"; then
dnl GNU gettext is not found in the C library.
dnl Fall back on included GNU gettext library.
nls_cv_use_gnu_gettext=yes
fi
fi
if test "$nls_cv_use_gnu_gettext" = "yes"; then
dnl Mark actions used to generate GNU NLS library.
BUILD_INCLUDED_LIBINTL=yes
USE_INCLUDED_LIBINTL=yes
LIBINTL="ifelse([$3],[],\${top_builddir}/intl,[$3])/libintl.[]gt_libtool_suffix_prefix[]a $LIBICONV $LIBTHREAD"
LTLIBINTL="ifelse([$3],[],\${top_builddir}/intl,[$3])/libintl.[]gt_libtool_suffix_prefix[]a $LTLIBICONV $LTLIBTHREAD"
LIBS=`echo " $LIBS " | sed -e 's/ -lintl / /' -e 's/^ //' -e 's/ $//'`
fi
CATOBJEXT=
if test "$gt_use_preinstalled_gnugettext" = "yes" \
|| test "$nls_cv_use_gnu_gettext" = "yes"; then
dnl Mark actions to use GNU gettext tools.
CATOBJEXT=.gmo
fi
])
if test -n "$INTL_MACOSX_LIBS"; then
if test "$gt_use_preinstalled_gnugettext" = "yes" \
|| test "$nls_cv_use_gnu_gettext" = "yes"; then
dnl Some extra flags are needed during linking.
LIBINTL="$LIBINTL $INTL_MACOSX_LIBS"
LTLIBINTL="$LTLIBINTL $INTL_MACOSX_LIBS"
fi
fi
if test "$gt_use_preinstalled_gnugettext" = "yes" \
|| test "$nls_cv_use_gnu_gettext" = "yes"; then
AC_DEFINE([ENABLE_NLS], [1],
[Define to 1 if translation of program messages to the user's native language
is requested.])
else
USE_NLS=no
fi
fi
AC_MSG_CHECKING([whether to use NLS])
AC_MSG_RESULT([$USE_NLS])
if test "$USE_NLS" = "yes"; then
AC_MSG_CHECKING([where the gettext function comes from])
if test "$gt_use_preinstalled_gnugettext" = "yes"; then
if { eval "gt_val=\$$gt_func_gnugettext_libintl"; test "$gt_val" = "yes"; }; then
gt_source="external libintl"
else
gt_source="libc"
fi
else
gt_source="included intl directory"
fi
AC_MSG_RESULT([$gt_source])
fi
if test "$USE_NLS" = "yes"; then
if test "$gt_use_preinstalled_gnugettext" = "yes"; then
if { eval "gt_val=\$$gt_func_gnugettext_libintl"; test "$gt_val" = "yes"; }; then
AC_MSG_CHECKING([how to link with libintl])
AC_MSG_RESULT([$LIBINTL])
AC_LIB_APPENDTOVAR([CPPFLAGS], [$INCINTL])
fi
dnl For backward compatibility. Some packages may be using this.
AC_DEFINE([HAVE_GETTEXT], [1],
[Define if the GNU gettext() function is already present or preinstalled.])
AC_DEFINE([HAVE_DCGETTEXT], [1],
[Define if the GNU dcgettext() function is already present or preinstalled.])
fi
dnl We need to process the po/ directory.
POSUB=po
fi
ifelse(gt_included_intl, yes, [
dnl If this is used in GNU gettext we have to set BUILD_INCLUDED_LIBINTL
dnl to 'yes' because some of the testsuite requires it.
if test "$PACKAGE" = gettext-runtime || test "$PACKAGE" = gettext-tools; then
BUILD_INCLUDED_LIBINTL=yes
fi
dnl Make all variables we use known to autoconf.
AC_SUBST([BUILD_INCLUDED_LIBINTL])
AC_SUBST([USE_INCLUDED_LIBINTL])
AC_SUBST([CATOBJEXT])
dnl For backward compatibility. Some configure.ins may be using this.
nls_cv_header_intl=
nls_cv_header_libgt=
dnl For backward compatibility. Some Makefiles may be using this.
DATADIRNAME=share
AC_SUBST([DATADIRNAME])
dnl For backward compatibility. Some Makefiles may be using this.
INSTOBJEXT=.mo
AC_SUBST([INSTOBJEXT])
dnl For backward compatibility. Some Makefiles may be using this.
GENCAT=gencat
AC_SUBST([GENCAT])
dnl For backward compatibility. Some Makefiles may be using this.
INTLOBJS=
if test "$USE_INCLUDED_LIBINTL" = yes; then
INTLOBJS="\$(GETTOBJS)"
fi
AC_SUBST([INTLOBJS])
dnl Enable libtool support if the surrounding package wishes it.
INTL_LIBTOOL_SUFFIX_PREFIX=gt_libtool_suffix_prefix
AC_SUBST([INTL_LIBTOOL_SUFFIX_PREFIX])
])
dnl For backward compatibility. Some Makefiles may be using this.
INTLLIBS="$LIBINTL"
AC_SUBST([INTLLIBS])
dnl Make all documented variables known to autoconf.
AC_SUBST([LIBINTL])
AC_SUBST([LTLIBINTL])
AC_SUBST([POSUB])
])
dnl gt_NEEDS_INIT ensures that the gt_needs variable is initialized.
m4_define([gt_NEEDS_INIT],
[
m4_divert_text([DEFAULTS], [gt_needs=])
m4_define([gt_NEEDS_INIT], [])
])
dnl Usage: AM_GNU_GETTEXT_NEED([NEEDSYMBOL])
AC_DEFUN([AM_GNU_GETTEXT_NEED],
[
m4_divert_text([INIT_PREPARE], [gt_needs="$gt_needs $1"])
])
dnl Usage: AM_GNU_GETTEXT_VERSION([gettext-version])
AC_DEFUN([AM_GNU_GETTEXT_VERSION], [])
================================================
FILE: m4/iconv.m4
================================================
# iconv.m4 serial 11 (gettext-0.18.1)
dnl Copyright (C) 2000-2002, 2007-2010 Free Software Foundation, Inc.
dnl This file is free software; the Free Software Foundation
dnl gives unlimited permission to copy and/or distribute it,
dnl with or without modifications, as long as this notice is preserved.
dnl From Bruno Haible.
AC_DEFUN([AM_ICONV_LINKFLAGS_BODY],
[
dnl Prerequisites of AC_LIB_LINKFLAGS_BODY.
AC_REQUIRE([AC_LIB_PREPARE_PREFIX])
AC_REQUIRE([AC_LIB_RPATH])
dnl Search for libiconv and define LIBICONV, LTLIBICONV and INCICONV
dnl accordingly.
AC_LIB_LINKFLAGS_BODY([iconv])
])
AC_DEFUN([AM_ICONV_LINK],
[
dnl Some systems have iconv in libc, some have it in libiconv (OSF/1 and
dnl those with the standalone portable GNU libiconv installed).
AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles
dnl Search for libiconv and define LIBICONV, LTLIBICONV and INCICONV
dnl accordingly.
AC_REQUIRE([AM_ICONV_LINKFLAGS_BODY])
dnl Add $INCICONV to CPPFLAGS before performing the following checks,
dnl because if the user has installed libiconv and not disabled its use
dnl via --without-libiconv-prefix, he wants to use it. The first
dnl AC_TRY_LINK will then fail, the second AC_TRY_LINK will succeed.
am_save_CPPFLAGS="$CPPFLAGS"
AC_LIB_APPENDTOVAR([CPPFLAGS], [$INCICONV])
AC_CACHE_CHECK([for iconv], [am_cv_func_iconv], [
am_cv_func_iconv="no, consider installing GNU libiconv"
am_cv_lib_iconv=no
AC_TRY_LINK([#include
#include ],
[iconv_t cd = iconv_open("","");
iconv(cd,NULL,NULL,NULL,NULL);
iconv_close(cd);],
[am_cv_func_iconv=yes])
if test "$am_cv_func_iconv" != yes; then
am_save_LIBS="$LIBS"
LIBS="$LIBS $LIBICONV"
AC_TRY_LINK([#include
#include ],
[iconv_t cd = iconv_open("","");
iconv(cd,NULL,NULL,NULL,NULL);
iconv_close(cd);],
[am_cv_lib_iconv=yes]
[am_cv_func_iconv=yes])
LIBS="$am_save_LIBS"
fi
])
if test "$am_cv_func_iconv" = yes; then
AC_CACHE_CHECK([for working iconv], [am_cv_func_iconv_works], [
dnl This tests against bugs in AIX 5.1, HP-UX 11.11, Solaris 10.
am_save_LIBS="$LIBS"
if test $am_cv_lib_iconv = yes; then
LIBS="$LIBS $LIBICONV"
fi
AC_TRY_RUN([
#include
#include
int main ()
{
/* Test against AIX 5.1 bug: Failures are not distinguishable from successful
returns. */
{
iconv_t cd_utf8_to_88591 = iconv_open ("ISO8859-1", "UTF-8");
if (cd_utf8_to_88591 != (iconv_t)(-1))
{
static const char input[] = "\342\202\254"; /* EURO SIGN */
char buf[10];
const char *inptr = input;
size_t inbytesleft = strlen (input);
char *outptr = buf;
size_t outbytesleft = sizeof (buf);
size_t res = iconv (cd_utf8_to_88591,
(char **) &inptr, &inbytesleft,
&outptr, &outbytesleft);
if (res == 0)
return 1;
}
}
/* Test against Solaris 10 bug: Failures are not distinguishable from
successful returns. */
{
iconv_t cd_ascii_to_88591 = iconv_open ("ISO8859-1", "646");
if (cd_ascii_to_88591 != (iconv_t)(-1))
{
static const char input[] = "\263";
char buf[10];
const char *inptr = input;
size_t inbytesleft = strlen (input);
char *outptr = buf;
size_t outbytesleft = sizeof (buf);
size_t res = iconv (cd_ascii_to_88591,
(char **) &inptr, &inbytesleft,
&outptr, &outbytesleft);
if (res == 0)
return 1;
}
}
#if 0 /* This bug could be worked around by the caller. */
/* Test against HP-UX 11.11 bug: Positive return value instead of 0. */
{
iconv_t cd_88591_to_utf8 = iconv_open ("utf8", "iso88591");
if (cd_88591_to_utf8 != (iconv_t)(-1))
{
static const char input[] = "\304rger mit b\366sen B\374bchen ohne Augenma\337";
char buf[50];
const char *inptr = input;
size_t inbytesleft = strlen (input);
char *outptr = buf;
size_t outbytesleft = sizeof (buf);
size_t res = iconv (cd_88591_to_utf8,
(char **) &inptr, &inbytesleft,
&outptr, &outbytesleft);
if ((int)res > 0)
return 1;
}
}
#endif
/* Test against HP-UX 11.11 bug: No converter from EUC-JP to UTF-8 is
provided. */
if (/* Try standardized names. */
iconv_open ("UTF-8", "EUC-JP") == (iconv_t)(-1)
/* Try IRIX, OSF/1 names. */
&& iconv_open ("UTF-8", "eucJP") == (iconv_t)(-1)
/* Try AIX names. */
&& iconv_open ("UTF-8", "IBM-eucJP") == (iconv_t)(-1)
/* Try HP-UX names. */
&& iconv_open ("utf8", "eucJP") == (iconv_t)(-1))
return 1;
return 0;
}], [am_cv_func_iconv_works=yes], [am_cv_func_iconv_works=no],
[case "$host_os" in
aix* | hpux*) am_cv_func_iconv_works="guessing no" ;;
*) am_cv_func_iconv_works="guessing yes" ;;
esac])
LIBS="$am_save_LIBS"
])
case "$am_cv_func_iconv_works" in
*no) am_func_iconv=no am_cv_lib_iconv=no ;;
*) am_func_iconv=yes ;;
esac
else
am_func_iconv=no am_cv_lib_iconv=no
fi
if test "$am_func_iconv" = yes; then
AC_DEFINE([HAVE_ICONV], [1],
[Define if you have the iconv() function and it works.])
fi
if test "$am_cv_lib_iconv" = yes; then
AC_MSG_CHECKING([how to link with libiconv])
AC_MSG_RESULT([$LIBICONV])
else
dnl If $LIBICONV didn't lead to a usable library, we don't need $INCICONV
dnl either.
CPPFLAGS="$am_save_CPPFLAGS"
LIBICONV=
LTLIBICONV=
fi
AC_SUBST([LIBICONV])
AC_SUBST([LTLIBICONV])
])
dnl Define AM_ICONV using AC_DEFUN_ONCE for Autoconf >= 2.64, in order to
dnl avoid warnings like
dnl "warning: AC_REQUIRE: `AM_ICONV' was expanded before it was required".
dnl This is tricky because of the way 'aclocal' is implemented:
dnl - It requires defining an auxiliary macro whose name ends in AC_DEFUN.
dnl Otherwise aclocal's initial scan pass would miss the macro definition.
dnl - It requires a line break inside the AC_DEFUN_ONCE and AC_DEFUN expansions.
dnl Otherwise aclocal would emit many "Use of uninitialized value $1"
dnl warnings.
m4_define([gl_iconv_AC_DEFUN],
m4_version_prereq([2.64],
[[AC_DEFUN_ONCE(
[$1], [$2])]],
[[AC_DEFUN(
[$1], [$2])]]))
gl_iconv_AC_DEFUN([AM_ICONV],
[
AM_ICONV_LINK
if test "$am_cv_func_iconv" = yes; then
AC_MSG_CHECKING([for iconv declaration])
AC_CACHE_VAL([am_cv_proto_iconv], [
AC_TRY_COMPILE([
#include
#include
extern
#ifdef __cplusplus
"C"
#endif
#if defined(__STDC__) || defined(__cplusplus)
size_t iconv (iconv_t cd, char * *inbuf, size_t *inbytesleft, char * *outbuf, size_t *outbytesleft);
#else
size_t iconv();
#endif
], [], [am_cv_proto_iconv_arg1=""], [am_cv_proto_iconv_arg1="const"])
am_cv_proto_iconv="extern size_t iconv (iconv_t cd, $am_cv_proto_iconv_arg1 char * *inbuf, size_t *inbytesleft, char * *outbuf, size_t *outbytesleft);"])
am_cv_proto_iconv=`echo "[$]am_cv_proto_iconv" | tr -s ' ' | sed -e 's/( /(/'`
AC_MSG_RESULT([
$am_cv_proto_iconv])
AC_DEFINE_UNQUOTED([ICONV_CONST], [$am_cv_proto_iconv_arg1],
[Define as const if the declaration of iconv() needs const.])
fi
])
================================================
FILE: m4/intlmacosx.m4
================================================
# intlmacosx.m4 serial 3 (gettext-0.18)
dnl Copyright (C) 2004-2010 Free Software Foundation, Inc.
dnl This file is free software; the Free Software Foundation
dnl gives unlimited permission to copy and/or distribute it,
dnl with or without modifications, as long as this notice is preserved.
dnl
dnl This file can can be used in projects which are not available under
dnl the GNU General Public License or the GNU Library General Public
dnl License but which still want to provide support for the GNU gettext
dnl functionality.
dnl Please note that the actual code of the GNU gettext library is covered
dnl by the GNU Library General Public License, and the rest of the GNU
dnl gettext package package is covered by the GNU General Public License.
dnl They are *not* in the public domain.
dnl Checks for special options needed on MacOS X.
dnl Defines INTL_MACOSX_LIBS.
AC_DEFUN([gt_INTL_MACOSX],
[
dnl Check for API introduced in MacOS X 10.2.
AC_CACHE_CHECK([for CFPreferencesCopyAppValue],
[gt_cv_func_CFPreferencesCopyAppValue],
[gt_save_LIBS="$LIBS"
LIBS="$LIBS -Wl,-framework -Wl,CoreFoundation"
AC_TRY_LINK([#include ],
[CFPreferencesCopyAppValue(NULL, NULL)],
[gt_cv_func_CFPreferencesCopyAppValue=yes],
[gt_cv_func_CFPreferencesCopyAppValue=no])
LIBS="$gt_save_LIBS"])
if test $gt_cv_func_CFPreferencesCopyAppValue = yes; then
AC_DEFINE([HAVE_CFPREFERENCESCOPYAPPVALUE], [1],
[Define to 1 if you have the MacOS X function CFPreferencesCopyAppValue in the CoreFoundation framework.])
fi
dnl Check for API introduced in MacOS X 10.3.
AC_CACHE_CHECK([for CFLocaleCopyCurrent], [gt_cv_func_CFLocaleCopyCurrent],
[gt_save_LIBS="$LIBS"
LIBS="$LIBS -Wl,-framework -Wl,CoreFoundation"
AC_TRY_LINK([#include ], [CFLocaleCopyCurrent();],
[gt_cv_func_CFLocaleCopyCurrent=yes],
[gt_cv_func_CFLocaleCopyCurrent=no])
LIBS="$gt_save_LIBS"])
if test $gt_cv_func_CFLocaleCopyCurrent = yes; then
AC_DEFINE([HAVE_CFLOCALECOPYCURRENT], [1],
[Define to 1 if you have the MacOS X function CFLocaleCopyCurrent in the CoreFoundation framework.])
fi
INTL_MACOSX_LIBS=
if test $gt_cv_func_CFPreferencesCopyAppValue = yes || test $gt_cv_func_CFLocaleCopyCurrent = yes; then
INTL_MACOSX_LIBS="-Wl,-framework -Wl,CoreFoundation"
fi
AC_SUBST([INTL_MACOSX_LIBS])
])
================================================
FILE: m4/lib-ld.m4
================================================
# lib-ld.m4 serial 4 (gettext-0.18)
dnl Copyright (C) 1996-2003, 2009-2010 Free Software Foundation, Inc.
dnl This file is free software; the Free Software Foundation
dnl gives unlimited permission to copy and/or distribute it,
dnl with or without modifications, as long as this notice is preserved.
dnl Subroutines of libtool.m4,
dnl with replacements s/AC_/AC_LIB/ and s/lt_cv/acl_cv/ to avoid collision
dnl with libtool.m4.
dnl From libtool-1.4. Sets the variable with_gnu_ld to yes or no.
AC_DEFUN([AC_LIB_PROG_LD_GNU],
[AC_CACHE_CHECK([if the linker ($LD) is GNU ld], [acl_cv_prog_gnu_ld],
[# I'd rather use --version here, but apparently some GNU ld's only accept -v.
case `$LD -v 2>&1 conf$$.sh
echo "exit 0" >>conf$$.sh
chmod +x conf$$.sh
if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then
PATH_SEPARATOR=';'
else
PATH_SEPARATOR=:
fi
rm -f conf$$.sh
fi
ac_prog=ld
if test "$GCC" = yes; then
# Check if gcc -print-prog-name=ld gives a path.
AC_MSG_CHECKING([for ld used by GCC])
case $host in
*-*-mingw*)
# gcc leaves a trailing carriage return which upsets mingw
ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;;
*)
ac_prog=`($CC -print-prog-name=ld) 2>&5` ;;
esac
case $ac_prog in
# Accept absolute paths.
[[\\/]* | [A-Za-z]:[\\/]*)]
[re_direlt='/[^/][^/]*/\.\./']
# Canonicalize the path of ld
ac_prog=`echo $ac_prog| sed 's%\\\\%/%g'`
while echo $ac_prog | grep "$re_direlt" > /dev/null 2>&1; do
ac_prog=`echo $ac_prog| sed "s%$re_direlt%/%"`
done
test -z "$LD" && LD="$ac_prog"
;;
"")
# If it fails, then pretend we aren't using GCC.
ac_prog=ld
;;
*)
# If it is relative, then search for the first ld in PATH.
with_gnu_ld=unknown
;;
esac
elif test "$with_gnu_ld" = yes; then
AC_MSG_CHECKING([for GNU ld])
else
AC_MSG_CHECKING([for non-GNU ld])
fi
AC_CACHE_VAL([acl_cv_path_LD],
[if test -z "$LD"; then
IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}${PATH_SEPARATOR-:}"
for ac_dir in $PATH; do
test -z "$ac_dir" && ac_dir=.
if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then
acl_cv_path_LD="$ac_dir/$ac_prog"
# Check to see if the program is GNU ld. I'd rather use --version,
# but apparently some GNU ld's only accept -v.
# Break only if it was the GNU/non-GNU ld that we prefer.
case `"$acl_cv_path_LD" -v 2>&1 < /dev/null` in
*GNU* | *'with BFD'*)
test "$with_gnu_ld" != no && break ;;
*)
test "$with_gnu_ld" != yes && break ;;
esac
fi
done
IFS="$ac_save_ifs"
else
acl_cv_path_LD="$LD" # Let the user override the test with a path.
fi])
LD="$acl_cv_path_LD"
if test -n "$LD"; then
AC_MSG_RESULT([$LD])
else
AC_MSG_RESULT([no])
fi
test -z "$LD" && AC_MSG_ERROR([no acceptable ld found in \$PATH])
AC_LIB_PROG_LD_GNU
])
================================================
FILE: m4/lib-link.m4
================================================
# lib-link.m4 serial 21 (gettext-0.18)
dnl Copyright (C) 2001-2010 Free Software Foundation, Inc.
dnl This file is free software; the Free Software Foundation
dnl gives unlimited permission to copy and/or distribute it,
dnl with or without modifications, as long as this notice is preserved.
dnl From Bruno Haible.
AC_PREREQ([2.54])
dnl AC_LIB_LINKFLAGS(name [, dependencies]) searches for libname and
dnl the libraries corresponding to explicit and implicit dependencies.
dnl Sets and AC_SUBSTs the LIB${NAME} and LTLIB${NAME} variables and
dnl augments the CPPFLAGS variable.
dnl Sets and AC_SUBSTs the LIB${NAME}_PREFIX variable to nonempty if libname
dnl was found in ${LIB${NAME}_PREFIX}/$acl_libdirstem.
AC_DEFUN([AC_LIB_LINKFLAGS],
[
AC_REQUIRE([AC_LIB_PREPARE_PREFIX])
AC_REQUIRE([AC_LIB_RPATH])
pushdef([Name],[translit([$1],[./-], [___])])
pushdef([NAME],[translit([$1],[abcdefghijklmnopqrstuvwxyz./-],
[ABCDEFGHIJKLMNOPQRSTUVWXYZ___])])
AC_CACHE_CHECK([how to link with lib[]$1], [ac_cv_lib[]Name[]_libs], [
AC_LIB_LINKFLAGS_BODY([$1], [$2])
ac_cv_lib[]Name[]_libs="$LIB[]NAME"
ac_cv_lib[]Name[]_ltlibs="$LTLIB[]NAME"
ac_cv_lib[]Name[]_cppflags="$INC[]NAME"
ac_cv_lib[]Name[]_prefix="$LIB[]NAME[]_PREFIX"
])
LIB[]NAME="$ac_cv_lib[]Name[]_libs"
LTLIB[]NAME="$ac_cv_lib[]Name[]_ltlibs"
INC[]NAME="$ac_cv_lib[]Name[]_cppflags"
LIB[]NAME[]_PREFIX="$ac_cv_lib[]Name[]_prefix"
AC_LIB_APPENDTOVAR([CPPFLAGS], [$INC]NAME)
AC_SUBST([LIB]NAME)
AC_SUBST([LTLIB]NAME)
AC_SUBST([LIB]NAME[_PREFIX])
dnl Also set HAVE_LIB[]NAME so that AC_LIB_HAVE_LINKFLAGS can reuse the
dnl results of this search when this library appears as a dependency.
HAVE_LIB[]NAME=yes
popdef([NAME])
popdef([Name])
])
dnl AC_LIB_HAVE_LINKFLAGS(name, dependencies, includes, testcode, [missing-message])
dnl searches for libname and the libraries corresponding to explicit and
dnl implicit dependencies, together with the specified include files and
dnl the ability to compile and link the specified testcode. The missing-message
dnl defaults to 'no' and may contain additional hints for the user.
dnl If found, it sets and AC_SUBSTs HAVE_LIB${NAME}=yes and the LIB${NAME}
dnl and LTLIB${NAME} variables and augments the CPPFLAGS variable, and
dnl #defines HAVE_LIB${NAME} to 1. Otherwise, it sets and AC_SUBSTs
dnl HAVE_LIB${NAME}=no and LIB${NAME} and LTLIB${NAME} to empty.
dnl Sets and AC_SUBSTs the LIB${NAME}_PREFIX variable to nonempty if libname
dnl was found in ${LIB${NAME}_PREFIX}/$acl_libdirstem.
AC_DEFUN([AC_LIB_HAVE_LINKFLAGS],
[
AC_REQUIRE([AC_LIB_PREPARE_PREFIX])
AC_REQUIRE([AC_LIB_RPATH])
pushdef([Name],[translit([$1],[./-], [___])])
pushdef([NAME],[translit([$1],[abcdefghijklmnopqrstuvwxyz./-],
[ABCDEFGHIJKLMNOPQRSTUVWXYZ___])])
dnl Search for lib[]Name and define LIB[]NAME, LTLIB[]NAME and INC[]NAME
dnl accordingly.
AC_LIB_LINKFLAGS_BODY([$1], [$2])
dnl Add $INC[]NAME to CPPFLAGS before performing the following checks,
dnl because if the user has installed lib[]Name and not disabled its use
dnl via --without-lib[]Name-prefix, he wants to use it.
ac_save_CPPFLAGS="$CPPFLAGS"
AC_LIB_APPENDTOVAR([CPPFLAGS], [$INC]NAME)
AC_CACHE_CHECK([for lib[]$1], [ac_cv_lib[]Name], [
ac_save_LIBS="$LIBS"
dnl If $LIB[]NAME contains some -l options, add it to the end of LIBS,
dnl because these -l options might require -L options that are present in
dnl LIBS. -l options benefit only from the -L options listed before it.
dnl Otherwise, add it to the front of LIBS, because it may be a static
dnl library that depends on another static library that is present in LIBS.
dnl Static libraries benefit only from the static libraries listed after
dnl it.
case " $LIB[]NAME" in
*" -l"*) LIBS="$LIBS $LIB[]NAME" ;;
*) LIBS="$LIB[]NAME $LIBS" ;;
esac
AC_TRY_LINK([$3], [$4],
[ac_cv_lib[]Name=yes],
[ac_cv_lib[]Name='m4_if([$5], [], [no], [[$5]])'])
LIBS="$ac_save_LIBS"
])
if test "$ac_cv_lib[]Name" = yes; then
HAVE_LIB[]NAME=yes
AC_DEFINE([HAVE_LIB]NAME, 1, [Define if you have the lib][$1 library.])
AC_MSG_CHECKING([how to link with lib[]$1])
AC_MSG_RESULT([$LIB[]NAME])
else
HAVE_LIB[]NAME=no
dnl If $LIB[]NAME didn't lead to a usable library, we don't need
dnl $INC[]NAME either.
CPPFLAGS="$ac_save_CPPFLAGS"
LIB[]NAME=
LTLIB[]NAME=
LIB[]NAME[]_PREFIX=
fi
AC_SUBST([HAVE_LIB]NAME)
AC_SUBST([LIB]NAME)
AC_SUBST([LTLIB]NAME)
AC_SUBST([LIB]NAME[_PREFIX])
popdef([NAME])
popdef([Name])
])
dnl Determine the platform dependent parameters needed to use rpath:
dnl acl_libext,
dnl acl_shlibext,
dnl acl_hardcode_libdir_flag_spec,
dnl acl_hardcode_libdir_separator,
dnl acl_hardcode_direct,
dnl acl_hardcode_minus_L.
AC_DEFUN([AC_LIB_RPATH],
[
dnl Tell automake >= 1.10 to complain if config.rpath is missing.
m4_ifdef([AC_REQUIRE_AUX_FILE], [AC_REQUIRE_AUX_FILE([config.rpath])])
AC_REQUIRE([AC_PROG_CC]) dnl we use $CC, $GCC, $LDFLAGS
AC_REQUIRE([AC_LIB_PROG_LD]) dnl we use $LD, $with_gnu_ld
AC_REQUIRE([AC_CANONICAL_HOST]) dnl we use $host
AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT]) dnl we use $ac_aux_dir
AC_CACHE_CHECK([for shared library run path origin], [acl_cv_rpath], [
CC="$CC" GCC="$GCC" LDFLAGS="$LDFLAGS" LD="$LD" with_gnu_ld="$with_gnu_ld" \
${CONFIG_SHELL-/bin/sh} "$ac_aux_dir/config.rpath" "$host" > conftest.sh
. ./conftest.sh
rm -f ./conftest.sh
acl_cv_rpath=done
])
wl="$acl_cv_wl"
acl_libext="$acl_cv_libext"
acl_shlibext="$acl_cv_shlibext"
acl_libname_spec="$acl_cv_libname_spec"
acl_library_names_spec="$acl_cv_library_names_spec"
acl_hardcode_libdir_flag_spec="$acl_cv_hardcode_libdir_flag_spec"
acl_hardcode_libdir_separator="$acl_cv_hardcode_libdir_separator"
acl_hardcode_direct="$acl_cv_hardcode_direct"
acl_hardcode_minus_L="$acl_cv_hardcode_minus_L"
dnl Determine whether the user wants rpath handling at all.
AC_ARG_ENABLE([rpath],
[ --disable-rpath do not hardcode runtime library paths],
:, enable_rpath=yes)
])
dnl AC_LIB_FROMPACKAGE(name, package)
dnl declares that libname comes from the given package. The configure file
dnl will then not have a --with-libname-prefix option but a
dnl --with-package-prefix option. Several libraries can come from the same
dnl package. This declaration must occur before an AC_LIB_LINKFLAGS or similar
dnl macro call that searches for libname.
AC_DEFUN([AC_LIB_FROMPACKAGE],
[
pushdef([NAME],[translit([$1],[abcdefghijklmnopqrstuvwxyz./-],
[ABCDEFGHIJKLMNOPQRSTUVWXYZ___])])
define([acl_frompackage_]NAME, [$2])
popdef([NAME])
pushdef([PACK],[$2])
pushdef([PACKUP],[translit(PACK,[abcdefghijklmnopqrstuvwxyz./-],
[ABCDEFGHIJKLMNOPQRSTUVWXYZ___])])
define([acl_libsinpackage_]PACKUP,
m4_ifdef([acl_libsinpackage_]PACKUP, [acl_libsinpackage_]PACKUP[[, ]],)[lib$1])
popdef([PACKUP])
popdef([PACK])
])
dnl AC_LIB_LINKFLAGS_BODY(name [, dependencies]) searches for libname and
dnl the libraries corresponding to explicit and implicit dependencies.
dnl Sets the LIB${NAME}, LTLIB${NAME} and INC${NAME} variables.
dnl Also, sets the LIB${NAME}_PREFIX variable to nonempty if libname was found
dnl in ${LIB${NAME}_PREFIX}/$acl_libdirstem.
AC_DEFUN([AC_LIB_LINKFLAGS_BODY],
[
AC_REQUIRE([AC_LIB_PREPARE_MULTILIB])
pushdef([NAME],[translit([$1],[abcdefghijklmnopqrstuvwxyz./-],
[ABCDEFGHIJKLMNOPQRSTUVWXYZ___])])
pushdef([PACK],[m4_ifdef([acl_frompackage_]NAME, [acl_frompackage_]NAME, lib[$1])])
pushdef([PACKUP],[translit(PACK,[abcdefghijklmnopqrstuvwxyz./-],
[ABCDEFGHIJKLMNOPQRSTUVWXYZ___])])
pushdef([PACKLIBS],[m4_ifdef([acl_frompackage_]NAME, [acl_libsinpackage_]PACKUP, lib[$1])])
dnl Autoconf >= 2.61 supports dots in --with options.
pushdef([P_A_C_K],[m4_if(m4_version_compare(m4_defn([m4_PACKAGE_VERSION]),[2.61]),[-1],[translit(PACK,[.],[_])],PACK)])
dnl By default, look in $includedir and $libdir.
use_additional=yes
AC_LIB_WITH_FINAL_PREFIX([
eval additional_includedir=\"$includedir\"
eval additional_libdir=\"$libdir\"
])
AC_ARG_WITH(P_A_C_K[-prefix],
[[ --with-]]P_A_C_K[[-prefix[=DIR] search for ]PACKLIBS[ in DIR/include and DIR/lib
--without-]]P_A_C_K[[-prefix don't search for ]PACKLIBS[ in includedir and libdir]],
[
if test "X$withval" = "Xno"; then
use_additional=no
else
if test "X$withval" = "X"; then
AC_LIB_WITH_FINAL_PREFIX([
eval additional_includedir=\"$includedir\"
eval additional_libdir=\"$libdir\"
])
else
additional_includedir="$withval/include"
additional_libdir="$withval/$acl_libdirstem"
if test "$acl_libdirstem2" != "$acl_libdirstem" \
&& ! test -d "$withval/$acl_libdirstem"; then
additional_libdir="$withval/$acl_libdirstem2"
fi
fi
fi
])
dnl Search the library and its dependencies in $additional_libdir and
dnl $LDFLAGS. Using breadth-first-seach.
LIB[]NAME=
LTLIB[]NAME=
INC[]NAME=
LIB[]NAME[]_PREFIX=
dnl HAVE_LIB${NAME} is an indicator that LIB${NAME}, LTLIB${NAME} have been
dnl computed. So it has to be reset here.
HAVE_LIB[]NAME=
rpathdirs=
ltrpathdirs=
names_already_handled=
names_next_round='$1 $2'
while test -n "$names_next_round"; do
names_this_round="$names_next_round"
names_next_round=
for name in $names_this_round; do
already_handled=
for n in $names_already_handled; do
if test "$n" = "$name"; then
already_handled=yes
break
fi
done
if test -z "$already_handled"; then
names_already_handled="$names_already_handled $name"
dnl See if it was already located by an earlier AC_LIB_LINKFLAGS
dnl or AC_LIB_HAVE_LINKFLAGS call.
uppername=`echo "$name" | sed -e 'y|abcdefghijklmnopqrstuvwxyz./-|ABCDEFGHIJKLMNOPQRSTUVWXYZ___|'`
eval value=\"\$HAVE_LIB$uppername\"
if test -n "$value"; then
if test "$value" = yes; then
eval value=\"\$LIB$uppername\"
test -z "$value" || LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$value"
eval value=\"\$LTLIB$uppername\"
test -z "$value" || LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }$value"
else
dnl An earlier call to AC_LIB_HAVE_LINKFLAGS has determined
dnl that this library doesn't exist. So just drop it.
:
fi
else
dnl Search the library lib$name in $additional_libdir and $LDFLAGS
dnl and the already constructed $LIBNAME/$LTLIBNAME.
found_dir=
found_la=
found_so=
found_a=
eval libname=\"$acl_libname_spec\" # typically: libname=lib$name
if test -n "$acl_shlibext"; then
shrext=".$acl_shlibext" # typically: shrext=.so
else
shrext=
fi
if test $use_additional = yes; then
dir="$additional_libdir"
dnl The same code as in the loop below:
dnl First look for a shared library.
if test -n "$acl_shlibext"; then
if test -f "$dir/$libname$shrext"; then
found_dir="$dir"
found_so="$dir/$libname$shrext"
else
if test "$acl_library_names_spec" = '$libname$shrext$versuffix'; then
ver=`(cd "$dir" && \
for f in "$libname$shrext".*; do echo "$f"; done \
| sed -e "s,^$libname$shrext\\\\.,," \
| sort -t '.' -n -r -k1,1 -k2,2 -k3,3 -k4,4 -k5,5 \
| sed 1q ) 2>/dev/null`
if test -n "$ver" && test -f "$dir/$libname$shrext.$ver"; then
found_dir="$dir"
found_so="$dir/$libname$shrext.$ver"
fi
else
eval library_names=\"$acl_library_names_spec\"
for f in $library_names; do
if test -f "$dir/$f"; then
found_dir="$dir"
found_so="$dir/$f"
break
fi
done
fi
fi
fi
dnl Then look for a static library.
if test "X$found_dir" = "X"; then
if test -f "$dir/$libname.$acl_libext"; then
found_dir="$dir"
found_a="$dir/$libname.$acl_libext"
fi
fi
if test "X$found_dir" != "X"; then
if test -f "$dir/$libname.la"; then
found_la="$dir/$libname.la"
fi
fi
fi
if test "X$found_dir" = "X"; then
for x in $LDFLAGS $LTLIB[]NAME; do
AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"])
case "$x" in
-L*)
dir=`echo "X$x" | sed -e 's/^X-L//'`
dnl First look for a shared library.
if test -n "$acl_shlibext"; then
if test -f "$dir/$libname$shrext"; then
found_dir="$dir"
found_so="$dir/$libname$shrext"
else
if test "$acl_library_names_spec" = '$libname$shrext$versuffix'; then
ver=`(cd "$dir" && \
for f in "$libname$shrext".*; do echo "$f"; done \
| sed -e "s,^$libname$shrext\\\\.,," \
| sort -t '.' -n -r -k1,1 -k2,2 -k3,3 -k4,4 -k5,5 \
| sed 1q ) 2>/dev/null`
if test -n "$ver" && test -f "$dir/$libname$shrext.$ver"; then
found_dir="$dir"
found_so="$dir/$libname$shrext.$ver"
fi
else
eval library_names=\"$acl_library_names_spec\"
for f in $library_names; do
if test -f "$dir/$f"; then
found_dir="$dir"
found_so="$dir/$f"
break
fi
done
fi
fi
fi
dnl Then look for a static library.
if test "X$found_dir" = "X"; then
if test -f "$dir/$libname.$acl_libext"; then
found_dir="$dir"
found_a="$dir/$libname.$acl_libext"
fi
fi
if test "X$found_dir" != "X"; then
if test -f "$dir/$libname.la"; then
found_la="$dir/$libname.la"
fi
fi
;;
esac
if test "X$found_dir" != "X"; then
break
fi
done
fi
if test "X$found_dir" != "X"; then
dnl Found the library.
LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-L$found_dir -l$name"
if test "X$found_so" != "X"; then
dnl Linking with a shared library. We attempt to hardcode its
dnl directory into the executable's runpath, unless it's the
dnl standard /usr/lib.
if test "$enable_rpath" = no \
|| test "X$found_dir" = "X/usr/$acl_libdirstem" \
|| test "X$found_dir" = "X/usr/$acl_libdirstem2"; then
dnl No hardcoding is needed.
LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so"
else
dnl Use an explicit option to hardcode DIR into the resulting
dnl binary.
dnl Potentially add DIR to ltrpathdirs.
dnl The ltrpathdirs will be appended to $LTLIBNAME at the end.
haveit=
for x in $ltrpathdirs; do
if test "X$x" = "X$found_dir"; then
haveit=yes
break
fi
done
if test -z "$haveit"; then
ltrpathdirs="$ltrpathdirs $found_dir"
fi
dnl The hardcoding into $LIBNAME is system dependent.
if test "$acl_hardcode_direct" = yes; then
dnl Using DIR/libNAME.so during linking hardcodes DIR into the
dnl resulting binary.
LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so"
else
if test -n "$acl_hardcode_libdir_flag_spec" && test "$acl_hardcode_minus_L" = no; then
dnl Use an explicit option to hardcode DIR into the resulting
dnl binary.
LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so"
dnl Potentially add DIR to rpathdirs.
dnl The rpathdirs will be appended to $LIBNAME at the end.
haveit=
for x in $rpathdirs; do
if test "X$x" = "X$found_dir"; then
haveit=yes
break
fi
done
if test -z "$haveit"; then
rpathdirs="$rpathdirs $found_dir"
fi
else
dnl Rely on "-L$found_dir".
dnl But don't add it if it's already contained in the LDFLAGS
dnl or the already constructed $LIBNAME
haveit=
for x in $LDFLAGS $LIB[]NAME; do
AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"])
if test "X$x" = "X-L$found_dir"; then
haveit=yes
break
fi
done
if test -z "$haveit"; then
LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-L$found_dir"
fi
if test "$acl_hardcode_minus_L" != no; then
dnl FIXME: Not sure whether we should use
dnl "-L$found_dir -l$name" or "-L$found_dir $found_so"
dnl here.
LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so"
else
dnl We cannot use $acl_hardcode_runpath_var and LD_RUN_PATH
dnl here, because this doesn't fit in flags passed to the
dnl compiler. So give up. No hardcoding. This affects only
dnl very old systems.
dnl FIXME: Not sure whether we should use
dnl "-L$found_dir -l$name" or "-L$found_dir $found_so"
dnl here.
LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-l$name"
fi
fi
fi
fi
else
if test "X$found_a" != "X"; then
dnl Linking with a static library.
LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_a"
else
dnl We shouldn't come here, but anyway it's good to have a
dnl fallback.
LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-L$found_dir -l$name"
fi
fi
dnl Assume the include files are nearby.
additional_includedir=
case "$found_dir" in
*/$acl_libdirstem | */$acl_libdirstem/)
basedir=`echo "X$found_dir" | sed -e 's,^X,,' -e "s,/$acl_libdirstem/"'*$,,'`
if test "$name" = '$1'; then
LIB[]NAME[]_PREFIX="$basedir"
fi
additional_includedir="$basedir/include"
;;
*/$acl_libdirstem2 | */$acl_libdirstem2/)
basedir=`echo "X$found_dir" | sed -e 's,^X,,' -e "s,/$acl_libdirstem2/"'*$,,'`
if test "$name" = '$1'; then
LIB[]NAME[]_PREFIX="$basedir"
fi
additional_includedir="$basedir/include"
;;
esac
if test "X$additional_includedir" != "X"; then
dnl Potentially add $additional_includedir to $INCNAME.
dnl But don't add it
dnl 1. if it's the standard /usr/include,
dnl 2. if it's /usr/local/include and we are using GCC on Linux,
dnl 3. if it's already present in $CPPFLAGS or the already
dnl constructed $INCNAME,
dnl 4. if it doesn't exist as a directory.
if test "X$additional_includedir" != "X/usr/include"; then
haveit=
if test "X$additional_includedir" = "X/usr/local/include"; then
if test -n "$GCC"; then
case $host_os in
linux* | gnu* | k*bsd*-gnu) haveit=yes;;
esac
fi
fi
if test -z "$haveit"; then
for x in $CPPFLAGS $INC[]NAME; do
AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"])
if test "X$x" = "X-I$additional_includedir"; then
haveit=yes
break
fi
done
if test -z "$haveit"; then
if test -d "$additional_includedir"; then
dnl Really add $additional_includedir to $INCNAME.
INC[]NAME="${INC[]NAME}${INC[]NAME:+ }-I$additional_includedir"
fi
fi
fi
fi
fi
dnl Look for dependencies.
if test -n "$found_la"; then
dnl Read the .la file. It defines the variables
dnl dlname, library_names, old_library, dependency_libs, current,
dnl age, revision, installed, dlopen, dlpreopen, libdir.
save_libdir="$libdir"
case "$found_la" in
*/* | *\\*) . "$found_la" ;;
*) . "./$found_la" ;;
esac
libdir="$save_libdir"
dnl We use only dependency_libs.
for dep in $dependency_libs; do
case "$dep" in
-L*)
additional_libdir=`echo "X$dep" | sed -e 's/^X-L//'`
dnl Potentially add $additional_libdir to $LIBNAME and $LTLIBNAME.
dnl But don't add it
dnl 1. if it's the standard /usr/lib,
dnl 2. if it's /usr/local/lib and we are using GCC on Linux,
dnl 3. if it's already present in $LDFLAGS or the already
dnl constructed $LIBNAME,
dnl 4. if it doesn't exist as a directory.
if test "X$additional_libdir" != "X/usr/$acl_libdirstem" \
&& test "X$additional_libdir" != "X/usr/$acl_libdirstem2"; then
haveit=
if test "X$additional_libdir" = "X/usr/local/$acl_libdirstem" \
|| test "X$additional_libdir" = "X/usr/local/$acl_libdirstem2"; then
if test -n "$GCC"; then
case $host_os in
linux* | gnu* | k*bsd*-gnu) haveit=yes;;
esac
fi
fi
if test -z "$haveit"; then
haveit=
for x in $LDFLAGS $LIB[]NAME; do
AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"])
if test "X$x" = "X-L$additional_libdir"; then
haveit=yes
break
fi
done
if test -z "$haveit"; then
if test -d "$additional_libdir"; then
dnl Really add $additional_libdir to $LIBNAME.
LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-L$additional_libdir"
fi
fi
haveit=
for x in $LDFLAGS $LTLIB[]NAME; do
AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"])
if test "X$x" = "X-L$additional_libdir"; then
haveit=yes
break
fi
done
if test -z "$haveit"; then
if test -d "$additional_libdir"; then
dnl Really add $additional_libdir to $LTLIBNAME.
LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-L$additional_libdir"
fi
fi
fi
fi
;;
-R*)
dir=`echo "X$dep" | sed -e 's/^X-R//'`
if test "$enable_rpath" != no; then
dnl Potentially add DIR to rpathdirs.
dnl The rpathdirs will be appended to $LIBNAME at the end.
haveit=
for x in $rpathdirs; do
if test "X$x" = "X$dir"; then
haveit=yes
break
fi
done
if test -z "$haveit"; then
rpathdirs="$rpathdirs $dir"
fi
dnl Potentially add DIR to ltrpathdirs.
dnl The ltrpathdirs will be appended to $LTLIBNAME at the end.
haveit=
for x in $ltrpathdirs; do
if test "X$x" = "X$dir"; then
haveit=yes
break
fi
done
if test -z "$haveit"; then
ltrpathdirs="$ltrpathdirs $dir"
fi
fi
;;
-l*)
dnl Handle this in the next round.
names_next_round="$names_next_round "`echo "X$dep" | sed -e 's/^X-l//'`
;;
*.la)
dnl Handle this in the next round. Throw away the .la's
dnl directory; it is already contained in a preceding -L
dnl option.
names_next_round="$names_next_round "`echo "X$dep" | sed -e 's,^X.*/,,' -e 's,^lib,,' -e 's,\.la$,,'`
;;
*)
dnl Most likely an immediate library name.
LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$dep"
LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }$dep"
;;
esac
done
fi
else
dnl Didn't find the library; assume it is in the system directories
dnl known to the linker and runtime loader. (All the system
dnl directories known to the linker should also be known to the
dnl runtime loader, otherwise the system is severely misconfigured.)
LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-l$name"
LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-l$name"
fi
fi
fi
done
done
if test "X$rpathdirs" != "X"; then
if test -n "$acl_hardcode_libdir_separator"; then
dnl Weird platform: only the last -rpath option counts, the user must
dnl pass all path elements in one option. We can arrange that for a
dnl single library, but not when more than one $LIBNAMEs are used.
alldirs=
for found_dir in $rpathdirs; do
alldirs="${alldirs}${alldirs:+$acl_hardcode_libdir_separator}$found_dir"
done
dnl Note: acl_hardcode_libdir_flag_spec uses $libdir and $wl.
acl_save_libdir="$libdir"
libdir="$alldirs"
eval flag=\"$acl_hardcode_libdir_flag_spec\"
libdir="$acl_save_libdir"
LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$flag"
else
dnl The -rpath options are cumulative.
for found_dir in $rpathdirs; do
acl_save_libdir="$libdir"
libdir="$found_dir"
eval flag=\"$acl_hardcode_libdir_flag_spec\"
libdir="$acl_save_libdir"
LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$flag"
done
fi
fi
if test "X$ltrpathdirs" != "X"; then
dnl When using libtool, the option that works for both libraries and
dnl executables is -R. The -R options are cumulative.
for found_dir in $ltrpathdirs; do
LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-R$found_dir"
done
fi
popdef([P_A_C_K])
popdef([PACKLIBS])
popdef([PACKUP])
popdef([PACK])
popdef([NAME])
])
dnl AC_LIB_APPENDTOVAR(VAR, CONTENTS) appends the elements of CONTENTS to VAR,
dnl unless already present in VAR.
dnl Works only for CPPFLAGS, not for LIB* variables because that sometimes
dnl contains two or three consecutive elements that belong together.
AC_DEFUN([AC_LIB_APPENDTOVAR],
[
for element in [$2]; do
haveit=
for x in $[$1]; do
AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"])
if test "X$x" = "X$element"; then
haveit=yes
break
fi
done
if test -z "$haveit"; then
[$1]="${[$1]}${[$1]:+ }$element"
fi
done
])
dnl For those cases where a variable contains several -L and -l options
dnl referring to unknown libraries and directories, this macro determines the
dnl necessary additional linker options for the runtime path.
dnl AC_LIB_LINKFLAGS_FROM_LIBS([LDADDVAR], [LIBSVALUE], [USE-LIBTOOL])
dnl sets LDADDVAR to linker options needed together with LIBSVALUE.
dnl If USE-LIBTOOL evaluates to non-empty, linking with libtool is assumed,
dnl otherwise linking without libtool is assumed.
AC_DEFUN([AC_LIB_LINKFLAGS_FROM_LIBS],
[
AC_REQUIRE([AC_LIB_RPATH])
AC_REQUIRE([AC_LIB_PREPARE_MULTILIB])
$1=
if test "$enable_rpath" != no; then
if test -n "$acl_hardcode_libdir_flag_spec" && test "$acl_hardcode_minus_L" = no; then
dnl Use an explicit option to hardcode directories into the resulting
dnl binary.
rpathdirs=
next=
for opt in $2; do
if test -n "$next"; then
dir="$next"
dnl No need to hardcode the standard /usr/lib.
if test "X$dir" != "X/usr/$acl_libdirstem" \
&& test "X$dir" != "X/usr/$acl_libdirstem2"; then
rpathdirs="$rpathdirs $dir"
fi
next=
else
case $opt in
-L) next=yes ;;
-L*) dir=`echo "X$opt" | sed -e 's,^X-L,,'`
dnl No need to hardcode the standard /usr/lib.
if test "X$dir" != "X/usr/$acl_libdirstem" \
&& test "X$dir" != "X/usr/$acl_libdirstem2"; then
rpathdirs="$rpathdirs $dir"
fi
next= ;;
*) next= ;;
esac
fi
done
if test "X$rpathdirs" != "X"; then
if test -n ""$3""; then
dnl libtool is used for linking. Use -R options.
for dir in $rpathdirs; do
$1="${$1}${$1:+ }-R$dir"
done
else
dnl The linker is used for linking directly.
if test -n "$acl_hardcode_libdir_separator"; then
dnl Weird platform: only the last -rpath option counts, the user
dnl must pass all path elements in one option.
alldirs=
for dir in $rpathdirs; do
alldirs="${alldirs}${alldirs:+$acl_hardcode_libdir_separator}$dir"
done
acl_save_libdir="$libdir"
libdir="$alldirs"
eval flag=\"$acl_hardcode_libdir_flag_spec\"
libdir="$acl_save_libdir"
$1="$flag"
else
dnl The -rpath options are cumulative.
for dir in $rpathdirs; do
acl_save_libdir="$libdir"
libdir="$dir"
eval flag=\"$acl_hardcode_libdir_flag_spec\"
libdir="$acl_save_libdir"
$1="${$1}${$1:+ }$flag"
done
fi
fi
fi
fi
fi
AC_SUBST([$1])
])
================================================
FILE: m4/lib-prefix.m4
================================================
# lib-prefix.m4 serial 7 (gettext-0.18)
dnl Copyright (C) 2001-2005, 2008-2010 Free Software Foundation, Inc.
dnl This file is free software; the Free Software Foundation
dnl gives unlimited permission to copy and/or distribute it,
dnl with or without modifications, as long as this notice is preserved.
dnl From Bruno Haible.
dnl AC_LIB_ARG_WITH is synonymous to AC_ARG_WITH in autoconf-2.13, and
dnl similar to AC_ARG_WITH in autoconf 2.52...2.57 except that is doesn't
dnl require excessive bracketing.
ifdef([AC_HELP_STRING],
[AC_DEFUN([AC_LIB_ARG_WITH], [AC_ARG_WITH([$1],[[$2]],[$3],[$4])])],
[AC_DEFUN([AC_][LIB_ARG_WITH], [AC_ARG_WITH([$1],[$2],[$3],[$4])])])
dnl AC_LIB_PREFIX adds to the CPPFLAGS and LDFLAGS the flags that are needed
dnl to access previously installed libraries. The basic assumption is that
dnl a user will want packages to use other packages he previously installed
dnl with the same --prefix option.
dnl This macro is not needed if only AC_LIB_LINKFLAGS is used to locate
dnl libraries, but is otherwise very convenient.
AC_DEFUN([AC_LIB_PREFIX],
[
AC_BEFORE([$0], [AC_LIB_LINKFLAGS])
AC_REQUIRE([AC_PROG_CC])
AC_REQUIRE([AC_CANONICAL_HOST])
AC_REQUIRE([AC_LIB_PREPARE_MULTILIB])
AC_REQUIRE([AC_LIB_PREPARE_PREFIX])
dnl By default, look in $includedir and $libdir.
use_additional=yes
AC_LIB_WITH_FINAL_PREFIX([
eval additional_includedir=\"$includedir\"
eval additional_libdir=\"$libdir\"
])
AC_LIB_ARG_WITH([lib-prefix],
[ --with-lib-prefix[=DIR] search for libraries in DIR/include and DIR/lib
--without-lib-prefix don't search for libraries in includedir and libdir],
[
if test "X$withval" = "Xno"; then
use_additional=no
else
if test "X$withval" = "X"; then
AC_LIB_WITH_FINAL_PREFIX([
eval additional_includedir=\"$includedir\"
eval additional_libdir=\"$libdir\"
])
else
additional_includedir="$withval/include"
additional_libdir="$withval/$acl_libdirstem"
fi
fi
])
if test $use_additional = yes; then
dnl Potentially add $additional_includedir to $CPPFLAGS.
dnl But don't add it
dnl 1. if it's the standard /usr/include,
dnl 2. if it's already present in $CPPFLAGS,
dnl 3. if it's /usr/local/include and we are using GCC on Linux,
dnl 4. if it doesn't exist as a directory.
if test "X$additional_includedir" != "X/usr/include"; then
haveit=
for x in $CPPFLAGS; do
AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"])
if test "X$x" = "X-I$additional_includedir"; then
haveit=yes
break
fi
done
if test -z "$haveit"; then
if test "X$additional_includedir" = "X/usr/local/include"; then
if test -n "$GCC"; then
case $host_os in
linux* | gnu* | k*bsd*-gnu) haveit=yes;;
esac
fi
fi
if test -z "$haveit"; then
if test -d "$additional_includedir"; then
dnl Really add $additional_includedir to $CPPFLAGS.
CPPFLAGS="${CPPFLAGS}${CPPFLAGS:+ }-I$additional_includedir"
fi
fi
fi
fi
dnl Potentially add $additional_libdir to $LDFLAGS.
dnl But don't add it
dnl 1. if it's the standard /usr/lib,
dnl 2. if it's already present in $LDFLAGS,
dnl 3. if it's /usr/local/lib and we are using GCC on Linux,
dnl 4. if it doesn't exist as a directory.
if test "X$additional_libdir" != "X/usr/$acl_libdirstem"; then
haveit=
for x in $LDFLAGS; do
AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"])
if test "X$x" = "X-L$additional_libdir"; then
haveit=yes
break
fi
done
if test -z "$haveit"; then
if test "X$additional_libdir" = "X/usr/local/$acl_libdirstem"; then
if test -n "$GCC"; then
case $host_os in
linux*) haveit=yes;;
esac
fi
fi
if test -z "$haveit"; then
if test -d "$additional_libdir"; then
dnl Really add $additional_libdir to $LDFLAGS.
LDFLAGS="${LDFLAGS}${LDFLAGS:+ }-L$additional_libdir"
fi
fi
fi
fi
fi
])
dnl AC_LIB_PREPARE_PREFIX creates variables acl_final_prefix,
dnl acl_final_exec_prefix, containing the values to which $prefix and
dnl $exec_prefix will expand at the end of the configure script.
AC_DEFUN([AC_LIB_PREPARE_PREFIX],
[
dnl Unfortunately, prefix and exec_prefix get only finally determined
dnl at the end of configure.
if test "X$prefix" = "XNONE"; then
acl_final_prefix="$ac_default_prefix"
else
acl_final_prefix="$prefix"
fi
if test "X$exec_prefix" = "XNONE"; then
acl_final_exec_prefix='${prefix}'
else
acl_final_exec_prefix="$exec_prefix"
fi
acl_save_prefix="$prefix"
prefix="$acl_final_prefix"
eval acl_final_exec_prefix=\"$acl_final_exec_prefix\"
prefix="$acl_save_prefix"
])
dnl AC_LIB_WITH_FINAL_PREFIX([statement]) evaluates statement, with the
dnl variables prefix and exec_prefix bound to the values they will have
dnl at the end of the configure script.
AC_DEFUN([AC_LIB_WITH_FINAL_PREFIX],
[
acl_save_prefix="$prefix"
prefix="$acl_final_prefix"
acl_save_exec_prefix="$exec_prefix"
exec_prefix="$acl_final_exec_prefix"
$1
exec_prefix="$acl_save_exec_prefix"
prefix="$acl_save_prefix"
])
dnl AC_LIB_PREPARE_MULTILIB creates
dnl - a variable acl_libdirstem, containing the basename of the libdir, either
dnl "lib" or "lib64" or "lib/64",
dnl - a variable acl_libdirstem2, as a secondary possible value for
dnl acl_libdirstem, either the same as acl_libdirstem or "lib/sparcv9" or
dnl "lib/amd64".
AC_DEFUN([AC_LIB_PREPARE_MULTILIB],
[
dnl There is no formal standard regarding lib and lib64.
dnl On glibc systems, the current practice is that on a system supporting
dnl 32-bit and 64-bit instruction sets or ABIs, 64-bit libraries go under
dnl $prefix/lib64 and 32-bit libraries go under $prefix/lib. We determine
dnl the compiler's default mode by looking at the compiler's library search
dnl path. If at least one of its elements ends in /lib64 or points to a
dnl directory whose absolute pathname ends in /lib64, we assume a 64-bit ABI.
dnl Otherwise we use the default, namely "lib".
dnl On Solaris systems, the current practice is that on a system supporting
dnl 32-bit and 64-bit instruction sets or ABIs, 64-bit libraries go under
dnl $prefix/lib/64 (which is a symlink to either $prefix/lib/sparcv9 or
dnl $prefix/lib/amd64) and 32-bit libraries go under $prefix/lib.
AC_REQUIRE([AC_CANONICAL_HOST])
acl_libdirstem=lib
acl_libdirstem2=
case "$host_os" in
solaris*)
dnl See Solaris 10 Software Developer Collection > Solaris 64-bit Developer's Guide > The Development Environment
dnl .
dnl "Portable Makefiles should refer to any library directories using the 64 symbolic link."
dnl But we want to recognize the sparcv9 or amd64 subdirectory also if the
dnl symlink is missing, so we set acl_libdirstem2 too.
AC_CACHE_CHECK([for 64-bit host], [gl_cv_solaris_64bit],
[AC_EGREP_CPP([sixtyfour bits], [
#ifdef _LP64
sixtyfour bits
#endif
], [gl_cv_solaris_64bit=yes], [gl_cv_solaris_64bit=no])
])
if test $gl_cv_solaris_64bit = yes; then
acl_libdirstem=lib/64
case "$host_cpu" in
sparc*) acl_libdirstem2=lib/sparcv9 ;;
i*86 | x86_64) acl_libdirstem2=lib/amd64 ;;
esac
fi
;;
*)
searchpath=`(LC_ALL=C $CC -print-search-dirs) 2>/dev/null | sed -n -e 's,^libraries: ,,p' | sed -e 's,^=,,'`
if test -n "$searchpath"; then
acl_save_IFS="${IFS= }"; IFS=":"
for searchdir in $searchpath; do
if test -d "$searchdir"; then
case "$searchdir" in
*/lib64/ | */lib64 ) acl_libdirstem=lib64 ;;
*/../ | */.. )
# Better ignore directories of this form. They are misleading.
;;
*) searchdir=`cd "$searchdir" && pwd`
case "$searchdir" in
*/lib64 ) acl_libdirstem=lib64 ;;
esac ;;
esac
fi
done
IFS="$acl_save_IFS"
fi
;;
esac
test -n "$acl_libdirstem2" || acl_libdirstem2="$acl_libdirstem"
])
================================================
FILE: m4/nls.m4
================================================
# nls.m4 serial 5 (gettext-0.18)
dnl Copyright (C) 1995-2003, 2005-2006, 2008-2010 Free Software Foundation,
dnl Inc.
dnl This file is free software; the Free Software Foundation
dnl gives unlimited permission to copy and/or distribute it,
dnl with or without modifications, as long as this notice is preserved.
dnl
dnl This file can can be used in projects which are not available under
dnl the GNU General Public License or the GNU Library General Public
dnl License but which still want to provide support for the GNU gettext
dnl functionality.
dnl Please note that the actual code of the GNU gettext library is covered
dnl by the GNU Library General Public License, and the rest of the GNU
dnl gettext package package is covered by the GNU General Public License.
dnl They are *not* in the public domain.
dnl Authors:
dnl Ulrich Drepper , 1995-2000.
dnl Bruno Haible , 2000-2003.
AC_PREREQ([2.50])
AC_DEFUN([AM_NLS],
[
AC_MSG_CHECKING([whether NLS is requested])
dnl Default is enabled NLS
AC_ARG_ENABLE([nls],
[ --disable-nls do not use Native Language Support],
USE_NLS=$enableval, USE_NLS=yes)
AC_MSG_RESULT([$USE_NLS])
AC_SUBST([USE_NLS])
])
================================================
FILE: m4/po.m4
================================================
# po.m4 serial 17 (gettext-0.18)
dnl Copyright (C) 1995-2010 Free Software Foundation, Inc.
dnl This file is free software; the Free Software Foundation
dnl gives unlimited permission to copy and/or distribute it,
dnl with or without modifications, as long as this notice is preserved.
dnl
dnl This file can can be used in projects which are not available under
dnl the GNU General Public License or the GNU Library General Public
dnl License but which still want to provide support for the GNU gettext
dnl functionality.
dnl Please note that the actual code of the GNU gettext library is covered
dnl by the GNU Library General Public License, and the rest of the GNU
dnl gettext package package is covered by the GNU General Public License.
dnl They are *not* in the public domain.
dnl Authors:
dnl Ulrich Drepper , 1995-2000.
dnl Bruno Haible , 2000-2003.
AC_PREREQ([2.50])
dnl Checks for all prerequisites of the po subdirectory.
AC_DEFUN([AM_PO_SUBDIRS],
[
AC_REQUIRE([AC_PROG_MAKE_SET])dnl
AC_REQUIRE([AC_PROG_INSTALL])dnl
AC_REQUIRE([AC_PROG_MKDIR_P])dnl defined by autoconf
AC_REQUIRE([AM_NLS])dnl
dnl Release version of the gettext macros. This is used to ensure that
dnl the gettext macros and po/Makefile.in.in are in sync.
AC_SUBST([GETTEXT_MACRO_VERSION], [0.18])
dnl Perform the following tests also if --disable-nls has been given,
dnl because they are needed for "make dist" to work.
dnl Search for GNU msgfmt in the PATH.
dnl The first test excludes Solaris msgfmt and early GNU msgfmt versions.
dnl The second test excludes FreeBSD msgfmt.
AM_PATH_PROG_WITH_TEST(MSGFMT, msgfmt,
[$ac_dir/$ac_word --statistics /dev/null >&]AS_MESSAGE_LOG_FD[ 2>&1 &&
(if $ac_dir/$ac_word --statistics /dev/null 2>&1 >/dev/null | grep usage >/dev/null; then exit 1; else exit 0; fi)],
:)
AC_PATH_PROG([GMSGFMT], [gmsgfmt], [$MSGFMT])
dnl Test whether it is GNU msgfmt >= 0.15.
changequote(,)dnl
case `$MSGFMT --version | sed 1q | sed -e 's,^[^0-9]*,,'` in
'' | 0.[0-9] | 0.[0-9].* | 0.1[0-4] | 0.1[0-4].*) MSGFMT_015=: ;;
*) MSGFMT_015=$MSGFMT ;;
esac
changequote([,])dnl
AC_SUBST([MSGFMT_015])
changequote(,)dnl
case `$GMSGFMT --version | sed 1q | sed -e 's,^[^0-9]*,,'` in
'' | 0.[0-9] | 0.[0-9].* | 0.1[0-4] | 0.1[0-4].*) GMSGFMT_015=: ;;
*) GMSGFMT_015=$GMSGFMT ;;
esac
changequote([,])dnl
AC_SUBST([GMSGFMT_015])
dnl Search for GNU xgettext 0.12 or newer in the PATH.
dnl The first test excludes Solaris xgettext and early GNU xgettext versions.
dnl The second test excludes FreeBSD xgettext.
AM_PATH_PROG_WITH_TEST(XGETTEXT, xgettext,
[$ac_dir/$ac_word --omit-header --copyright-holder= --msgid-bugs-address= /dev/null >&]AS_MESSAGE_LOG_FD[ 2>&1 &&
(if $ac_dir/$ac_word --omit-header --copyright-holder= --msgid-bugs-address= /dev/null 2>&1 >/dev/null | grep usage >/dev/null; then exit 1; else exit 0; fi)],
:)
dnl Remove leftover from FreeBSD xgettext call.
rm -f messages.po
dnl Test whether it is GNU xgettext >= 0.15.
changequote(,)dnl
case `$XGETTEXT --version | sed 1q | sed -e 's,^[^0-9]*,,'` in
'' | 0.[0-9] | 0.[0-9].* | 0.1[0-4] | 0.1[0-4].*) XGETTEXT_015=: ;;
*) XGETTEXT_015=$XGETTEXT ;;
esac
changequote([,])dnl
AC_SUBST([XGETTEXT_015])
dnl Search for GNU msgmerge 0.11 or newer in the PATH.
AM_PATH_PROG_WITH_TEST(MSGMERGE, msgmerge,
[$ac_dir/$ac_word --update -q /dev/null /dev/null >&]AS_MESSAGE_LOG_FD[ 2>&1], :)
dnl Installation directories.
dnl Autoconf >= 2.60 defines localedir. For older versions of autoconf, we
dnl have to define it here, so that it can be used in po/Makefile.
test -n "$localedir" || localedir='${datadir}/locale'
AC_SUBST([localedir])
dnl Support for AM_XGETTEXT_OPTION.
test -n "${XGETTEXT_EXTRA_OPTIONS+set}" || XGETTEXT_EXTRA_OPTIONS=
AC_SUBST([XGETTEXT_EXTRA_OPTIONS])
AC_CONFIG_COMMANDS([po-directories], [[
for ac_file in $CONFIG_FILES; do
# Support "outfile[:infile[:infile...]]"
case "$ac_file" in
*:*) ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;;
esac
# PO directories have a Makefile.in generated from Makefile.in.in.
case "$ac_file" in */Makefile.in)
# Adjust a relative srcdir.
ac_dir=`echo "$ac_file"|sed 's%/[^/][^/]*$%%'`
ac_dir_suffix="/`echo "$ac_dir"|sed 's%^\./%%'`"
ac_dots=`echo "$ac_dir_suffix"|sed 's%/[^/]*%../%g'`
# In autoconf-2.13 it is called $ac_given_srcdir.
# In autoconf-2.50 it is called $srcdir.
test -n "$ac_given_srcdir" || ac_given_srcdir="$srcdir"
case "$ac_given_srcdir" in
.) top_srcdir=`echo $ac_dots|sed 's%/$%%'` ;;
/*) top_srcdir="$ac_given_srcdir" ;;
*) top_srcdir="$ac_dots$ac_given_srcdir" ;;
esac
# Treat a directory as a PO directory if and only if it has a
# POTFILES.in file. This allows packages to have multiple PO
# directories under different names or in different locations.
if test -f "$ac_given_srcdir/$ac_dir/POTFILES.in"; then
rm -f "$ac_dir/POTFILES"
test -n "$as_me" && echo "$as_me: creating $ac_dir/POTFILES" || echo "creating $ac_dir/POTFILES"
cat "$ac_given_srcdir/$ac_dir/POTFILES.in" | sed -e "/^#/d" -e "/^[ ]*\$/d" -e "s,.*, $top_srcdir/& \\\\," | sed -e "\$s/\(.*\) \\\\/\1/" > "$ac_dir/POTFILES"
POMAKEFILEDEPS="POTFILES.in"
# ALL_LINGUAS, POFILES, UPDATEPOFILES, DUMMYPOFILES, GMOFILES depend
# on $ac_dir but don't depend on user-specified configuration
# parameters.
if test -f "$ac_given_srcdir/$ac_dir/LINGUAS"; then
# The LINGUAS file contains the set of available languages.
if test -n "$OBSOLETE_ALL_LINGUAS"; then
test -n "$as_me" && echo "$as_me: setting ALL_LINGUAS in configure.in is obsolete" || echo "setting ALL_LINGUAS in configure.in is obsolete"
fi
ALL_LINGUAS_=`sed -e "/^#/d" -e "s/#.*//" "$ac_given_srcdir/$ac_dir/LINGUAS"`
# Hide the ALL_LINGUAS assigment from automake < 1.5.
eval 'ALL_LINGUAS''=$ALL_LINGUAS_'
POMAKEFILEDEPS="$POMAKEFILEDEPS LINGUAS"
else
# The set of available languages was given in configure.in.
# Hide the ALL_LINGUAS assigment from automake < 1.5.
eval 'ALL_LINGUAS''=$OBSOLETE_ALL_LINGUAS'
fi
# Compute POFILES
# as $(foreach lang, $(ALL_LINGUAS), $(srcdir)/$(lang).po)
# Compute UPDATEPOFILES
# as $(foreach lang, $(ALL_LINGUAS), $(lang).po-update)
# Compute DUMMYPOFILES
# as $(foreach lang, $(ALL_LINGUAS), $(lang).nop)
# Compute GMOFILES
# as $(foreach lang, $(ALL_LINGUAS), $(srcdir)/$(lang).gmo)
case "$ac_given_srcdir" in
.) srcdirpre= ;;
*) srcdirpre='$(srcdir)/' ;;
esac
POFILES=
UPDATEPOFILES=
DUMMYPOFILES=
GMOFILES=
for lang in $ALL_LINGUAS; do
POFILES="$POFILES $srcdirpre$lang.po"
UPDATEPOFILES="$UPDATEPOFILES $lang.po-update"
DUMMYPOFILES="$DUMMYPOFILES $lang.nop"
GMOFILES="$GMOFILES $srcdirpre$lang.gmo"
done
# CATALOGS depends on both $ac_dir and the user's LINGUAS
# environment variable.
INST_LINGUAS=
if test -n "$ALL_LINGUAS"; then
for presentlang in $ALL_LINGUAS; do
useit=no
if test "%UNSET%" != "$LINGUAS"; then
desiredlanguages="$LINGUAS"
else
desiredlanguages="$ALL_LINGUAS"
fi
for desiredlang in $desiredlanguages; do
# Use the presentlang catalog if desiredlang is
# a. equal to presentlang, or
# b. a variant of presentlang (because in this case,
# presentlang can be used as a fallback for messages
# which are not translated in the desiredlang catalog).
case "$desiredlang" in
"$presentlang"*) useit=yes;;
esac
done
if test $useit = yes; then
INST_LINGUAS="$INST_LINGUAS $presentlang"
fi
done
fi
CATALOGS=
if test -n "$INST_LINGUAS"; then
for lang in $INST_LINGUAS; do
CATALOGS="$CATALOGS $lang.gmo"
done
fi
test -n "$as_me" && echo "$as_me: creating $ac_dir/Makefile" || echo "creating $ac_dir/Makefile"
sed -e "/^POTFILES =/r $ac_dir/POTFILES" -e "/^# Makevars/r $ac_given_srcdir/$ac_dir/Makevars" -e "s|@POFILES@|$POFILES|g" -e "s|@UPDATEPOFILES@|$UPDATEPOFILES|g" -e "s|@DUMMYPOFILES@|$DUMMYPOFILES|g" -e "s|@GMOFILES@|$GMOFILES|g" -e "s|@CATALOGS@|$CATALOGS|g" -e "s|@POMAKEFILEDEPS@|$POMAKEFILEDEPS|g" "$ac_dir/Makefile.in" > "$ac_dir/Makefile"
for f in "$ac_given_srcdir/$ac_dir"/Rules-*; do
if test -f "$f"; then
case "$f" in
*.orig | *.bak | *~) ;;
*) cat "$f" >> "$ac_dir/Makefile" ;;
esac
fi
done
fi
;;
esac
done]],
[# Capture the value of obsolete ALL_LINGUAS because we need it to compute
# POFILES, UPDATEPOFILES, DUMMYPOFILES, GMOFILES, CATALOGS. But hide it
# from automake < 1.5.
eval 'OBSOLETE_ALL_LINGUAS''="$ALL_LINGUAS"'
# Capture the value of LINGUAS because we need it to compute CATALOGS.
LINGUAS="${LINGUAS-%UNSET%}"
])
])
dnl Postprocesses a Makefile in a directory containing PO files.
AC_DEFUN([AM_POSTPROCESS_PO_MAKEFILE],
[
# When this code is run, in config.status, two variables have already been
# set:
# - OBSOLETE_ALL_LINGUAS is the value of LINGUAS set in configure.in,
# - LINGUAS is the value of the environment variable LINGUAS at configure
# time.
changequote(,)dnl
# Adjust a relative srcdir.
ac_dir=`echo "$ac_file"|sed 's%/[^/][^/]*$%%'`
ac_dir_suffix="/`echo "$ac_dir"|sed 's%^\./%%'`"
ac_dots=`echo "$ac_dir_suffix"|sed 's%/[^/]*%../%g'`
# In autoconf-2.13 it is called $ac_given_srcdir.
# In autoconf-2.50 it is called $srcdir.
test -n "$ac_given_srcdir" || ac_given_srcdir="$srcdir"
case "$ac_given_srcdir" in
.) top_srcdir=`echo $ac_dots|sed 's%/$%%'` ;;
/*) top_srcdir="$ac_given_srcdir" ;;
*) top_srcdir="$ac_dots$ac_given_srcdir" ;;
esac
# Find a way to echo strings without interpreting backslash.
if test "X`(echo '\t') 2>/dev/null`" = 'X\t'; then
gt_echo='echo'
else
if test "X`(printf '%s\n' '\t') 2>/dev/null`" = 'X\t'; then
gt_echo='printf %s\n'
else
echo_func () {
cat < "$ac_file.tmp"
if grep -l '@TCLCATALOGS@' "$ac_file" > /dev/null; then
# Add dependencies that cannot be formulated as a simple suffix rule.
for lang in $ALL_LINGUAS; do
frobbedlang=`echo $lang | sed -e 's/\..*$//' -e 'y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/'`
cat >> "$ac_file.tmp" < /dev/null; then
# Add dependencies that cannot be formulated as a simple suffix rule.
for lang in $ALL_LINGUAS; do
frobbedlang=`echo $lang | sed -e 's/_/-/g' -e 's/^sr-CS/sr-SP/' -e 's/@latin$/-Latn/' -e 's/@cyrillic$/-Cyrl/' -e 's/^sr-SP$/sr-SP-Latn/' -e 's/^uz-UZ$/uz-UZ-Latn/'`
cat >> "$ac_file.tmp" <> "$ac_file.tmp" <, 1996.
AC_PREREQ([2.50])
# Search path for a program which passes the given test.
dnl AM_PATH_PROG_WITH_TEST(VARIABLE, PROG-TO-CHECK-FOR,
dnl TEST-PERFORMED-ON-FOUND_PROGRAM [, VALUE-IF-NOT-FOUND [, PATH]])
AC_DEFUN([AM_PATH_PROG_WITH_TEST],
[
# Prepare PATH_SEPARATOR.
# The user is always right.
if test "${PATH_SEPARATOR+set}" != set; then
echo "#! /bin/sh" >conf$$.sh
echo "exit 0" >>conf$$.sh
chmod +x conf$$.sh
if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then
PATH_SEPARATOR=';'
else
PATH_SEPARATOR=:
fi
rm -f conf$$.sh
fi
# Find out how to test for executable files. Don't use a zero-byte file,
# as systems may use methods other than mode bits to determine executability.
cat >conf$$.file <<_ASEOF
#! /bin/sh
exit 0
_ASEOF
chmod +x conf$$.file
if test -x conf$$.file >/dev/null 2>&1; then
ac_executable_p="test -x"
else
ac_executable_p="test -f"
fi
rm -f conf$$.file
# Extract the first word of "$2", so it can be a program name with args.
set dummy $2; ac_word=[$]2
AC_MSG_CHECKING([for $ac_word])
AC_CACHE_VAL([ac_cv_path_$1],
[case "[$]$1" in
[[\\/]]* | ?:[[\\/]]*)
ac_cv_path_$1="[$]$1" # Let the user override the test with a path.
;;
*)
ac_save_IFS="$IFS"; IFS=$PATH_SEPARATOR
for ac_dir in ifelse([$5], , $PATH, [$5]); do
IFS="$ac_save_IFS"
test -z "$ac_dir" && ac_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
if $ac_executable_p "$ac_dir/$ac_word$ac_exec_ext"; then
echo "$as_me: trying $ac_dir/$ac_word..." >&AS_MESSAGE_LOG_FD
if [$3]; then
ac_cv_path_$1="$ac_dir/$ac_word$ac_exec_ext"
break 2
fi
fi
done
done
IFS="$ac_save_IFS"
dnl If no 4th arg is given, leave the cache variable unset,
dnl so AC_PATH_PROGS will keep looking.
ifelse([$4], , , [ test -z "[$]ac_cv_path_$1" && ac_cv_path_$1="$4"
])dnl
;;
esac])dnl
$1="$ac_cv_path_$1"
if test ifelse([$4], , [-n "[$]$1"], ["[$]$1" != "$4"]); then
AC_MSG_RESULT([$][$1])
else
AC_MSG_RESULT([no])
fi
AC_SUBST([$1])dnl
])
================================================
FILE: mockmodel.py
================================================
#
# Project Kimchi
#
# Copyright IBM Corp, 2015-2017
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
import os
import tempfile
import time
from collections import defaultdict
import cherrypy
import libvirt
import lxml.etree as ET
from lxml import objectify
from lxml.builder import E
from wok.asynctask import AsyncTask
from wok.exception import NotFoundError
from wok.exception import OperationFailed
from wok.objectstore import ObjectStore
from wok.plugins.kimchi import config as kimchi_config
from wok.plugins.kimchi import imageinfo
from wok.plugins.kimchi import osinfo
from wok.plugins.kimchi.model import cpuinfo
from wok.plugins.kimchi.model import storagevolumes
from wok.plugins.kimchi.model.groups import PAMGroupsModel
from wok.plugins.kimchi.model.host import DeviceModel
from wok.plugins.kimchi.model.host import DevicesModel
from wok.plugins.kimchi.model.libvirtstoragepool import IscsiPoolDef
from wok.plugins.kimchi.model.libvirtstoragepool import NetfsPoolDef
from wok.plugins.kimchi.model.libvirtstoragepool import StoragePoolDef
from wok.plugins.kimchi.model.model import Model
from wok.plugins.kimchi.model.storagepools import StoragePoolModel
from wok.plugins.kimchi.model.storagepools import StoragePoolsModel
from wok.plugins.kimchi.model.storagevolumes import StorageVolumeModel
from wok.plugins.kimchi.model.storagevolumes import StorageVolumesModel
from wok.plugins.kimchi.model.templates import LibvirtVMTemplate
from wok.plugins.kimchi.model.users import PAMUsersModel
from wok.plugins.kimchi.model.vmhostdevs import VMHostDevsModel
from wok.plugins.kimchi.utils import get_next_clone_name
from wok.plugins.kimchi.utils import pool_name_from_uri
from wok.plugins.kimchi.vmtemplate import VMTemplate
from wok.utils import convert_data_size
from wok.xmlutils.utils import xml_item_update
mockmodel_defaults = {'domain': 'test', 'arch': 'i686'}
storagevolumes.VALID_RAW_CONTENT = [
'dos/mbr boot sector',
'x86 boot sector',
'data',
'empty',
]
DEFAULT_POOL = '/plugins/kimchi/storagepools/default-pool'
class MockModel(Model):
_mock_vms = defaultdict(list)
_mock_snapshots = {}
_XMLDesc = libvirt.virDomain.XMLDesc
_undefineDomain = libvirt.virDomain.undefine
_libvirt_get_vol_path = LibvirtVMTemplate._get_volume_path
def __init__(self, objstore_loc=None):
# Override osinfo.defaults to ajust the values according to
# test:///default driver
defaults = dict(osinfo.defaults)
defaults.update(mockmodel_defaults)
defaults['disks'][0]['pool'] = {'name': DEFAULT_POOL}
osinfo.defaults = dict(defaults)
self._mock_vgs = MockVolumeGroups()
self._mock_partitions = MockPartitions()
self._mock_devices = MockDevices()
self._mock_storagevolumes = MockStorageVolumes()
cpuinfo.get_topo_capabilities = MockModel.get_topo_capabilities
libvirt.virNetwork.DHCPLeases = MockModel.getDHCPLeases
libvirt.virDomain.XMLDesc = MockModel.domainXMLDesc
libvirt.virDomain.undefine = MockModel.undefineDomain
libvirt.virDomain.attachDeviceFlags = MockModel.attachDeviceFlags
libvirt.virDomain.detachDeviceFlags = MockModel.detachDeviceFlags
libvirt.virDomain.updateDeviceFlags = MockModel.updateDeviceFlags
libvirt.virStorageVol.resize = MockModel.volResize
libvirt.virStorageVol.wipePattern = MockModel.volWipePattern
IscsiPoolDef.prepare = NetfsPoolDef.prepare = StoragePoolDef.prepare
PAMUsersModel.auth_type = 'fake'
PAMGroupsModel.auth_type = 'fake'
super(MockModel, self).__init__('test:///default', objstore_loc)
self.objstore_loc = objstore_loc
self.objstore = ObjectStore(objstore_loc)
# The MockModel methods are instantiated on runtime according to Model
# and BaseModel
# Because that a normal method override will not work here
# Instead of that we also need to do the override on runtime
for method in dir(self):
if method.startswith('_mock_'):
mock_method = getattr(self, method)
if not callable(mock_method):
continue
m = method[6:]
model_method = getattr(self, m)
setattr(self, '_model_' + m, model_method)
setattr(self, m, mock_method)
DeviceModel.lookup = self._mock_device_lookup
DeviceModel.get_iommu_groups = self._mock_device_get_iommu_groups
DeviceModel.is_device_3D_controller = self._mock_device_is_device_3D_controller
DevicesModel.get_list = self._mock_devices_get_list
StoragePoolsModel._check_lvm = self._check_lvm
StoragePoolModel._update_lvm_disks = self._update_lvm_disks
StoragePoolModel._pool_used_by_template = self._pool_used_by_template
StorageVolumesModel.get_list = self._mock_storagevolumes_get_list
StorageVolumeModel.doUpload = self._mock_storagevolume_doUpload
LibvirtVMTemplate._get_volume_path = self._get_volume_path
VMTemplate.get_iso_info = self._probe_image
imageinfo.probe_image = self._probe_image
VMHostDevsModel._get_pci_device_xml = self._get_pci_device_xml
VMHostDevsModel._validate_pci_passthrough_env = self._validate_pci
self._create_virt_viewer_tmp_file()
cherrypy.engine.subscribe('exit', self.virtviewertmpfile_cleanup)
def _create_virt_viewer_tmp_file(self):
path = kimchi_config.get_virtviewerfiles_path()
if not os.path.isdir(path):
os.makedirs(path)
self.virtviewerfile_tmp = tempfile.NamedTemporaryFile(
dir=path, delete=False)
file_content = '[virt-viewer]\ntype=vnc\nhost=127.0.0.1\nport=5999\n'
self.virtviewerfile_tmp.write(file_content.encode('utf-8'))
self.virtviewerfile_tmp.close()
def virtviewertmpfile_cleanup(self):
os.unlink(self.virtviewerfile_tmp.name)
cherrypy.engine.unsubscribe('exit', self.virtviewertmpfile_cleanup)
def reset(self):
MockModel._mock_vms = defaultdict(list)
MockModel._mock_snapshots = {}
if hasattr(self, 'objstore'):
self.objstore = ObjectStore(self.objstore_loc)
params = {
'vms': [u'test'],
'templates': [],
'networks': [u'default'],
'storagepools': [u'default-pool'],
}
for res, items in params.items():
resources = getattr(self, '%s_get_list' % res)()
for i in resources:
if i in items:
continue
try:
getattr(self, '%s_deactivate' % res[:-1])(i)
except Exception:
pass
getattr(self, '%s_delete' % res[:-1])(i)
volumes = self.storagevolumes_get_list('default-pool')
for v in volumes:
self.storagevolume_delete('default-pool', v)
@staticmethod
def get_topo_capabilities(conn):
# The libvirt test driver doesn't return topology.
xml = ""
return ET.fromstring(xml)
@staticmethod
def domainXMLDesc(dom, flags=0):
xml = MockModel._XMLDesc(dom, flags)
root = objectify.fromstring(xml)
mem_devs = root.findall('./devices/memory')
for dev_xml in MockModel._mock_vms.get(dom.name(), []):
dev = objectify.fromstring(dev_xml)
add = True
if dev.tag == 'memory':
for mem_dev in mem_devs:
if mem_dev.target.size == dev.target.size:
mem_devs.remove(mem_dev)
add = False
break
if add:
root.devices.append(dev)
return ET.tostring(root, encoding='unicode')
@staticmethod
def undefineDomain(dom):
name = dom.name()
if name in MockModel._mock_vms.keys():
del MockModel._mock_vms[dom.name()]
return MockModel._undefineDomain(dom)
@staticmethod
def attachDeviceFlags(dom, xml, flags=0):
myxml = objectify.fromstring(xml)
if myxml.tag == 'memory':
unit = myxml.target.size.get('unit')
myxml.target.size.set('unit', 'KiB')
myxml.target.size._setText(
str(int(convert_data_size(myxml.target.size.text, unit, 'KiB')))
)
xml = ET.tostring(myxml, encoding='unicode')
dom.setMaxMemory(int(dom.maxMemory() + myxml.target.size))
MockModel._mock_vms[dom.name()].append(xml)
@staticmethod
def _get_device_node(dom, xml):
xpath_map = {'disk': 'target',
'interface': 'mac', 'graphics': 'listen'}
dev = objectify.fromstring(xml)
dev_id = dev.find(xpath_map[dev.tag]).items()
dev_filter = ''
for key, value in dev_id:
dev_filter += "[@%s='%s']" % (key, value)
old_xml = dom.XMLDesc(libvirt.VIR_DOMAIN_XML_SECURE)
root = objectify.fromstring(old_xml)
devices = root.devices
dev = devices.find('./%s/%s%s/..' %
(dev.tag, xpath_map[dev.tag], dev_filter))
return (root, dev)
@staticmethod
def detachDeviceFlags(dom, xml, flags=0):
node = ET.fromstring(xml)
xml = ET.tostring(node, encoding='unicode', pretty_print=True)
if xml in MockModel._mock_vms[dom.name()]:
MockModel._mock_vms[dom.name()].remove(xml)
@staticmethod
def updateDeviceFlags(dom, xml, flags=0):
_, old_dev = MockModel._get_device_node(dom, xml)
old_xml = ET.tostring(old_dev, encoding='unicode', pretty_print=True)
if old_xml in MockModel._mock_vms[dom.name()]:
MockModel._mock_vms[dom.name()].remove(old_xml)
MockModel._mock_vms[dom.name()].append(xml)
@staticmethod
def volResize(vol, size, flags=0):
new_xml = xml_item_update(vol.XMLDesc(0), './capacity', str(size))
vol.delete(0)
pool = vol.storagePoolLookupByVolume()
pool.createXML(new_xml)
@staticmethod
def volWipePattern(vol, algorithm, flags=0):
new_xml = xml_item_update(vol.XMLDesc(0), './allocation', '0')
vol.delete(0)
pool = vol.storagePoolLookupByVolume()
pool.createXML(new_xml)
@staticmethod
def getDHCPLeases(net, mac):
return [
{
'iface': 'virbr1',
'ipaddr': '192.168.0.167',
'hostname': 'kimchi',
'expirytime': 1433285036,
'prefix': 24,
'clientid': '01:%s' % mac,
'mac': mac,
'iaid': None,
'type': 0,
}
]
def _probe_image(self, path):
return ('unknown', 'unknown')
def _get_volume_path(self, pool_uri, vol):
pool = pool_name_from_uri(pool_uri)
pool_info = self.storagepool_lookup(pool)
if pool_info['type'] == 'scsi':
return self._mock_storagevolumes.scsi_volumes[vol]['path']
return MockModel._libvirt_get_vol_path(pool, vol)
def _check_lvm(self, name, from_vg):
# do not do any verification while using MockModel
pass
def _pool_used_by_template(self, pool_name):
return False
def _update_lvm_disks(self, pool_name, disks):
conn = self.conn.get()
pool = conn.storagePoolLookupByName(pool_name)
xml = pool.XMLDesc(0)
root = ET.fromstring(xml)
source = root.xpath('./source')[0]
for d in disks:
dev = E.device(path=d)
source.append(dev)
conn.storagePoolDefineXML(ET.tostring(root, encoding='unicode'), 0)
def _mock_storagevolumes_create(self, pool, params):
vol_source = ['url', 'capacity']
index_list = list(i for i in range(len(vol_source))
if vol_source[i] in params)
create_param = vol_source[index_list[0]]
name = params.get('name')
if name is None and create_param == 'url':
params['name'] = os.path.basename(params['url'])
del params['url']
params['capacity'] = 1024
return self._model_storagevolumes_create(pool, params)
def _mock_storagevolumes_get_list(self, pool):
pool_info = self.storagepool_lookup(pool)
if pool_info['type'] == 'scsi':
return self._mock_storagevolumes.scsi_volumes.keys()
return self._model_storagevolumes_get_list(pool)
def _mock_storagevolume_lookup(self, pool, vol):
pool_info = self.storagepool_lookup(pool)
if pool_info['type'] == 'scsi':
return self._mock_storagevolumes.scsi_volumes[vol]
return self._model_storagevolume_lookup(pool, vol)
def _mock_storagevolume_doUpload(self, cb, vol, offset, data, data_size):
vol_path = vol.path()
# MockModel does not create the storage volume as a file
# So create it to do the file upload
if offset == 0:
dirname = os.path.dirname(vol_path)
if not os.path.exists(dirname):
os.makedirs(dirname)
open(vol_path, 'w').close()
try:
with open(vol_path, 'a') as fd:
fd.seek(offset)
fd.write(data)
except Exception as e:
os.remove(vol_path)
cb('', False)
raise OperationFailed('KCHVOL0029E', {'err': e.message})
def _mock_devices_get_list(
self,
_cap=None,
_passthrough=None,
_passthrough_affected_by=None,
_available_only=None,
):
if _cap is None:
return self._mock_devices.devices.keys()
if _cap == 'fc_host':
_cap = 'scsi_host'
return [
dev['name']
for dev in self._mock_devices.devices.values()
if dev['device_type'] == _cap
]
def _mock_device_get_iommu_groups(self):
return [
dev['iommuGroup']
for dev in self._mock_devices.devices.values()
if 'iommuGroup' in dev
]
def _mock_device_is_device_3D_controller(self, info):
if 'driver' in info and 'name' in info['driver']:
return info['driver']['name'] == 'nvidia'
return False
def _mock_device_lookup(self, dev_name):
return self._mock_devices.devices[dev_name]
def _mock_partitions_get_list(self):
return self._mock_partitions.partitions.keys()
def _mock_partition_lookup(self, name):
return self._mock_partitions.partitions[name]
def _mock_volumegroups_get_list(self):
return self._mock_vgs.data.keys()
def _mock_volumegroup_lookup(self, name):
return self._mock_vgs.data[name]
def _mock_vm_clone(self, name):
new_name = get_next_clone_name(self.vms_get_list(), name)
snapshots = MockModel._mock_snapshots.get(name, [])
MockModel._mock_snapshots[new_name] = snapshots
return self._model_vm_clone(name)
def _mock_vm_migrate(
self, name, remote_host, user=None, password=None, enable_rdma=None
):
if enable_rdma is None:
enable_rdma = False
params = {'remote_host': remote_host, 'enable_rdma': enable_rdma}
taskid = AsyncTask(
u'/plugins/kimchi/vms/%s/migrate' % name,
self._vmmigrate_create_task,
params,
).id
return self.task_lookup(taskid)
def _vmmigrate_create_task(self, cb, params):
cb('OK', True)
def _mock_vmvirtviewerfile_lookup(self, vm_name):
file_name = 'plugins/kimchi/data/virtviewerfiles/%s' % os.path.basename(
self.virtviewerfile_tmp.name
)
return file_name
def _mock_vmsnapshots_create(self, vm_name, params):
name = params.get('name', str(int(time.time())))
params = {'vm_name': vm_name, 'name': name}
taskid = AsyncTask(
u'/plugins/kimchi/vms/%s/snapshots/%s' % (vm_name, name),
self._vmsnapshots_create_task,
params,
).id
return self.task_lookup(taskid)
def _vmsnapshots_create_task(self, cb, params):
vm_name = params['vm_name']
name = params['name']
parent = u''
snapshots = MockModel._mock_snapshots.get(vm_name, [])
for sn in snapshots:
if sn.current:
sn.current = False
parent = sn.name
snapshots.append(MockVMSnapshot(name, {'parent': parent}))
MockModel._mock_snapshots[vm_name] = snapshots
cb('OK', True)
def _mock_vmsnapshots_get_list(self, vm_name):
snapshots = MockModel._mock_snapshots.get(vm_name, [])
return sorted([snap.name for snap in snapshots])
def _mock_currentvmsnapshot_lookup(self, vm_name):
for sn in MockModel._mock_snapshots.get(vm_name, []):
if sn.current:
return sn.info
def _mock_vmsnapshot_lookup(self, vm_name, name):
for sn in MockModel._mock_snapshots.get(vm_name, []):
if sn.name == name:
return sn.info
raise NotFoundError('KCHSNAP0003E', {'name': name, 'vm': vm_name})
def _mock_vmsnapshot_delete(self, vm_name, name):
snapshots = MockModel._mock_snapshots.get(vm_name, [])
for sn in snapshots:
if sn.name == name:
del snapshots[snapshots.index(sn)]
MockModel._mock_snapshots[vm_name] = snapshots
def _mock_vmsnapshot_revert(self, vm_name, name):
snapshots = MockModel._mock_snapshots.get(vm_name, [])
for sn in snapshots:
if sn.current:
sn.current = False
for sn in snapshots:
if sn.name == name:
sn.current = True
def _attach_device(self, vm_name, xmlstr):
MockModel._mock_vms[vm_name].append(xmlstr)
def _validate_pci(self):
pass
def _get_pci_device_xml(self, dev_info, slot, is_multifunction):
if 'detach_driver' not in dev_info:
dev_info['detach_driver'] = 'kvm'
source = E.source(
E.address(
domain=str(dev_info['domain']),
bus=str(dev_info['bus']),
slot=str(dev_info['slot']),
function=str(dev_info['function']),
)
)
driver = E.driver(name=dev_info['detach_driver'])
if is_multifunction:
multi = E.address(
type='pci',
domain='0',
bus='0',
slot=str(slot),
function=str(dev_info['function']),
)
if dev_info['function'] == 0:
multi = E.address(
type='pci',
domain='0',
bus='0',
slot=str(slot),
function=str(dev_info['function']),
multifunction='on',
)
host_dev = E.hostdev(
source, driver, multi, mode='subsystem', type='pci', managed='yes'
)
else:
host_dev = E.hostdev(
source, driver, mode='subsystem', type='pci', managed='yes'
)
return ET.tostring(host_dev, encoding='unicode')
class MockStorageVolumes(object):
def __init__(self):
base_path = '/dev/disk/by-path/pci-0000:0e:00.0-fc-0x20-lun'
self.scsi_volumes = {
'unit:0:0:1': {
'capacity': 1024,
'format': 'unknown',
'allocation': 512,
'type': 'block',
'path': base_path + '1',
'used_by': [],
'isvalid': True,
'has_permission': True,
},
'unit:0:0:2': {
'capacity': 2048,
'format': 'unknown',
'allocation': 512,
'type': 'block',
'path': base_path + '2',
'used_by': [],
'isvalid': True,
'has_permission': True,
},
}
class MockVolumeGroups(object):
def __init__(self):
self.data = {
'hostVG': {
'lvs': [],
'name': 'hostVG',
'pvs': ['/dev/vdx'],
'free': 5347737600,
'size': 5347737600,
},
'kimchiVG': {
'lvs': [],
'name': 'kimchiVG',
'pvs': ['/dev/vdz', '/dev/vdw'],
'free': 10695475200,
'size': 10695475200,
},
}
class MockPartitions(object):
def __init__(self):
self.partitions = {
'vdx': {
'available': True,
'name': 'vdx',
'fstype': '',
'path': '/dev/vdx',
'mountpoint': '',
'type': 'disk',
'size': '2147483648',
},
'vdz': {
'available': True,
'name': 'vdz',
'fstype': '',
'path': '/dev/vdz',
'mountpoint': '',
'type': 'disk',
'size': '2147483648',
},
}
class MockDevices(object):
def __init__(self):
self.devices = {
'computer': {
'device_type': 'system',
'firmware': {
'release_date': '01/01/2012',
'vendor': 'LENOVO',
'version': 'XXXXX (X.XX )',
},
'hardware': {
'serial': 'PXXXXX',
'uuid': '9d660370-820f-4241-8731-5a60c97e8aa6',
'vendor': 'LENOVO',
'version': 'ThinkPad T420',
},
'name': 'computer',
'parent': None,
'product': '4180XXX',
},
'pci_0000_03_00_0': {
'bus': 3,
'device_type': 'pci',
'domain': 0,
'driver': {'name': 'iwlwifi'},
'function': 0,
'iommuGroup': 7,
'name': 'pci_0000_03_00_0',
'parent': 'computer',
'path': '/sys/devices/pci0000:00/0000:03:00.0',
'product': {
'description': 'Centrino Advanced-N 6205 [Taylor Peak]',
'id': '0x0085',
},
'slot': 0,
'vga3d': False,
'vendor': {'description': 'Intel Corporation', 'id': '0x8086'},
},
'pci_0000_0d_00_0': {
'bus': 13,
'device_type': 'pci',
'domain': 0,
'driver': {'name': 'sdhci-pci'},
'function': 0,
'iommuGroup': 7,
'name': 'pci_0000_0d_00_0',
'parent': 'computer',
'path': '/sys/devices/pci0000:00/0000:0d:00.0',
'product': {
'description': 'PCIe SDXC/MMC Host Controller',
'id': '0xe823',
},
'slot': 0,
'vga3d': False,
'vendor': {'description': 'Ricoh Co Ltd', 'id': '0x1180'},
},
'pci_0000_09_01_0': {
'bus': 9,
'device_type': 'pci',
'domain': 0,
'driver': {'name': 'tg3'},
'function': 0,
'iommuGroup': 8,
'name': 'pci_0000_09_01_0',
'parent': 'computer',
'path': '/sys/devices/pci0000:00/0000:09:01.0',
'product': {'description': 'NetXtreme BCM5719', 'id': '0x1657'},
'slot': 1,
'vga3d': False,
'vendor': {'description': 'Broadcom Corp', 'id': '0x14e4'},
},
'pci_0000_09_01_1': {
'bus': 9,
'device_type': 'pci',
'domain': 0,
'driver': {'name': 'tg3'},
'function': 1,
'iommuGroup': 8,
'name': 'pci_0000_09_01_1',
'parent': 'computer',
'path': '/sys/devices/pci0000:00/0000:09:01.1',
'product': {'description': 'NetXtreme BCM5719', 'id': '0x1657'},
'slot': 1,
'vga3d': False,
'vendor': {'description': 'Broadcom Corp', 'id': '0x14e4'},
},
'pci_0000_09_01_2': {
'bus': 9,
'device_type': 'pci',
'domain': 0,
'driver': {'name': 'tg3'},
'function': 2,
'iommuGroup': 8,
'name': 'pci_0000_09_01_2',
'parent': 'computer',
'path': '/sys/devices/pci0000:00/0000:09:01.2',
'product': {'description': 'NetXtreme BCM5719', 'id': '0x1657'},
'slot': 1,
'vga3d': False,
'vendor': {'description': 'Broadcom Corp', 'id': '0x14e4'},
},
'pci_0000_1a_00_0': {
'bus': 26,
'device_type': 'pci',
'domain': 0,
'driver': {'name': 'nvidia'},
'function': 0,
'iommuGroup': 9,
'name': 'pci_0000_1a_00_0',
'parent': 'computer',
'path': '/sys/devices/pci0000:00/0000:1a:00.0',
'product': {'description': 'GK210GL [Tesla K80]', 'id': '0x0302'},
'slot': 0,
'vga3d': True,
'vendor': {'description': 'NVIDIA Corp', 'id': '0x10de'},
},
'pci_0001_1b_00_0': {
'bus': 27,
'device_type': 'pci',
'domain': 1,
'driver': {'name': 'nvidia'},
'function': 0,
'iommuGroup': 7,
'name': 'pci_0001_1b_00_0',
'parent': 'computer',
'path': '/sys/devices/pci0000:00/0001:1b:00.0',
'product': {'description': 'GK210GL [Tesla K80]', 'id': '0x0302'},
'slot': 0,
'vga3d': True,
'vendor': {'description': 'NVIDIA Corp', 'id': '0x10de'},
},
'pci_0000_1c_00_0': {
'bus': 28,
'device_type': 'pci',
'domain': 0,
'driver': {'name': 'nvidia'},
'function': 0,
'iommuGroup': 7,
'name': 'pci_0000_1c_00_0',
'parent': 'computer',
'path': '/sys/devices/pci0000:00/0000:0d:00.0',
'product': {'description': 'GK210GL [Tesla K80]', 'id': '0x0302'},
'slot': 0,
'vga3d': True,
'vendor': {'description': 'NVIDIA Corp', 'id': '0x10de'},
},
'scsi_host0': {
'adapter': {
'fabric_wwn': '37df6c1efa1b4388',
'type': 'fc_host',
'wwnn': 'efb6563f06434a98',
'wwpn': '742f32073aab45d7',
},
'device_type': 'scsi_host',
'host': 0,
'name': 'scsi_host0',
'parent': 'computer',
'path': '/sys/devices/pci0000:00/0000:40:00.0/0',
},
'scsi_host1': {
'adapter': {
'fabric_wwn': '542efa5dced34123',
'type': 'fc_host',
'wwnn': 'b7433a40c9b84092',
'wwpn': '25c1f485ae42497f',
},
'device_type': 'scsi_host',
'host': 0,
'name': 'scsi_host1',
'parent': 'computer',
'path': '/sys/devices/pci0000:00/0000:40:00.0/1',
},
'scsi_host2': {
'adapter': {
'fabric_wwn': '5c373c334c20478d',
'type': 'fc_host',
'wwnn': 'f2030bec4a254e6b',
'wwpn': '07dbca4164d44096',
},
'device_type': 'scsi_host',
'host': 0,
'name': 'scsi_host2',
'parent': 'computer',
'path': '/sys/devices/pci0000:00/0000:40:00.0/2',
},
}
class MockVMSnapshot(object):
def __init__(self, name, params=None):
if params is None:
params = {}
self.name = name
self.current = True
self.info = {
'created': params.get('created', str(int(time.time()))),
'name': name,
'parent': params.get('parent', u''),
'state': params.get('state', u'shutoff'),
}
================================================
FILE: model/Makefile.am
================================================
#
# Kimchi
#
# Copyright IBM Corp, 2015-2016
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
model_PYTHON = *.py
modeldir = $(pythondir)/wok/plugins/kimchi/model
install-data-local:
$(MKDIR_P) $(DESTDIR)$(modeldir)
================================================
FILE: model/__init__.py
================================================
#
# Project Kimchi
#
# Copyright IBM Corp, 2015-2016
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
================================================
FILE: model/cpuinfo.py
================================================
#
# Project Kimchi
#
# Copyright IBM Corp, 2015-2016
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
import platform
from xml.etree import ElementTree as ET
from wok.exception import InvalidOperation
from wok.exception import InvalidParameter
from wok.utils import run_command
from wok.utils import wok_log
ARCH = 'power' if platform.machine().startswith('ppc') else 'x86'
MAX_PPC_VCPUS = 255
def get_topo_capabilities(connect):
"""
This helper function exists solely to be overridden for
mockmodel tests. Since other modules use getCapabilies(),
it can't be overridden directly.
"""
xml = connect.getCapabilities()
capabilities = ET.fromstring(xml)
return capabilities.find('host').find('cpu').find('topology')
class CPUInfoModel(object):
"""
Get information about a CPU for hyperthreading (on x86)
or SMT (on POWER) for logic when creating templates and VMs.
"""
def __init__(self, **kargs):
self.guest_threads_enabled = False
self.sockets = 0
self.cores_present = 0
self.cores_available = 0
self.cores_per_socket = 0
self.threads_per_core = 0
self.max_threads = 0
self.conn = kargs['conn']
try:
connect = self.conn.get()
libvirt_topology = get_topo_capabilities(connect)
except Exception as e:
wok_log.info(f'Unable to get CPU topology capabilities: {str(e)}')
return
if libvirt_topology is None:
wok_log.info('cpu_info topology not supported.')
return
if ARCH == 'power':
# IBM PowerPC
self.guest_threads_enabled = True
out, error, rc = run_command(['ppc64_cpu', '--smt'])
if rc or 'on' in out:
# SMT has to be disabled for guest to use threads as CPUs.
# rc is always zero, whether SMT is off or on.
self.guest_threads_enabled = False
out, error, rc = run_command(['ppc64_cpu', '--cores-present'])
if not rc:
self.cores_present = int(out.split()[-1])
out, error, rc = run_command(['ppc64_cpu', '--cores-on'])
if not rc:
self.cores_available = int(out.split()[-1])
out, error, rc = run_command(['ppc64_cpu', '--threads-per-core'])
if not rc:
self.threads_per_core = int(out.split()[-1])
self.sockets = self.cores_present / self.threads_per_core
if self.sockets == 0:
self.sockets = 1
self.cores_per_socket = self.cores_present / self.sockets
else:
# Intel or AMD
self.guest_threads_enabled = True
self.sockets = int(libvirt_topology.get('sockets'))
self.cores_per_socket = int(libvirt_topology.get('cores'))
self.cores_present = self.cores_per_socket * self.sockets
self.cores_available = self.cores_present
self.threads_per_core = int(libvirt_topology.get('threads'))
def lookup(self, ident):
return {
'guest_threads_enabled': self.guest_threads_enabled,
'sockets': self.sockets,
'cores_per_socket': self.cores_per_socket,
'cores_present': self.cores_present,
'cores_available': self.cores_available,
'threads_per_core': self.threads_per_core,
}
def check_cpu_info(self, cpu_info):
"""
param cpu_info: topology definition dict: {
'maxvcpus': integer
'vcpus': integer
'topology': {
'sockets': integer,
'cores': integer,
'threads': integer
}
}
"""
maxvcpus = cpu_info.get('maxvcpus')
vcpus = cpu_info.get('vcpus')
topology = cpu_info.get('topology')
if topology:
# sockets, cores and threads are required when topology is defined
if (
'sockets' not in topology
or 'cores' not in topology
or 'threads' not in topology
):
raise InvalidOperation('KCHCPUINF0007E')
sockets = topology['sockets']
cores = topology['cores']
threads = topology['threads']
if not self.guest_threads_enabled:
raise InvalidOperation('KCHCPUINF0003E')
if maxvcpus != sockets * cores * threads:
raise InvalidParameter('KCHCPUINF0002E')
if vcpus % threads != 0:
raise InvalidParameter('KCHCPUINF0005E')
if maxvcpus > self.get_host_max_vcpus():
raise InvalidParameter('KCHCPUINF0004E')
if vcpus > maxvcpus:
raise InvalidParameter('KCHCPUINF0001E')
def get_host_max_vcpus(self):
if ARCH == 'power':
max_vcpus = self.cores_available * self.threads_per_core
if max_vcpus > MAX_PPC_VCPUS:
max_vcpus = MAX_PPC_VCPUS
else:
max_vcpus = self.conn.get().getMaxVcpus('kvm')
return max_vcpus
================================================
FILE: model/diskutils.py
================================================
#
# Project Kimchi
#
# Copyright IBM Corp, 2015-2016
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
from wok.plugins.kimchi.model.vms import VMModel
from wok.plugins.kimchi.model.vms import VMsModel
from wok.plugins.kimchi.xmlutils.disk import get_vm_disk_info
from wok.plugins.kimchi.xmlutils.disk import get_vm_disks
"""
Functions that multiple storage-related models (e.g. VMStoragesModel,
VolumesModel) will need.
"""
def get_disk_used_by(conn, path):
used_by = []
# try to find this volume in existing vm
vms_list = VMsModel.get_vms(conn)
for vm in vms_list:
dom = VMModel.get_vm(vm, conn)
storages = get_vm_disks(dom)
for disk in storages.keys():
d_info = get_vm_disk_info(dom, disk)
if path == d_info['path']:
used_by.append(vm)
return used_by
================================================
FILE: model/featuretests.py
================================================
#
# Project Kimchi
#
# Copyright IBM Corp, 2015-2016
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
import platform
import subprocess
import cherrypy
import libvirt
import lxml.etree as ET
from lxml.builder import E
from wok.utils import run_command
from wok.utils import servermethod
from wok.utils import wok_log
FEATURETEST_VM_NAME = 'FEATURETEST_VM'
FEATURETEST_POOL_NAME = 'FEATURETEST_POOL'
ISO_STREAM_XML = """
%(name)s256hvm"""
SIMPLE_VM_XML = """
%(name)s256hvm"""
MAXMEM_VM_XML = """
%(name)s512256hvm"""
DEV_MEM_XML = """
2560"""
SCSI_FC_XML = """
%(name)s/dev/disk/by-path
"""
class FeatureTests(object):
@staticmethod
def disable_libvirt_error_logging():
def libvirt_errorhandler(userdata, error):
# A libvirt error handler to ignore annoying messages in stderr
pass
# Filter functions are enable only in production env
if cherrypy.config.get('environment') != 'production':
return
# Register the error handler to hide libvirt error in stderr
libvirt.registerErrorHandler(f=libvirt_errorhandler, ctx=None)
@staticmethod
def enable_libvirt_error_logging():
# Filter functions are enable only in production env
if cherrypy.config.get('environment') != 'production':
return
# Unregister the error handler
libvirt.registerErrorHandler(f=None, ctx=None)
@staticmethod
def libvirt_supports_iso_stream(conn, protocol):
conn_type = conn.getType().lower()
domain_type = 'test' if conn_type == 'test' else 'kvm'
arch = 'i686' if conn_type == 'test' else platform.machine()
arch = 'ppc64' if arch == 'ppc64le' else arch
xml = ISO_STREAM_XML % {
'name': FEATURETEST_VM_NAME,
'domain': domain_type,
'protocol': protocol,
'arch': arch,
}
try:
FeatureTests.disable_libvirt_error_logging()
dom = conn.defineXML(xml)
dom.undefine()
return True
except libvirt.libvirtError as e:
wok_log.error(str(e))
return False
finally:
FeatureTests.enable_libvirt_error_logging()
@staticmethod
def libvirt_support_nfs_probe(conn):
def _get_xml():
obj = E.source(E.host(name='127.0.0.1'), E.format(type='nfs'))
xml = ET.tostring(obj, encoding='unicode')
return xml
try:
FeatureTests.disable_libvirt_error_logging()
conn.findStoragePoolSources('netfs', _get_xml(), 0)
except libvirt.libvirtError as e:
wok_log.error(str(e))
if e.get_error_code() == 38:
# if libvirt cannot find showmount,
# it returns 38--general system call failure
return False
finally:
FeatureTests.enable_libvirt_error_logging()
return True
@staticmethod
@servermethod
def qemu_supports_iso_stream():
host = cherrypy.server.socket_host
port = cherrypy.server.socket_port
cmd = (
"qemu-io -r http://%s:%d/plugins/kimchi/images/icon-fedora.png \
-c 'read -v 0 512'"
% (host, port)
)
proc = subprocess.Popen(
cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True
)
stdout, stderr = proc.communicate()
return len(stderr) == 0
@staticmethod
def libvirt_support_fc_host(conn):
pool = None
try:
FeatureTests.disable_libvirt_error_logging()
pool_xml = SCSI_FC_XML % {'name': FEATURETEST_POOL_NAME}
pool = conn.storagePoolDefineXML(pool_xml, 0)
except libvirt.libvirtError as e:
if e.get_error_code() == 27:
# Libvirt requires adapter name, not needed when supports to FC
return False
finally:
FeatureTests.enable_libvirt_error_logging()
pool is None or pool.undefine()
return True
@staticmethod
def kernel_support_vfio():
out, err, rc = run_command(['modprobe', 'vfio-pci'])
if rc != 0:
wok_log.warning('Unable to load Kernal module vfio-pci.')
return False
return True
@staticmethod
def is_nm_running():
"""Tries to determine whether NetworkManager is running."""
out, err, rc = run_command(['nmcli', 'dev', 'status'])
if rc != 0:
return False
return True
@staticmethod
def has_mem_hotplug_support(conn):
"""
A memory device can be hot-plugged or hot-unplugged since libvirt
version 1.2.14.
"""
# Libvirt < 1.2.14 does not support memory devices, so try to attach a
# device. Then check if QEMU (>= 2.1) supports memory hotplug, starting
# the guest These steps avoid errors with Libvirt 'test' driver for KVM
conn_type = conn.getType().lower()
domain_type = 'test' if conn_type == 'test' else 'kvm'
arch = 'i686' if conn_type == 'test' else platform.machine()
arch = 'ppc64' if arch == 'ppc64le' else arch
dom = None
try:
FeatureTests.disable_libvirt_error_logging()
dom = conn.defineXML(
MAXMEM_VM_XML
% {'name': FEATURETEST_VM_NAME, 'domain': domain_type, 'arch': arch}
)
dom.attachDeviceFlags(DEV_MEM_XML, libvirt.VIR_DOMAIN_MEM_CONFIG)
dom.create()
except libvirt.libvirtError:
return False
finally:
if dom and dom.isActive() == 1:
dom.destroy()
dom is None or dom.undefine()
FeatureTests.enable_libvirt_error_logging()
return True
================================================
FILE: model/groups.py
================================================
#
# Project Kimchi
#
# Copyright IBM Corp, 2015-2016
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
import grp
from wok.config import config
class GroupsModel(object):
def __init__(self, **args):
auth_type = config.get('authentication', 'method')
for klass in GroupsModel.__subclasses__():
if auth_type == klass.auth_type:
self.grp = klass(**args)
def get_list(self, **args):
if hasattr(self.grp, '_get_list'):
return self.grp._get_list(**args)
else:
return list()
def validate(self, gid):
return self.grp._validate(gid)
class PAMGroupsModel(GroupsModel):
auth_type = 'pam'
def __init__(self, **kargs):
pass
def _get_list(self):
return sorted([group.gr_name
for group in grp.getgrall()])
def _validate(self, gid):
try:
grp.getgrnam(gid)
except KeyError:
return False
return True
class LDAPGroupsModel(GroupsModel):
auth_type = 'ldap'
def __init__(self, **kargs):
pass
def _validate(self, gid):
return False
================================================
FILE: model/host.py
================================================
#
# Project Kimchi
#
# Copyright IBM Corp, 2015-2017
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
import os
from collections import defaultdict
import libvirt
from lxml import objectify
from wok.exception import InvalidParameter
from wok.exception import NotFoundError
from wok.plugins.kimchi import disks
from wok.plugins.kimchi.model import hostdev
from wok.plugins.kimchi.model.config import CapabilitiesModel
from wok.plugins.kimchi.model.vms import VMModel
from wok.plugins.kimchi.model.vms import VMsModel
from wok.xmlutils.utils import xpath_get_text
class DevicesModel(object):
def __init__(self, **kargs):
self.conn = kargs['conn']
self.caps = CapabilitiesModel(**kargs)
self.cap_map = {
'net': libvirt.VIR_CONNECT_LIST_NODE_DEVICES_CAP_NET,
'pci': libvirt.VIR_CONNECT_LIST_NODE_DEVICES_CAP_PCI_DEV,
'scsi': libvirt.VIR_CONNECT_LIST_NODE_DEVICES_CAP_SCSI,
'scsi_host': libvirt.VIR_CONNECT_LIST_NODE_DEVICES_CAP_SCSI_HOST,
'storage': libvirt.VIR_CONNECT_LIST_NODE_DEVICES_CAP_STORAGE,
'usb_device': libvirt.VIR_CONNECT_LIST_NODE_DEVICES_CAP_USB_DEV,
'usb': libvirt.VIR_CONNECT_LIST_NODE_DEVICES_CAP_USB_INTERFACE,
}
# TODO: when no longer supporting Libvirt < 1.0.5 distros
# (like RHEL6) remove this verification and insert the
# key 'fc_host' with the libvirt variable in the hash
# declaration above.
try:
self.cap_map['fc_host'] = libvirt.VIR_CONNECT_LIST_NODE_DEVICES_CAP_FC_HOST
except AttributeError:
self.cap_map['fc_host'] = None
def _get_unavailable_devices(self):
vm_list = VMsModel.get_vms(self.conn)
unavailable_devs = []
for vm in vm_list:
dom = VMModel.get_vm(vm, self.conn)
xmlstr = dom.XMLDesc(0)
root = objectify.fromstring(xmlstr)
try:
hostDevices = root.devices.hostdev
except AttributeError:
continue
vm_devs = [DeviceModel.deduce_dev_name(
e, self.conn) for e in hostDevices]
for dev in vm_devs:
unavailable_devs.append(dev)
return unavailable_devs
def get_list(
self,
_cap=None,
_passthrough=None,
_passthrough_affected_by=None,
_available_only=None,
):
if _passthrough_affected_by is not None:
# _passthrough_affected_by conflicts with _cap and _passthrough
if (_cap, _passthrough) != (None, None):
raise InvalidParameter('KCHHOST0004E')
return sorted(self._get_passthrough_affected_devs(_passthrough_affected_by))
if _cap == 'fc_host':
dev_names = self._get_devices_fc_host()
else:
dev_names = self._get_devices_with_capability(_cap)
if _passthrough is not None and _passthrough.lower() == 'true':
conn = self.conn.get()
passthrough_names = [
dev['name'] for dev in hostdev.get_passthrough_dev_infos(conn)
]
dev_names = list(set(dev_names) & set(passthrough_names))
if _available_only is not None and _available_only.lower() == 'true':
unavailable_devs = self._get_unavailable_devices()
dev_names = [
dev for dev in dev_names if dev not in unavailable_devs]
dev_names.sort()
return dev_names
def _get_devices_with_capability(self, cap):
conn = self.conn.get()
if cap is None:
cap_flag = 0
else:
cap_flag = self.cap_map.get(cap)
if cap_flag is None:
return []
return [name.name() for name in conn.listAllDevices(cap_flag)]
def _get_passthrough_affected_devs(self, dev_name):
conn = self.conn.get()
info = DeviceModel(conn=self.conn).lookup(dev_name)
affected = hostdev.get_affected_passthrough_devices(conn, info)
return [dev_info['name'] for dev_info in affected]
def _get_devices_fc_host(self):
conn = self.conn.get()
# Libvirt < 1.0.5 does not support fc_host capability
if not self.caps.fc_host_support:
ret = []
scsi_hosts = self._get_devices_with_capability('scsi_host')
for host in scsi_hosts:
xml = conn.nodeDeviceLookupByName(host).XMLDesc(0)
path = '/device/capability/capability/@type'
if 'fc_host' in xpath_get_text(xml, path):
ret.append(host)
return ret
# Double verification to catch the case where the libvirt
# supports fc_host but does not, for some reason, recognize
# the libvirt.VIR_CONNECT_LIST_NODE_DEVICES_CAP_FC_HOST
# attribute.
if not self.cap_map['fc_host']:
return conn.listDevices('fc_host', 0)
return self._get_devices_with_capability('fc_host')
class DeviceModel(object):
def __init__(self, **kargs):
self.conn = kargs['conn']
self.iommu_groups = self.get_iommu_groups()
def get_iommu_groups(self):
iommu_groups = defaultdict(list)
conn = self.conn
try:
devices = DevicesModel(conn=conn).get_list()
except Exception:
return iommu_groups
for device in devices:
info = hostdev.get_dev_info(
conn.get().nodeDeviceLookupByName(device))
if 'iommuGroup' not in info:
continue
iommu_group_nr = int(info['iommuGroup'])
iommu_groups[iommu_group_nr].append(device)
return iommu_groups
def lookup(self, nodedev_name):
conn = self.conn.get()
try:
dev = conn.nodeDeviceLookupByName(nodedev_name)
except Exception:
raise NotFoundError('KCHHOST0003E', {'name': nodedev_name})
info = hostdev.get_dev_info(dev)
info['multifunction'] = self.is_multifunction_pci(info)
info['vga3d'] = self.is_device_3D_controller(info)
return info
def is_multifunction_pci(self, info):
if 'iommuGroup' not in info:
return False
iommu_group_nr = int(info['iommuGroup'])
return len(self.iommu_groups[iommu_group_nr]) > 1
def is_device_3D_controller(self, info):
try:
with open(os.path.join(info['path'], 'class')) as f:
pci_class = int(f.readline().strip(), 16)
except Exception:
return False
if pci_class == 0x030200:
return True
return False
@staticmethod
def _toint(num_str):
if num_str.startswith('0x'):
return int(num_str, 16)
elif num_str.startswith('0'):
return int(num_str, 8)
else:
return int(num_str)
@staticmethod
def deduce_dev_name(e, conn):
if e.attrib['type'] == 'pci':
return DeviceModel._deduce_dev_name_pci(e)
elif e.attrib['type'] == 'scsi':
return DeviceModel._deduce_dev_name_scsi(e)
elif e.attrib['type'] == 'usb':
return DeviceModel._deduce_dev_name_usb(e, conn)
return None
@staticmethod
def _deduce_dev_name_pci(e):
attrib = {}
for field in ('domain', 'bus', 'slot', 'function'):
attrib[field] = DeviceModel._toint(e.source.address.attrib[field])
return 'pci_%(domain)04x_%(bus)02x_%(slot)02x_%(function)x' % attrib
@staticmethod
def _deduce_dev_name_scsi(e):
attrib = {}
for field in ('bus', 'target', 'unit'):
attrib[field] = DeviceModel._toint(e.source.address.attrib[field])
attrib['host'] = DeviceModel._toint(
e.source.adapter.attrib['name'][len('scsi_host'):]
)
return 'scsi_%(host)d_%(bus)d_%(target)d_%(unit)d' % attrib
@staticmethod
def _deduce_dev_name_usb(e, conn):
dev_names = DevicesModel(conn=conn).get_list(_cap='usb_device')
usb_infos = [DeviceModel(conn=conn).lookup(dev_name)
for dev_name in dev_names]
unknown_dev = None
try:
evendor = DeviceModel._toint(e.source.vendor.attrib['id'])
eproduct = DeviceModel._toint(e.source.product.attrib['id'])
except AttributeError:
evendor = 0
eproduct = 0
else:
unknown_dev = f'usb_vendor_{evendor}_product_{eproduct}'
try:
ebus = DeviceModel._toint(e.source.address.attrib['bus'])
edevice = DeviceModel._toint(e.source.address.attrib['device'])
except AttributeError:
ebus = -1
edevice = -1
else:
unknown_dev = f'usb_bus_{ebus}_device_{edevice}'
for usb_info in usb_infos:
ivendor = DeviceModel._toint(usb_info['vendor']['id'])
iproduct = DeviceModel._toint(usb_info['product']['id'])
if evendor == ivendor and eproduct == iproduct:
return usb_info['name']
ibus = usb_info['bus']
idevice = usb_info['device']
if ebus == ibus and edevice == idevice:
return usb_info['name']
return unknown_dev
class PartitionsModel(object):
def __init__(self, **kargs):
pass
def get_list(self):
result = disks.get_partitions_names()
return result
class PartitionModel(object):
def __init__(self, **kargs):
pass
def lookup(self, name):
return disks.get_partition_details(name)
class VolumeGroupsModel(object):
def __init__(self, **kargs):
pass
def get_list(self):
return [vg['vgname'] for vg in disks.vgs()]
class VolumeGroupModel(object):
def __init__(self, **kargs):
pass
def lookup(self, name):
def _format(vg):
return {
'name': vg['vgname'],
'size': vg['size'],
'free': vg['free'],
'pvs': [pv['pvname'] for pv in disks.pvs(vg['vgname'])],
'lvs': [lv['lvname'] for lv in disks.lvs(vg['vgname'])],
}
vgs = [_format(vg) for vg in disks.vgs() if vg['vgname'] == name]
if not vgs:
raise InvalidParameter('KCHLVMS0001E', {'name': name})
return vgs[0]
================================================
FILE: model/hostdev.py
================================================
#
# Kimchi
#
# Copyright IBM Corp, 2015-2016
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
import os
from pprint import pformat
from pprint import pprint
from wok.plugins.kimchi.model.libvirtconnection import LibvirtConnection
from wok.utils import wok_log
from wok.xmlutils.utils import dictize
def _get_all_host_dev_infos(libvirt_conn):
node_devs = libvirt_conn.listAllDevices(0)
return [get_dev_info(node_dev) for node_dev in node_devs]
def _get_dev_info_tree(dev_infos):
devs = dict([(dev_info['name'], dev_info) for dev_info in dev_infos])
root = None
for dev_info in dev_infos:
if dev_info['parent'] is None:
root = dev_info
continue
try:
parent = devs[dev_info['parent']]
except KeyError:
wok_log.error(
'Parent %s of device %s does not exist.',
dev_info['parent'],
dev_info['name'],
)
continue
try:
children = parent['children']
except KeyError:
parent['children'] = [dev_info]
else:
children.append(dev_info)
return root
def _is_pci_qualified(pci_dev):
# PCI bridge is not suitable to passthrough
# KVM does not support passthrough graphic card now but supports
# 3D controller
blacklist_classes = (0x030000, 0x060000)
with open(os.path.join(pci_dev['path'], 'class')) as f:
pci_class = int(f.readline().strip(), 16)
if pci_class != 0x030200 and pci_class & 0xFF0000 in blacklist_classes:
return False
return True
def get_passthrough_dev_infos(libvirt_conn):
""" Get devices eligible to be passed through to VM. """
def is_eligible(dev):
return dev['device_type'] in ('usb_device', 'scsi') or (
dev['device_type'] == 'pci' and _is_pci_qualified(dev)
)
dev_infos = _get_all_host_dev_infos(libvirt_conn)
return [dev_info for dev_info in dev_infos if is_eligible(dev_info)]
def _get_same_iommugroup_devices(dev_infos, device_info):
dev_dict = dict([(dev_info['name'], dev_info) for dev_info in dev_infos])
def get_iommu_group(dev_info):
# Find out the iommu group of a given device.
# Child device belongs to the same iommu group as the parent device.
try:
return dev_info['iommuGroup']
except KeyError:
pass
parent = dev_info['parent']
while parent is not None:
try:
parent_info = dev_dict[parent]
except KeyError:
wok_log.error(
'Parent %s of device %s does not exist', parent, dev_info['name']
)
break
try:
iommuGroup = parent_info['iommuGroup']
except KeyError:
pass
else:
return iommuGroup
parent = parent_info['parent']
return None
iommu_group = get_iommu_group(device_info)
if iommu_group is None:
return []
return [
dev_info
for dev_info in dev_infos
if dev_info['name'] != device_info['name']
and get_iommu_group(dev_info) == iommu_group
]
def _get_children_devices(dev_infos, device_info):
def get_children_recursive(parent):
try:
children = parent['children']
except KeyError:
return []
result = []
for child in children:
result.append(child)
result.extend(get_children_recursive(child))
return result
# Annotate every the dev_info element with children information
_get_dev_info_tree(dev_infos)
for dev_info in dev_infos:
if dev_info['name'] == device_info['name']:
return get_children_recursive(dev_info)
return []
def get_affected_passthrough_devices(libvirt_conn, passthrough_dev):
dev_infos = _get_all_host_dev_infos(libvirt_conn)
group_devices = _get_same_iommugroup_devices(dev_infos, passthrough_dev)
if not group_devices:
# On host without iommu group support, the affected devices should
# at least include all children devices
group_devices.extend(_get_children_devices(dev_infos, passthrough_dev))
return group_devices
def get_dev_info(node_dev):
""" Parse the node device XML string into dict according to
http://libvirt.org/formatnode.html.
scsi_generic is not documented in libvirt official website. Try to
parse scsi_generic according to the following libvirt path series.
https://www.redhat.com/archives/libvir-list/2013-June/msg00014.html
scsi_target is not documented in libvirt official website. Try to
parse scsi_target according to the libvirt commit db19834a0a.
"""
xmlstr = node_dev.XMLDesc(0)
info = dictize(xmlstr)['device']
dev_type = info['capability'].pop('type')
info['device_type'] = dev_type
cap_dict = info.pop('capability')
info.update(cap_dict)
# parent device not found: set as None
info['parent'] = info.get('parent')
if dev_type in ('scsi', 'scsi_generic', 'scsi_target', 'system', 'usb'):
return info
if dev_type in ('net', 'pci', 'scsi_host', 'storage', 'usb_device'):
return globals()[f'_get_{dev_type}_dev_info'](info)
wok_log.error(f'Unknown device type: {dev_type}')
return info
def _get_net_dev_info(info):
cap = info.pop('capability')
links = {'80203': 'IEEE 802.3', '80211': 'IEEE 802.11'}
link_raw = cap['type']
info['link_type'] = links.get(link_raw, link_raw)
return info
def _get_pci_dev_info(info):
for k in ('vendor', 'product'):
try:
description = info[k].pop('pyval')
except KeyError:
description = None
info[k]['description'] = description
if 'path' not in info:
# Old libvirt does not provide syspath info
info['path'] = (
'/sys/bus/pci/devices/'
'%(domain)04x:%(bus)02x:%(slot)02x.%(function)01x'
% {
'domain': info['domain'],
'bus': info['bus'],
'slot': info['slot'],
'function': info['function'],
}
)
try:
info['iommuGroup'] = int(info['iommuGroup']['number'])
except KeyError:
# Old libvirt does not provide syspath info, figure it out ourselves
iommu_link = os.path.join(info['path'], 'iommu_group')
if os.path.exists(iommu_link):
iommu_path = os.path.realpath(iommu_link)
try:
info['iommuGroup'] = int(iommu_path.rsplit('/', 1)[1])
except (ValueError, IndexError):
# No IOMMU group support at all.
pass
else:
# No IOMMU group support at all.
pass
return info
def _get_scsi_host_dev_info(info):
try:
cap_info = info.pop('capability')
except KeyError:
# kimchi.model.libvirtstoragepool.ScsiPoolDef assumes
# info['adapter']['type'] always exists.
info['adapter'] = {'type': ''}
return info
if isinstance(cap_info, list):
info['adapter'] = {}
for cap in cap_info:
if cap['type'] == 'vport_ops':
del cap['type']
info['adapter']['vport_ops'] = cap
else:
info['adapter'].update(cap)
else:
info['adapter'] = cap_info
return info
def _get_storage_dev_info(info):
try:
cap_info = info.pop('capability')
except KeyError:
return info
if cap_info['type'] == 'removable':
cap_info['available'] = bool(cap_info.pop('media_available'))
if cap_info['available']:
for k in ('size', 'label'):
try:
cap_info[k] = cap_info.pop('media_' + k)
except KeyError:
cap_info[k] = None
info['media'] = cap_info
return info
def _get_usb_device_dev_info(info):
for k in ('vendor', 'product'):
try:
info[k]['description'] = info[k].pop('pyval')
except KeyError:
# Some USB devices don't provide vendor/product description.
pass
return info
# For test and debug
def _print_host_dev_tree(libvirt_conn):
dev_infos = _get_all_host_dev_infos(libvirt_conn)
root = _get_dev_info_tree(dev_infos)
if root is None:
print('No device found')
return
print('-----------------')
print('\n'.join(_format_dev_node(root)))
def _format_dev_node(node):
try:
children = node['children']
del node['children']
except KeyError:
children = []
lines = []
lines.extend([' ~' + line for line in pformat(node).split('\n')])
count = len(children)
for i, child in enumerate(children):
if count == 1:
lines.append(' \\-----------------')
else:
lines.append(' +-----------------')
clines = _format_dev_node(child)
if i == count - 1:
p = ' '
else:
p = ' |'
lines.extend([p + cline for cline in clines])
lines.append('')
return lines
if __name__ == '__main__':
libvirt_conn = LibvirtConnection('qemu:///system').get()
_print_host_dev_tree(libvirt_conn)
print('Eligible passthrough devices:')
pprint(get_passthrough_dev_infos(libvirt_conn))
================================================
FILE: model/interfaces.py
================================================
#
# Project Kimchi
#
# Copyright IBM Corp, 2015-2017
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
import ethtool
from wok.exception import InvalidParameter
from wok.exception import NotFoundError
from wok.plugins.kimchi import network as netinfo
from wok.plugins.kimchi.model.networks import NetworksModel
from wok.stringutils import encode_value
from wok.utils import wok_log
class InterfacesModel(object):
def __init__(self, **kargs):
self.conn = kargs['conn']
self.networks = NetworksModel(**kargs)
def get_list(self, _inuse=None):
if _inuse == 'true':
return list(
set(netinfo.all_favored_interfaces()) &
set(self.networks.get_all_networks_interfaces())
)
elif _inuse == 'false':
return list(
set(netinfo.all_favored_interfaces()) -
set(self.networks.get_all_networks_interfaces())
)
elif _inuse is None:
return list(set(netinfo.all_favored_interfaces()))
else:
wok_log.error(
f'Invalid filter _inuse. _inuse: {_inuse}. Supported'
f' options are true/false'
)
raise InvalidParameter(
'KCHIFACE0002E', {'supported_inuse': ['true', 'false']}
)
class InterfaceModel(object):
def __init__(self, **kargs):
pass
def lookup(self, name):
if encode_value(name) not in map(encode_value, ethtool.get_devices()):
raise NotFoundError('KCHIFACE0001E', {'name': name})
ipaddr = ''
netmask = ''
module = 'unknown'
status = 'down'
try:
ipaddr = ethtool.get_ipaddr(encode_value(name))
netmask = ethtool.get_netmask(encode_value(name))
module = ethtool.get_module(encode_value(name))
flags = ethtool.get_flags(encode_value(name))
status = 'up' if flags & (
ethtool.IFF_RUNNING | ethtool.IFF_UP) else 'down'
except IOError:
pass
iface_type = netinfo.get_interface_type(name)
return {
'name': name,
'type': iface_type,
'status': status,
'ipaddr': ipaddr,
'netmask': netmask,
'module': module,
}
================================================
FILE: model/libvirtconnection.py
================================================
#
# Project Kimchi
#
# Copyright IBM Corp, 2015-2016
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
import threading
import time
import libvirt
from wok.model.notifications import add_notification
from wok.model.notifications import del_notification
from wok.model.notifications import notificationsStore
from wok.plugins.kimchi.utils import is_libvirtd_up
from wok.utils import wok_log
class LibvirtConnection(object):
_connections = {}
_connectionLock = threading.Lock()
def __init__(self, uri):
self.uri = uri
if self.uri not in LibvirtConnection._connections:
LibvirtConnection._connections[self.uri] = {}
self._connections = LibvirtConnection._connections[self.uri]
self.wrappables = self.get_wrappable_objects()
def get_wrappable_objects(self):
"""
When a wrapped function returns an instance of another libvirt object,
we also want to wrap that object so we can catch errors that happen
when calling its methods.
"""
objs = []
for name in (
'virDomain',
'virDomainSnapshot',
'virInterface',
'virNWFilter',
'virNetwork',
'virNodeDevice',
'virSecret',
'virStoragePool',
'virStorageVol',
'virStream',
):
try:
attr = getattr(libvirt, name)
except AttributeError:
pass
objs.append(attr)
return tuple(objs)
def get(self, conn_id=0):
"""
Return current connection to libvirt or open a new one. Wrap all
callable libvirt methods so we can catch connection errors and handle
them by restarting the server.
"""
def wrapMethod(f):
def wrapper(*args, **kwargs):
try:
ret = f(*args, **kwargs)
return ret
except libvirt.libvirtError as e:
edom = e.get_error_domain()
ecode = e.get_error_code()
EDOMAINS = (libvirt.VIR_FROM_REMOTE, libvirt.VIR_FROM_RPC)
ECODES = (
libvirt.VIR_ERR_SYSTEM_ERROR,
libvirt.VIR_ERR_INTERNAL_ERROR,
libvirt.VIR_ERR_NO_CONNECT,
libvirt.VIR_ERR_INVALID_CONN,
)
if edom in EDOMAINS and ecode in ECODES:
wok_log.error(
'Connection to libvirt broken. '
'Recycling. ecode: %d edom: %d' % (ecode, edom)
)
with LibvirtConnection._connectionLock:
self._connections[conn_id] = None
raise
wrapper.__name__ = f.__name__
wrapper.__doc__ = f.__doc__
return wrapper
if not is_libvirtd_up():
wok_log.error('Libvirt service is not active.')
add_notification('KCHCONN0002E', plugin_name='/plugins/kimchi')
return None
elif notificationsStore.get('KCHCONN0002E') is not None:
try:
del_notification('KCHCONN0002E')
except Exception:
# If notification was not found, just ignore
pass
with LibvirtConnection._connectionLock:
conn = self._connections.get(conn_id)
if not conn:
conn = self._get_new_connection()
for name in dir(libvirt.virConnect):
method = getattr(conn, name)
if callable(method) and not name.startswith('_'):
setattr(conn, name, wrapMethod(method))
for cls in self.wrappables:
for name in dir(cls):
method = getattr(cls, name)
if callable(method) and not name.startswith('_'):
setattr(cls, name, wrapMethod(method))
self._connections[conn_id] = conn
# In case we're running into troubles with keeping the
# connections alive we should place here:
# conn.setKeepAlive(interval=5, count=3)
# However the values need to be considered wisely to not affect
# hosts which are hosting a lot of virtual machines
return conn
def _get_new_connection(self):
retries = 5
while True:
retries = retries - 1
try:
return libvirt.open(self.uri)
except libvirt.libvirtError:
wok_log.error('Unable to connect to libvirt.')
if not retries:
wok_log.error(
'Unable to establish connection '
'with libvirt. Please check '
'your libvirt URI which is often '
'defined in '
'/etc/libvirt/libvirt.conf'
)
add_notification(
'KCHCONN0001E', plugin_name='/plugins/kimchi'
)
return None
time.sleep(2)
def isQemuURI(self):
"""
This method will return True or Value when the system libvirt
URI is a qemu based URI. For example:
qemu:///system or qemu+tcp://someipaddress/system
"""
if self.get().getURI().startswith('qemu'):
return True
else:
return False
================================================
FILE: model/libvirtevents.py
================================================
#
# Project Kimchi
#
# Copyright IBM Corp, 2016-2017
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
import time
import cherrypy
import libvirt
from wok.exception import OperationFailed
from wok.message import WokMessage
from wok.model.notifications import add_notification
from wok.utils import wok_log
class LibvirtEvents(object):
def __init__(self):
# Register default implementation of event handlers
if libvirt.virEventRegisterDefaultImpl() < 0:
raise OperationFailed('KCHEVENT0001E')
# Run a background thread with the event loop. Using cherrypy
# BackgroundTask class due to issues when using threading module with
# cherrypy.
self.event_loop_thread = cherrypy.process.plugins.BackgroundTask(
2, self._event_loop_run
)
self.event_loop_thread.setName('KimchiLibvirtEventLoop')
self.event_loop_thread.setDaemon(True)
self.event_loop_thread.start()
# Set an event timeout to control the self._event_loop_run
if libvirt.virEventAddTimeout(0, self._kimchi_EventTimeout, None) < 0:
raise OperationFailed('KCHEVENT0002E')
# Event loop method to be executed in background as thread
def _event_loop_run(self):
while True:
if libvirt.virEventRunDefaultImpl() < 0:
raise OperationFailed('KCHEVENT0003E')
def is_event_loop_alive(self):
return self.event_loop_thread.isAlive()
# Event loop handler used to limit length of waiting for any other event.
def _kimchi_EventTimeout(self, timer, opaque):
time.sleep(0.01)
def event_enospc_cb(self, conn, dom, path, dev, action, reason, args):
if reason == 'enospc':
info = {'vm': dom.name(), 'srcPath': path, 'devAlias': dev}
add_notification('KCHEVENT0004W', info, '/plugins/kimchi')
msg = WokMessage('KCHEVENT0004W', info, '/plugins/kimchi')
wok_log.warning(msg.get_text())
def handleEnospc(self, conn):
"""
Register Libvirt IO_ERROR_REASON event to handle host ENOSPC
"""
try:
conn.get().domainEventRegisterAny(
None,
libvirt.VIR_DOMAIN_EVENT_ID_IO_ERROR_REASON,
self.event_enospc_cb,
libvirt.VIR_DOMAIN_EVENT_ID_IO_ERROR_REASON,
)
except (libvirt.libvirtError, AttributeError) as e:
if type(e) == AttributeError:
reason = 'Libvirt service is not running'
else:
reason = e
wok_log.error('Register of ENOSPC event failed: %s' % reason)
def registerAttachDevicesEvent(self, conn, cb, arg):
"""
register libvirt event to listen to devices attachment
"""
try:
return conn.get().domainEventRegisterAny(
None, libvirt.VIR_DOMAIN_EVENT_ID_DEVICE_ADDED, cb, arg
)
except (AttributeError, libvirt.libvirtError) as e:
wok_log.error(f'register attach event failed: {str(e)}')
def registerDetachDevicesEvent(self, conn, cb, arg):
"""
register libvirt event to listen to devices detachment
"""
try:
return conn.get().domainEventRegisterAny(
None, libvirt.VIR_DOMAIN_EVENT_ID_DEVICE_REMOVED, cb, arg
)
except libvirt.libvirtError as e:
wok_log.error(f'register detach event failed: {str(e)}')
def registerPoolEvents(self, conn, cb, arg):
"""
Register libvirt events to listen to any pool change
"""
def lifecycle_cb(conn, dom, event, detail, opaque):
return cb(opaque)
pool_events = [
(libvirt.VIR_STORAGE_POOL_EVENT_ID_LIFECYCLE, lifecycle_cb)
]
for ev, ev_cb in pool_events:
try:
conn.get().storagePoolEventRegisterAny(None, ev, ev_cb, arg)
except libvirt.libvirtError as e:
wok_log.error(
f'Unable to register pool event handler: {str(e)}')
def registerNetworkEvents(self, conn, cb, arg):
"""
Register libvirt events to listen to any network change
"""
def lifecycle_cb(conn, dom, event, detail, opaque):
return cb(opaque)
try:
conn.get().networkEventRegisterAny(
None,
libvirt.VIR_NETWORK_EVENT_ID_LIFECYCLE,
lifecycle_cb,
arg
)
except libvirt.libvirtError as e:
wok_log.error(
f'Unable to register network event handler: {str(e)}')
def registerDomainEvents(self, conn, cb, arg):
"""
Register libvirt events to listen to any domain change
"""
def lifecycle_cb(conn, dom, event, detail, opaque):
return cb(opaque)
def reboot_cb(conn, pool, opaque):
return cb(opaque)
events = [
(libvirt.VIR_DOMAIN_EVENT_ID_LIFECYCLE, lifecycle_cb),
(libvirt.VIR_DOMAIN_EVENT_ID_REBOOT, reboot_cb)
]
for ev, ev_cb in events:
try:
conn.get().domainEventRegisterAny(None, ev, ev_cb, arg)
except libvirt.libvirtError as e:
wok_log.error(
f'Unable to register domain event handler: {str(e)}')
================================================
FILE: model/libvirtstoragepool.py
================================================
#
# Project Kimchi
#
# Copyright IBM Corp, 2015-2016
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
import os
import tempfile
import libvirt
import lxml.etree as ET
from lxml.builder import E
from wok.exception import InvalidParameter
from wok.exception import OperationFailed
from wok.exception import TimeoutExpired
from wok.plugins.kimchi.iscsi import TargetClient
from wok.rollbackcontext import RollbackContext
from wok.utils import parse_cmd_output
from wok.utils import run_command
from wok.utils import wok_log
class StoragePoolDef(object):
@classmethod
def create(cls, poolArgs):
for klass in cls.__subclasses__():
if poolArgs['type'] == klass.poolType:
return klass(poolArgs)
raise OperationFailed('KCHPOOL0014E', {'type': poolArgs['type']})
def __init__(self, poolArgs):
self.poolArgs = poolArgs
def prepare(self, conn):
""" Validate pool arguments and perform preparations. Operation which
would cause side effect should be put here. Subclasses can optionally
override this method, or it always succeeds by default. """
pass
@property
def xml(self):
""" Subclasses have to override this method to actually generate the
storage pool XML definition. Should cause no side effect and be
idempotent"""
# TODO: When add new pool type, should also add the related test in
# tests/test_storagepool.py
raise OperationFailed('KCHPOOL0015E', {'pool': self})
class DirPoolDef(StoragePoolDef):
poolType = 'dir'
@property
def xml(self):
pool = E.pool(type='dir')
pool.append(E.name(self.poolArgs['name']))
pool.append(E.target(E.path(self.poolArgs['path'])))
return ET.tostring(pool, encoding='unicode', pretty_print=True)
class NetfsPoolDef(StoragePoolDef):
poolType = 'netfs'
def __init__(self, poolArgs):
super(NetfsPoolDef, self).__init__(poolArgs)
self.path = '/var/lib/kimchi/nfs_mount/' + self.poolArgs['name']
def prepare(self, conn):
mnt_point = tempfile.mkdtemp(dir='/tmp')
export_path = '%s:%s' % (
self.poolArgs['source']['host'],
self.poolArgs['source']['path'],
)
mount_cmd = [
'mount',
'-o',
'soft,timeo=100,retrans=3,retry=0',
export_path,
mnt_point,
]
umount_cmd = ['umount', '-f', export_path]
mounted = False
# Due to an NFS bug (See Red Hat BZ 1023059), NFSv4 exports may take
# 10-15 seconds to mount the first time.
cmd_timeout = 15
with RollbackContext() as rollback:
rollback.prependDefer(os.rmdir, mnt_point)
try:
run_command(mount_cmd, cmd_timeout)
rollback.prependDefer(run_command, umount_cmd, cmd_timeout)
except TimeoutExpired:
raise InvalidParameter('KCHPOOL0012E', {'path': export_path})
with open('/proc/mounts', 'r') as f:
rawMounts = f.read()
output_items = ['dev_path', 'mnt_point', 'type']
mounts = parse_cmd_output(rawMounts, output_items)
for item in mounts:
if 'dev_path' in item and item['dev_path'] == export_path:
mounted = True
if not mounted:
raise InvalidParameter('KCHPOOL0013E', {'path': export_path})
@property
def xml(self):
pool = E.pool(type='netfs')
pool.append(E.name(self.poolArgs['name']))
source = E.source()
source.append(E.host(name=self.poolArgs['source']['host']))
source.append(E.dir(path=self.poolArgs['source']['path']))
pool.append(source)
pool.append(E.target(E.path(self.path)))
return ET.tostring(pool, encoding='unicode', pretty_print=True)
class LogicalPoolDef(StoragePoolDef):
poolType = 'logical'
def __init__(self, poolArgs):
super(LogicalPoolDef, self).__init__(poolArgs)
self.path = '/dev/' + self.poolArgs['name']
@property
def xml(self):
pool = E.pool(type='logical')
pool.append(E.name(self.poolArgs['name']))
if not self.poolArgs['source'].get('from_vg', False):
source = E.source()
for device_path in self.poolArgs['source']['devices']:
source.append(E.device(path=device_path))
pool.append(source)
pool.append(E.target(E.path(self.path)))
return ET.tostring(pool, encoding='unicode', pretty_print=True)
class ScsiPoolDef(StoragePoolDef):
poolType = 'scsi'
def prepare(self, conn=None):
tmp_name = self.poolArgs['source']['name']
self.poolArgs['source']['name'] = tmp_name.replace('scsi_', '')
# fc_host adapters type are only available in libvirt >= 1.0.5
if not self.poolArgs['fc_host_support']:
self.poolArgs['source']['adapter']['type'] = 'scsi_host'
msg = (
"Libvirt version <= 1.0.5. Setting SCSI host name as '%s'; "
"setting SCSI adapter type as 'scsi_host'; "
'ignoring wwnn and wwpn.' % tmp_name
)
wok_log.info(msg)
# Path for Fibre Channel scsi hosts
self.poolArgs['path'] = '/dev/disk/by-path'
if not self.poolArgs['source']['adapter']['type']:
self.poolArgs['source']['adapter']['type'] = 'scsi_host'
@property
def xml(self):
pool = E.pool(type='scsi')
pool.append(E.name(self.poolArgs['name']))
adapter = E.adapter(type=self.poolArgs['source']['adapter']['type'])
adapter.set('name', self.poolArgs['source']['name'])
adapter.set('wwnn', self.poolArgs['source']['adapter']['wwnn'])
adapter.set('wwpn', self.poolArgs['source']['adapter']['wwpn'])
pool.append(E.source(adapter))
pool.append(E.target(E.path(self.poolArgs['path'])))
return ET.tostring(pool, encoding='unicode', pretty_print=True)
class IscsiPoolDef(StoragePoolDef):
poolType = 'iscsi'
def prepare(self, conn):
source = self.poolArgs['source']
if not TargetClient(**source).validate():
msg_args = {'host': source['host'], 'target': source['target']}
raise OperationFailed('KCHISCSI0002E', msg_args)
self._prepare_auth(conn)
def _prepare_auth(self, conn):
try:
auth = self.poolArgs['source']['auth']
except KeyError:
return
try:
virSecret = conn.secretLookupByUsage(
libvirt.VIR_SECRET_USAGE_TYPE_ISCSI, self.poolArgs['name']
)
except libvirt.libvirtError:
secret = E.secret(ephemeral='no', private='yes')
description = E.description(
'Secret for iSCSI storage pool %s' % self.poolArgs['name']
)
secret.append(description)
secret.append(E.auth(type='chap', username=auth['username']))
usage = E.usage(type='iscsi')
usage.append(E.target(self.poolArgs['name']))
secret.append(usage)
virSecret = conn.secretDefineXML(ET.tostring(secret, encoding='unicode'))
virSecret.setValue(auth['password'])
@property
def xml(self):
pool = E.pool(type='iscsi')
pool.append(E.name(self.poolArgs['name']))
host = E.host(name=self.poolArgs['source']['host'])
port = self.poolArgs['source'].get('port')
if port is not None:
host.set('port', str(port))
source = E.source(host)
source.append(E.device(path=self.poolArgs['source']['target']))
source_auth = self.poolArgs['source'].get('auth')
if source_auth is not None:
auth = E.auth(type='chap')
auth.set('username', source_auth['username'])
secret = E.secret(type='iscsi')
secret.set('usage', self.poolArgs['name'])
auth.append(secret)
source.append(auth)
pool.append(source)
pool.append(E.target(E.path('/dev/disk/by-id')))
return ET.tostring(pool, encoding='unicode', pretty_print=True)
================================================
FILE: model/model.py
================================================
#
# Project Kimchi
#
# Copyright IBM Corp, 2015-2017
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
from wok.basemodel import BaseModel
from wok.objectstore import ObjectStore
from wok.plugins.kimchi import config
from wok.plugins.kimchi.model.libvirtconnection import LibvirtConnection
from wok.plugins.kimchi.model.libvirtevents import LibvirtEvents
from wok.pushserver import send_wok_notification
from wok.utils import get_all_model_instances
from wok.utils import get_model_instances
class Model(BaseModel):
def __init__(self, libvirt_uri=None, objstore_loc=None):
self.objstore = ObjectStore(objstore_loc or config.get_object_store())
self.conn = LibvirtConnection(libvirt_uri)
# Register for libvirt events
self.events = LibvirtEvents()
self.events.handleEnospc(self.conn)
self.events.registerPoolEvents(self.conn, self._events_handler,
'storages')
self.events.registerNetworkEvents(self.conn, self._events_handler,
'networks')
self.events.registerDomainEvents(self.conn, self._events_handler,
'vms')
kargs = {'objstore': self.objstore, 'conn': self.conn,
'eventsloop': self.events}
models = get_all_model_instances(__name__, __file__, kargs)
# Import task model from Wok
instances = get_model_instances('wok.model.tasks')
for instance in instances:
models.append(instance(**kargs))
super(Model, self).__init__(models)
def _events_handler(self, api):
# Do not use any known method (POST, PUT, DELETE) as it is used by Wok
# engine and may lead in having 2 notifications for the same action
send_wok_notification('/plugins/kimchi', api, 'METHOD')
================================================
FILE: model/networks.py
================================================
#
# Project Kimchi
#
# Copyright IBM Corp, 2015-2017
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
import copy
import ipaddress
import time
import libvirt
from libvirt import VIR_INTERFACE_XML_INACTIVE
from wok.exception import InvalidOperation
from wok.exception import InvalidParameter
from wok.exception import MissingParameter
from wok.exception import NotFoundError
from wok.exception import OperationFailed
from wok.plugins.kimchi import network as netinfo
from wok.plugins.kimchi.config import kimchiPaths
from wok.plugins.kimchi.model.featuretests import FeatureTests
from wok.plugins.kimchi.osinfo import defaults as tmpl_defaults
from wok.plugins.kimchi.xmlutils.interface import get_iface_xml
from wok.plugins.kimchi.xmlutils.network import create_linux_bridge_xml
from wok.plugins.kimchi.xmlutils.network import create_vlan_tagged_bridge_xml
from wok.plugins.kimchi.xmlutils.network import get_no_network_config_xml
from wok.plugins.kimchi.xmlutils.network import to_network_xml
from wok.utils import run_command
from wok.utils import wok_log
from wok.xmlutils.utils import xpath_get_text
KIMCHI_BRIDGE_PREFIX = 'kb'
class NetworksModel(object):
def __init__(self, **kargs):
self.conn = kargs['conn']
if self.conn.get() is not None:
if self.conn.isQemuURI():
self._check_default_networks()
def _check_default_networks(self):
networks = list(set(tmpl_defaults.get('networks', [])))
conn = self.conn.get()
for net_name in networks:
error_msg = (
'Network %s does not exist or is not '
'active. Please, check the configuration in '
'%s/template.conf to ensure it lists only valid '
'networks.' % (net_name, kimchiPaths.sysconf_dir)
)
try:
net = conn.networkLookupByName(net_name)
except libvirt.libvirtError as e:
wok_log.error(f'Fatal: Unable to find network {net_name}.')
wok_log.error(f'Details: {str(e)}')
raise Exception(error_msg)
if net.isActive() == 0:
try:
net.create()
except libvirt.libvirtError as e:
wok_log.error(
f'Fatal: Unable to activate network {net_name}.')
wok_log.error(f'Details: {str(e)}')
raise Exception(error_msg)
def create(self, params):
conn = self.conn.get()
name = params['name']
if name in self.get_list():
raise InvalidOperation('KCHNET0001E', {'name': name})
# handle connection type
connection = params['connection']
if connection in ['nat', 'isolated']:
if connection == 'nat':
params['forward'] = {'mode': 'nat'}
# set subnet; bridge/macvtap networks do not need subnet
self._set_network_subnet(params)
else:
self._check_network_interface(params)
if connection == 'macvtap':
self._set_network_macvtap(params)
elif connection == 'bridge':
self._set_network_bridge(params)
elif connection in ['passthrough', 'vepa']:
self._set_network_multiple_interfaces(params)
# create network XML
xml = to_network_xml(**params)
try:
network = conn.networkDefineXML(xml)
network.setAutostart(params.get('autostart', True))
except libvirt.libvirtError as e:
raise OperationFailed(
'KCHNET0008E', {'name': name, 'err': e.get_error_message()}
)
return name
def get_list(self):
conn = self.conn.get()
names = conn.listNetworks() + conn.listDefinedNetworks()
return sorted(names)
def _get_available_address(self, addr_pools=None):
if addr_pools is None:
addr_pools = []
invalid_addrs = []
for net_name in self.get_list():
network = NetworkModel.get_network(self.conn.get(), net_name)
xml = network.XMLDesc(0)
subnet = NetworkModel.get_network_from_xml(xml)['subnet']
subnet and invalid_addrs.append(ipaddress.IPv4Network(subnet, False))
addr_pools = addr_pools if addr_pools else netinfo.PrivateNets
return netinfo.get_one_free_network(invalid_addrs, addr_pools)
def _set_network_subnet(self, params):
netaddr = params.get('subnet', '')
# lookup a free network address for nat and isolated automatically
if not netaddr:
netaddr = self._get_available_address()
if not netaddr:
raise OperationFailed('KCHNET0009E', {'name': params['name']})
try:
ip = ipaddress.IPv4Network(netaddr, False)
except ValueError:
raise InvalidParameter(
'KCHNET0003E', {'subnet': netaddr, 'network': params['name']}
)
ip.network_address = ip.network_address + 1
dhcp_start = str(ip.network_address + int(ip.num_addresses / 2))
dhcp_end = str(ip.network_address + int(ip.num_addresses - 3))
params.update(
{'net': str(ip), 'dhcp': {
'range': {'start': dhcp_start, 'end': dhcp_end}}}
)
def _ensure_iface_up(self, iface):
if netinfo.operstate(iface) != 'up':
_, err, rc = run_command(['ip', 'link', 'set', 'dev', iface, 'up'])
if rc != 0:
raise OperationFailed(
'KCHNET0020E', {'iface': iface, 'err': err})
# Add a delay to wait for the link change takes into effect.
for i in range(10):
time.sleep(1)
if netinfo.operstate(iface) == 'up':
break
else:
raise OperationFailed('KCHNET0021E', {'iface': iface})
def _check_network_interface(self, params):
if not params.get('interfaces'):
raise MissingParameter('KCHNET0004E', {'name': params['name']})
if len(params['interfaces']) == 0:
raise InvalidParameter('KCHNET0029E')
conn = params['connection']
if conn in ['bridge', 'macvtap'] and len(params['interfaces']) > 1:
raise InvalidParameter('KCHNET0030E')
for iface in params['interfaces']:
if iface in self.get_all_networks_interfaces():
msg_args = {'iface': iface, 'network': params['name']}
raise InvalidParameter('KCHNET0006E', msg_args)
def _set_network_macvtap(self, params):
iface = params['interfaces'][0]
if 'vlan_id' in params or not (
netinfo.is_bare_nic(iface) or netinfo.is_bonding(iface)
):
raise InvalidParameter('KCHNET0028E', {'name': iface})
# set macvtap network
params['forward'] = {'mode': 'bridge', 'dev': iface}
def _set_network_multiple_interfaces(self, params):
for iface in params['interfaces']:
if 'vlan_id' in params or not (
netinfo.is_bare_nic(iface) or netinfo.is_bonding(iface)
):
raise InvalidParameter('KCHNET0028E', {'name': iface})
params['forward'] = {'mode': params['connection'],
'devs': params['interfaces']}
def _set_network_bridge(self, params):
params['forward'] = {'mode': 'bridge'}
# Bridges cannot be the trunk device of a VLAN
iface = params['interfaces'][0]
if 'vlan_id' in params and netinfo.is_bridge(iface):
raise InvalidParameter('KCHNET0019E', {'name': iface})
# User specified bridge interface, simply use it
self._ensure_iface_up(iface)
params['ovs'] = False
if netinfo.is_bridge(iface):
params['bridge'] = iface
if netinfo.is_ovs_bridge(iface):
params['ovs'] = True
# connection == macvtap and iface is not bridge
elif netinfo.is_bare_nic(iface) or netinfo.is_bonding(iface):
# libvirt bridge creation will fail with NetworkManager enabled
if FeatureTests.is_nm_running():
raise InvalidParameter('KCHNET0027E')
if 'vlan_id' in params:
params['bridge'] = self._create_vlan_tagged_bridge(
str(iface), str(params['vlan_id'])
)
else:
# create Linux bridge interface and use it as actual iface
iface = self._create_linux_bridge(iface)
params['bridge'] = iface
# unrecognized interface type: fail
else:
raise InvalidParameter('KCHNET0007E')
def get_all_networks_interfaces(self):
net_names = self.get_list()
interfaces = []
for name in net_names:
conn = self.conn.get()
network = conn.networkLookupByName(name)
xml = network.XMLDesc(0)
net_dict = NetworkModel.get_network_from_xml(xml)
forward = net_dict['forward']
(
forward['mode'] == 'bridge'
and forward['interface']
and interfaces.append(forward['interface'][0]) is None
or interfaces.extend(forward['interface'] + forward['pf'])
)
net_dict['bridge'] and interfaces.append(net_dict['bridge'])
return interfaces
def _create_bridge(self, name, xml):
conn = self.conn.get()
# check if name exists
if name in netinfo.all_interfaces():
raise InvalidOperation('KCHNET0010E', {'iface': name})
# create bridge through libvirt
try:
bridge = conn.interfaceDefineXML(xml)
bridge.create()
except libvirt.libvirtError as e:
raise OperationFailed(
'KCHNET0025E', {'name': name, 'err': e.get_error_message()}
)
def _create_linux_bridge(self, interface):
# get xml definition of interface
iface_xml = self._get_interface_desc_xml(interface)
# interface not defined in libvirt: try to define it
iface_defined = False
conn = self.conn.get()
if iface_xml is None:
try:
mac = netinfo.get_dev_macaddr(str(interface))
iface_xml = get_iface_xml(
{
'type': 'ethernet',
'name': interface,
'mac': mac,
'startmode': 'onboot',
}
)
conn.interfaceDefineXML(iface_xml)
iface_defined = True
except libvirt.libvirtError as e:
raise OperationFailed(
'KCHNET0024E', {'name': interface,
'err': e.get_error_message()}
)
# Truncate the interface name if it exceeds 13 characters to make sure
# the length of bridge name is less than 15 (its maximum value).
br_name = KIMCHI_BRIDGE_PREFIX + interface[-13:]
br_xml = create_linux_bridge_xml(br_name, interface, iface_xml)
# drop network config from interface
iface_defined or self._redefine_iface_no_network(interface, iface_xml)
# create and start bridge
self._create_bridge(br_name, br_xml)
return br_name
def _create_vlan_tagged_bridge(self, interface, vlan_id):
# Truncate the interface name if it exceeds 8 characters to make sure
# the length of bridge name is less than 15 (its maximum value).
br_name = KIMCHI_BRIDGE_PREFIX + interface[-8:] + '-' + vlan_id
br_xml = create_vlan_tagged_bridge_xml(br_name, interface, vlan_id)
self._create_bridge(br_name, br_xml)
return br_name
def _get_interface_desc_xml(self, name):
conn = self.conn.get()
try:
iface = conn.interfaceLookupByName(name)
xml = iface.XMLDesc(flags=VIR_INTERFACE_XML_INACTIVE)
except libvirt.libvirtError:
return None
return xml
def _redefine_iface_no_network(self, name, iface_xml):
conn = self.conn.get()
# drop network config from definition of interface
xml = get_no_network_config_xml(iface_xml)
try:
# redefine interface
conn.interfaceDefineXML(xml)
except libvirt.libvirtError as e:
raise OperationFailed(
'KCHNET0024E', {'name': name, 'err': e.get_error_message()}
)
class NetworkModel(object):
def __init__(self, **kargs):
self.conn = kargs['conn']
self.objstore = kargs['objstore']
self.collection = NetworksModel(**kargs)
def lookup(self, name):
network = self.get_network(self.conn.get(), name)
xml = network.XMLDesc(0)
net_dict = self.get_network_from_xml(xml)
subnet = net_dict['subnet']
dhcp = net_dict['dhcp']
forward = net_dict['forward']
interface = net_dict['bridge']
connection = forward['mode'] or 'isolated'
# FIXME, if we want to support other forward mode well.
if connection == 'bridge':
# macvtap bridge
interface = interface or forward['interface'][0]
if netinfo.is_nic(interface) or netinfo.is_bonding(interface):
connection = 'macvtap'
# exposing the network on linux bridge or macvtap interface
interface_subnet = netinfo.get_dev_netaddr(interface)
subnet = subnet if subnet else interface_subnet
# libvirt use format 192.168.0.1/24, standard should be 192.168.0.0/24
# http://www.ovirt.org/File:Issue3.png
if subnet:
subnet = ipaddress.IPv4Network(subnet, False)
subnet = '%s/%s' % (subnet.network_address, subnet.prefixlen)
if connection in ['passthrough', 'vepa']:
interfaces = xpath_get_text(xml, '/network/forward/interface/@dev')
else:
interfaces = [interface]
network_in_use, used_by_vms, _ = self._is_network_in_use(name)
return {
'connection': connection,
'interfaces': interfaces,
'subnet': subnet,
'dhcp': dhcp,
'vms': used_by_vms,
'in_use': network_in_use,
'autostart': network.autostart() == 1,
'state': network.isActive() and 'active' or 'inactive',
'persistent': True if network.isPersistent() else False,
}
def _is_network_in_use(self, name):
# All the networks listed as default in template.conf file should not
# be deactivate or deleted. Otherwise, we will allow user create
# inconsistent templates from scratch
vms = self._get_vms_attach_to_a_network(name)
tmpls = self._is_network_used_by_template(name)
if name in tmpl_defaults['networks']:
return True, vms, tmpls
return bool(vms) or bool(tmpls), vms, tmpls
def _is_network_used_by_template(self, network):
tmpl_list = []
with self.objstore as session:
templates = session.get_list('template')
for tmpl in templates:
tmpl_net = session.get('template', tmpl)['networks']
if network in tmpl_net:
tmpl_list.append(tmpl)
return tmpl_list
def _get_vms_attach_to_a_network(self, network, filter='all'):
DOM_STATE_MAP = {
'nostate': 0,
'running': 1,
'blocked': 2,
'paused': 3,
'shutdown': 4,
'shutoff': 5,
'crashed': 6,
}
state = DOM_STATE_MAP.get(filter)
vms = []
conn = self.conn.get()
for dom in conn.listAllDomains(0):
networks = self._vm_get_networks(dom)
if network in networks and (state is None or state == dom.state(0)[0]):
vms.append(dom.name())
return vms
def _vm_get_networks(self, dom):
xml = dom.XMLDesc(0)
xpath = "/domain/devices/interface[@type='network']/source/@network"
return xpath_get_text(xml, xpath)
def activate(self, name):
network = self.get_network(self.conn.get(), name)
try:
network.create()
except libvirt.libvirtError as e:
raise OperationFailed(
'KCHNET0022E', {'name': name, 'err': e.message})
def deactivate(self, name):
in_use, used_by_vms, used_by_tmpls = self._is_network_in_use(name)
vms = 'N/A' if len(used_by_vms) == 0 else ', '.join(used_by_vms)
tmpls = 'N/A' if len(used_by_tmpls) == 0 else ', '.join(used_by_tmpls)
if in_use:
raise InvalidOperation(
'KCHNET0018E', {'name': name, 'vms': vms, 'tmpls': tmpls}
)
network = self.get_network(self.conn.get(), name)
network.destroy()
def delete(self, name):
in_use, used_by_vms, used_by_tmpls = self._is_network_in_use(name)
vms = 'N/A' if len(used_by_vms) == 0 else ', '.join(used_by_vms)
tmpls = 'N/A' if len(used_by_tmpls) == 0 else ', '.join(used_by_tmpls)
if in_use:
raise InvalidOperation(
'KCHNET0017E', {'name': name, 'vms': vms, 'tmpls': tmpls}
)
network = self.get_network(self.conn.get(), name)
if network.isActive():
raise InvalidOperation('KCHNET0005E', {'name': name})
self._remove_bridge(network)
network.undefine()
@staticmethod
def get_network(conn, name):
try:
return conn.networkLookupByName(name)
except libvirt.libvirtError:
raise NotFoundError('KCHNET0002E', {'name': name})
@staticmethod
def get_network_from_xml(xml):
address = xpath_get_text(xml, '/network/ip/@address')
address = address and address[0] or ''
netmask = xpath_get_text(xml, '/network/ip/@netmask')
netmask = netmask and netmask[0] or ''
net = address and netmask and '/'.join([address, netmask]) or ''
dhcp_start = xpath_get_text(xml, '/network/ip/dhcp/range/@start')
dhcp_start = dhcp_start and dhcp_start[0] or ''
dhcp_end = xpath_get_text(xml, '/network/ip/dhcp/range/@end')
dhcp_end = dhcp_end and dhcp_end[0] or ''
dhcp = {'start': dhcp_start, 'end': dhcp_end}
forward_mode = xpath_get_text(xml, '/network/forward/@mode')
forward_mode = forward_mode and forward_mode[0] or ''
forward_if = xpath_get_text(xml, '/network/forward/interface/@dev')
forward_pf = xpath_get_text(xml, '/network/forward/pf/@dev')
bridge = xpath_get_text(xml, '/network/bridge/@name')
bridge = bridge and bridge[0] or ''
return {
'subnet': net,
'dhcp': dhcp,
'bridge': bridge,
'forward': {
'mode': forward_mode,
'interface': forward_if,
'pf': forward_pf,
},
}
def _remove_bridge(self, network):
try:
bridge = network.bridgeName()
except libvirt.libvirtError:
pass
else:
if bridge.startswith(KIMCHI_BRIDGE_PREFIX):
conn = self.conn.get()
iface = conn.interfaceLookupByName(bridge)
iface.isActive() and iface.destroy(0)
iface.undefine()
def update(self, name, params):
info = self.lookup(name)
info['name'] = name
original = copy.deepcopy(info)
# validate update parameters
connection = info['connection']
if connection in ['bridge', 'macvtap', 'passthrough', 'vepa']:
if params.get('subnet'):
raise InvalidParameter('KCHNET0031E')
elif connection in ['nat', 'isolated']:
if params.get('vlan_id') or params.get('interfaces'):
raise InvalidParameter('KCHNET0032E')
# merge parameters
info.update(params)
# get target device if bridge was created by Kimchi
if connection == 'bridge':
iface = info['interfaces'][0]
if netinfo.is_bridge(iface) and iface.startswith(KIMCHI_BRIDGE_PREFIX):
port = netinfo.ports(iface)[0]
if netinfo.is_vlan(port):
dev = netinfo.get_vlan_device(port)
info['interfaces'] = original['interfaces'] = [dev]
# nic
else:
info['interfaces'] = original['interfaces'] = [port]
# delete original network
self.delete(name)
try:
# create new network
return self.collection.create(info)
except Exception:
# restore original network
self.collection.create(original)
raise
================================================
FILE: model/ovsbridges.py
================================================
#
# Project Kimchi
#
# Copyright IBM Corp, 2016-2017
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
from wok.plugins.kimchi.network import ovs_bridges
class OVSBridgesModel(object):
def get_list(self):
"""
Returns: list of ovs bridge names
"""
return ovs_bridges()
================================================
FILE: model/storagepools.py
================================================
#
# Project Kimchi
#
# Copyright IBM Corp, 2015-2017
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
import libvirt
import lxml.etree as ET
from lxml.builder import E
from wok.asynctask import AsyncTask
from wok.exception import InvalidOperation
from wok.exception import MissingParameter
from wok.exception import NotFoundError
from wok.exception import OperationFailed
from wok.plugins.kimchi.config import config
from wok.plugins.kimchi.config import get_kimchi_version
from wok.plugins.kimchi.config import kimchiPaths
from wok.plugins.kimchi.model.config import CapabilitiesModel
from wok.plugins.kimchi.model.host import DeviceModel
from wok.plugins.kimchi.model.libvirtstoragepool import StoragePoolDef
from wok.plugins.kimchi.osinfo import defaults as tmpl_defaults
from wok.plugins.kimchi.scan import Scanner
from wok.plugins.kimchi.utils import is_s390x
from wok.plugins.kimchi.utils import pool_name_from_uri
from wok.utils import run_command
from wok.utils import wok_log
from wok.xmlutils.utils import xpath_get_text
ISO_POOL_NAME = 'kimchi_isos'
POOL_STATE_MAP = {
0: 'inactive',
1: 'initializing',
2: 'active',
3: 'degraded',
4: 'inaccessible',
}
# Types of pools supported
STORAGE_SOURCES = {
'netfs': {'addr': '/pool/source/host/@name', 'path': '/pool/source/dir/@path'},
'iscsi': {
'addr': '/pool/source/host/@name',
'port': '/pool/source/host/@port',
'path': '/pool/source/device/@path',
},
'scsi': {
'adapter_type': '/pool/source/adapter/@type',
'adapter_name': '/pool/source/adapter/@name',
'wwnn': '/pool/source/adapter/@wwnn',
'wwpn': '/pool/source/adapter/@wwpn',
},
}
class StoragePoolsModel(object):
def __init__(self, **kargs):
self.conn = kargs['conn']
self.objstore = kargs['objstore']
self.scanner = Scanner(self._clean_scan)
self.scanner.delete()
self.caps = CapabilitiesModel(**kargs)
self.device = DeviceModel(**kargs)
if self.conn.get() is not None:
if self.conn.isQemuURI():
self._check_default_pools()
def _check_default_pools(self):
pools = {}
# Don't create default pool if it's not
# explicitly specified in template.conf
if is_s390x() and 'pool' not in tmpl_defaults['disks'][0]:
return
default_pool = tmpl_defaults['disks'][0]['pool']['name']
default_pool = default_pool.split('/')[-1]
pools[default_pool] = {}
if default_pool == 'default':
pools[default_pool] = {'path': '/var/lib/libvirt/images'}
if config.get('kimchi', {}).get('create_iso_pool', False):
pools['ISO'] = {'path': '/var/lib/kimchi/isos'}
conn = self.conn.get()
for pool_name in pools:
error_msg = (
'Storage pool %s does not exist or is not '
'active. Please, check the configuration in '
'%s/template.conf to ensure it lists only valid '
'storage.' % (pool_name, kimchiPaths.sysconf_dir)
)
try:
pool = conn.storagePoolLookupByName(pool_name)
except libvirt.libvirtError as e:
pool_path = pools[pool_name].get('path')
if pool_path is None:
wok_log.error(
f'Fatal: Unable to find storage pool {pool_name}.')
wok_log.error(f'Details: {str(e)}')
raise Exception(error_msg)
# Try to create the pool
pool = E.pool(E.name(pool_name), type='dir')
pool.append(E.target(E.path(pool_path)))
xml = ET.tostring(pool, encoding='unicode')
try:
pool = conn.storagePoolDefineXML(xml, 0)
except libvirt.libvirtError as e:
wok_log.error(
f'Fatal: Unable to create storage pool {pool_name}.')
wok_log.error(f'Details: {str(e)}')
raise Exception(error_msg)
# Build and set autostart value to pool
# Ignore error as the pool was already successfully created
try:
# Add build step to make sure target directory created
# The build process may fail when the pool directory
# already exists on system
pool.build(libvirt.VIR_STORAGE_POOL_BUILD_NEW)
pool.setAutostart(1)
except Exception:
pass
if pool.isActive() == 0:
try:
pool.create(0)
except libvirt.libvirtError as e:
wok_log.error(
f'Fatal: Unable to create storage pool {pool_name}.')
wok_log.error(f'Details: {str(e)}')
raise Exception(error_msg)
def get_list(self):
try:
conn = self.conn.get()
names = conn.listStoragePools()
names += conn.listDefinedStoragePools()
return sorted(names)
except libvirt.libvirtError as e:
raise OperationFailed(
'KCHPOOL0006E', {'err': e.get_error_message()})
def _check_lvm(self, name, from_vg):
vgdisplay_cmd = ['vgdisplay', name]
output, error, returncode = run_command(vgdisplay_cmd)
# From vgdisplay error codes:
# 1 error reading VGDA
# 2 volume group doesn't exist
# 3 not all physical volumes of volume group online
# 4 volume group not found
# 5 no volume groups found at all
# 6 error reading VGDA from lvmtab
if from_vg and returncode in [2, 4, 5]:
raise InvalidOperation('KCHPOOL0038E', {'name': name})
if not from_vg and returncode not in [2, 4, 5]:
raise InvalidOperation('KCHPOOL0036E', {'name': name})
def create(self, params):
task_id = None
conn = self.conn.get()
from_vg = params.get('source', {}).get('from_vg', False)
try:
name = params['name']
if name == ISO_POOL_NAME:
raise InvalidOperation('KCHPOOL0031E')
# The user may want to create a logical pool with the same name
# used before but a volume group will already exist with this name
# So check the volume group does not exist to create the pool
if params['type'] == 'logical':
self._check_lvm(name, from_vg)
if params['type'] == 'kimchi-iso':
task_id = self._do_deep_scan(params)
if params['type'] == 'scsi':
adapter_name = params['source']['adapter_name']
extra_params = self.device.lookup(adapter_name)
# Adds name, adapter_type, wwpn and wwnn to source information
params['source'].update(extra_params)
params['fc_host_support'] = self.caps.fc_host_support
poolDef = StoragePoolDef.create(params)
poolDef.prepare(conn)
xml = poolDef.xml
except KeyError as item:
raise MissingParameter(
'KCHPOOL0004E', {'item': str(item), 'name': name})
if name in self.get_list():
raise InvalidOperation('KCHPOOL0001E', {'name': name})
try:
if task_id:
# Create transient pool for deep scan
conn.storagePoolCreateXML(xml, 0)
return name
pool = conn.storagePoolDefineXML(xml, 0)
except libvirt.libvirtError as e:
wok_log.error(f'Problem creating Storage Pool: {str(e)}')
raise OperationFailed(
'KCHPOOL0007E', {'name': name, 'err': e.get_error_message()}
)
# Build and set autostart value to pool
# Ignore error as the pool was already successfully created
# The build process fails when the pool directory already exists
try:
if params['type'] in ['logical', 'dir', 'netfs', 'scsi']:
pool.build(libvirt.VIR_STORAGE_POOL_BUILD_NEW)
pool.setAutostart(1)
else:
pool.setAutostart(0)
except Exception:
pass
if params['type'] == 'netfs':
output, error, returncode = run_command(
['setsebool', '-P', 'virt_use_nfs=1']
)
if error or returncode:
wok_log.error(
'Unable to set virt_use_nfs=1. If you use '
'SELinux, this may prevent NFS pools from '
'being used.'
)
return name
def _clean_scan(self, pool_name):
try:
conn = self.conn.get()
pool = conn.storagePoolLookupByName(pool_name)
pool.destroy()
with self.objstore as session:
session.delete('scanning', pool_name)
except Exception as e:
wok_log.debug(f'Exception {e} occurred when cleaning scan result')
def _do_deep_scan(self, params):
scan_params = dict(ignore_list=[])
scan_params['scan_path'] = params['path']
params['type'] = 'dir'
for pool in self.get_list():
try:
res = StoragePoolModel(conn=self.conn, objstore=self.objstore).lookup(
pool
)
if res['state'] == 'active':
scan_params['ignore_list'].append(res['path'])
except Exception as e:
wok_log.debug(f'Exception {e} occured when get ignore path')
params['path'] = self.scanner.scan_dir_prepare(params['name'])
scan_params['pool_path'] = params['path']
task_id = AsyncTask(
f'/plugins/kimchi/storagepools/{ISO_POOL_NAME}',
self.scanner.start_scan,
scan_params,
).id
# Record scanning-task/storagepool mapping for future querying
try:
with self.objstore as session:
session.store(
'scanning', params['name'], task_id, get_kimchi_version())
return task_id
except Exception as e:
raise OperationFailed('KCHPOOL0037E', {'err': e.message})
class StoragePoolModel(object):
def __init__(self, **kargs):
self.conn = kargs['conn']
self.objstore = kargs['objstore']
@staticmethod
def get_storagepool(name, conn):
conn = conn.get()
try:
return conn.storagePoolLookupByName(name)
except libvirt.libvirtError as e:
if e.get_error_code() == libvirt.VIR_ERR_NO_STORAGE_POOL:
raise NotFoundError('KCHPOOL0002E', {'name': name})
else:
raise
def _get_storagepool_vols_num(self, pool):
if not pool.isActive():
return 0
try:
pool.refresh(0)
except Exception as e:
wok_log.error(f'Pool refresh failed: {e}')
return pool.numOfVolumes()
def _get_storage_source(self, pool_type, pool_xml):
source = {}
if pool_type not in STORAGE_SOURCES:
return source
for key, val in STORAGE_SOURCES[pool_type].items():
res = xpath_get_text(pool_xml, val)
if len(res) == 1:
source[key] = res[0]
elif len(res) == 0:
source[key] = ''
else:
source[key] = res
return source
def _nfs_status_online(self, pool, poolArgs=None):
if not poolArgs:
xml = pool.XMLDesc(0)
pool_type = xpath_get_text(xml, '/pool/@type')[0]
source = self._get_storage_source(pool_type, xml)
poolArgs = {}
poolArgs['name'] = pool.name()
poolArgs['type'] = pool_type
poolArgs['source'] = {
'path': source['path'], 'host': source['addr']}
conn = self.conn.get()
poolDef = StoragePoolDef.create(poolArgs)
try:
poolDef.prepare(conn)
return True
except Exception:
return False
def lookup(self, name):
pool = self.get_storagepool(name, self.conn)
info = pool.info()
autostart = True if pool.autostart() else False
persistent = True if pool.isPersistent() else False
xml = pool.XMLDesc(0)
path = xpath_get_text(xml, '/pool/target/path')[0]
pool_type = xpath_get_text(xml, '/pool/@type')[0]
source = self._get_storage_source(pool_type, xml)
# FIXME: nfs workaround - prevent any libvirt operation
# for a nfs if the corresponding NFS server is down.
if pool_type == 'netfs' and not self._nfs_status_online(pool):
wok_log.debug(
'NFS pool %s is offline, reason: NFS ' 'server %s is unreachable.',
name,
source['addr'],
)
# Mark state as '4' => inaccessible.
info[0] = 4
# skip calculating volumes
nr_volumes = 0
else:
nr_volumes = self._get_storagepool_vols_num(pool)
res = {
'state': POOL_STATE_MAP[info[0]],
'path': path,
'source': source,
'type': pool_type,
'autostart': autostart,
'capacity': info[1],
'allocated': info[2],
'available': info[3],
'nr_volumes': nr_volumes,
'persistent': persistent,
'in_use': self._pool_used_by_template(name),
}
if not pool.isPersistent():
# Deal with deep scan generated pool
try:
with self.objstore as session:
task_id = session.get('scanning', name)
res['task_id'] = str(task_id)
res['type'] = 'kimchi-iso'
except NotFoundError:
# User created normal pool
pass
return res
def _update_lvm_disks(self, pool_name, disks):
# check if all the disks/partitions exists in the host
for disk in disks:
lsblk_cmd = ['lsblk', disk]
output, error, returncode = run_command(lsblk_cmd)
if returncode != 0:
wok_log.error(
'%s is not a valid disk/partition. Could not '
'add it to the pool %s.',
disk,
pool_name,
)
raise OperationFailed(
'KCHPOOL0027E', {'disk': disk, 'pool': pool_name})
# add disks to the lvm pool using vgextend + virsh refresh
vgextend_cmd = ['vgextend', pool_name]
vgextend_cmd += disks
output, error, returncode = run_command(vgextend_cmd)
if returncode != 0:
msg = 'Could not add disks to pool %s, error: %s'
wok_log.error(msg, pool_name, error)
raise OperationFailed(
'KCHPOOL0028E', {'pool': pool_name, 'err': error})
# refreshing pool state
pool = self.get_storagepool(pool_name, self.conn)
if pool.isActive():
pool.refresh(0)
def update(self, name, params):
pool = self.get_storagepool(name, self.conn)
if 'autostart' in params:
if params['autostart']:
pool.setAutostart(1)
else:
pool.setAutostart(0)
if 'disks' in params:
# check if pool is type 'logical'
xml = pool.XMLDesc(0)
pool_type = xpath_get_text(xml, '/pool/@type')[0]
if pool_type != 'logical':
raise InvalidOperation('KCHPOOL0029E')
self._update_lvm_disks(name, params['disks'])
ident = pool.name()
return ident
def activate(self, name):
pool = self.get_storagepool(name, self.conn)
# FIXME: nfs workaround - do not activate a NFS pool
# if the NFS server is not reachable.
xml = pool.XMLDesc(0)
pool_type = xpath_get_text(xml, '/pool/@type')[0]
if pool_type == 'netfs' and not self._nfs_status_online(pool):
# block the user from activating the pool.
source = self._get_storage_source(pool_type, xml)
raise OperationFailed(
'KCHPOOL0032E', {'name': name, 'server': source['addr']}
)
try:
pool.create(0)
except libvirt.libvirtError as e:
raise OperationFailed(
'KCHPOOL0009E', {'name': name, 'err': e.get_error_message()}
)
def _pool_used_by_template(self, pool_name):
with self.objstore as session:
templates = session.get_list('template')
for tmpl in templates:
t_info = session.get('template', tmpl)
for disk in t_info['disks']:
if 'pool' in disk:
t_pool = disk['pool']['name']
if pool_name_from_uri(t_pool) == pool_name:
return True
return False
def deactivate(self, name):
if self._pool_used_by_template(name):
raise InvalidOperation('KCHPOOL0034E', {'name': name})
pool = self.get_storagepool(name, self.conn)
# FIXME: nfs workaround - do not try to deactivate a NFS pool
# if the NFS server is not reachable.
xml = pool.XMLDesc(0)
pool_type = xpath_get_text(xml, '/pool/@type')[0]
if pool_type == 'netfs' and not self._nfs_status_online(pool):
# block the user from dactivating the pool.
source = self._get_storage_source(pool_type, xml)
raise OperationFailed(
'KCHPOOL0033E', {'name': name, 'server': source['addr']}
)
try:
persistent = pool.isPersistent()
pool.destroy()
except libvirt.libvirtError as e:
raise OperationFailed(
'KCHPOOL0010E', {'name': name, 'err': e.get_error_message()}
)
# If pool was not persistent, then it was erased by destroy() and
# must return nothing here, to trigger _redirect() and avoid errors
if not persistent:
return ''
def delete(self, name):
if self._pool_used_by_template(name):
raise InvalidOperation('KCHPOOL0035E', {'name': name})
pool = self.get_storagepool(name, self.conn)
if pool.isActive():
raise InvalidOperation('KCHPOOL0005E', {'name': name})
vms = self._get_vms_attach_to_storagepool(name)
if len(vms) > 0:
raise InvalidOperation(
'KCHPOOL0039E', {'name': name, 'vms': ','.join(vms)})
try:
pool.undefine()
except libvirt.libvirtError as e:
raise OperationFailed(
'KCHPOOL0011E', {'name': name, 'err': e.get_error_message()}
)
def _get_vms_attach_to_storagepool(self, storagepool):
conn = self.conn.get()
# get storage pool path
pool = self.get_storagepool(storagepool, self.conn)
path = ''.join(xpath_get_text(pool.XMLDesc(), '/pool/target/path'))
# activate and deactive quickly to get volumes
vms = []
for dom in conn.listAllDomains(0):
xml = dom.XMLDesc(0)
files = "/domain/devices/disk[@device='disk']/source/@file"
for file in xpath_get_text(xml, files):
if file not in vms and file.startswith(path):
vms.append(dom.name())
return vms
class IsoPoolModel(object):
def __init__(self, **kargs):
pass
def lookup(self, name):
return {'state': 'active', 'type': 'kimchi-iso'}
================================================
FILE: model/storageservers.py
================================================
#
# Project Kimchi
#
# Copyright IBM Corp, 2015-2016
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
from wok.exception import NotFoundError
from wok.plugins.kimchi.model.storagepools import StoragePoolModel
from wok.plugins.kimchi.model.storagepools import StoragePoolsModel
# Types of remote storage servers supported
STORAGE_SERVERS = ['netfs', 'iscsi']
class StorageServersModel(object):
def __init__(self, **kargs):
self.conn = kargs['conn']
self.pool = StoragePoolModel(**kargs)
self.pools = StoragePoolsModel(**kargs)
def get_list(self, _target_type=None):
if not _target_type:
target_type = STORAGE_SERVERS
else:
target_type = [_target_type]
pools = self.pools.get_list()
server_list = []
for pool in pools:
try:
pool_info = self.pool.lookup(pool)
if (pool_info['type'] in target_type
and pool_info['source']['addr'] not in server_list):
# Avoid to add same server for multiple times
# if it hosts more than one storage type
server_list.append(pool_info['source']['addr'])
except NotFoundError:
pass
return server_list
class StorageServerModel(object):
def __init__(self, **kargs):
self.conn = kargs['conn']
self.pool = StoragePoolModel(**kargs)
def lookup(self, server):
conn = self.conn.get()
pools = conn.listStoragePools()
pools += conn.listDefinedStoragePools()
for pool in pools:
try:
pool_info = self.pool.lookup(pool)
if (pool_info['type'] in STORAGE_SERVERS
and pool_info['source']['addr'] == server):
info = dict(host=server)
if (pool_info['type'] == 'iscsi'
and 'port' in pool_info['source']):
info['port'] = pool_info['source']['port']
return info
except NotFoundError:
# Avoid inconsistent pool result because of lease between list
# lookup
pass
raise NotFoundError('KCHSR0001E', {'server': server})
================================================
FILE: model/storagetargets.py
================================================
#
# Project Kimchi
#
# Copyright IBM Corp, 2015-2016
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
import libvirt
import lxml.etree as ET
from lxml import objectify
from lxml.builder import E
from wok.plugins.kimchi.model.config import CapabilitiesModel
from wok.plugins.kimchi.model.storageservers import STORAGE_SERVERS
from wok.utils import patch_find_nfs_target
from wok.utils import wok_log
class StorageTargetsModel(object):
def __init__(self, **kargs):
self.conn = kargs['conn']
self.caps = CapabilitiesModel(**kargs)
def get_list(self, storage_server, _target_type=None, _server_port=None):
target_list = list()
if not _target_type:
target_types = STORAGE_SERVERS
else:
target_types = [_target_type]
for target_type in target_types:
if not self.caps.nfs_target_probe and target_type == 'netfs':
targets = patch_find_nfs_target(storage_server)
else:
xml = self._get_storage_server_spec(
server=storage_server,
target_type=target_type,
server_port=_server_port,
)
conn = self.conn.get()
try:
ret = conn.findStoragePoolSources(target_type, xml, 0)
except libvirt.libvirtError as e:
wok_log.warning(
f'Query storage pool source fails because of '
f'{e.get_error_message()}'
)
continue
targets = self._parse_target_source_result(target_type, ret)
target_list.extend(targets)
# Get all netfs and iscsi paths in use
used_paths = []
try:
conn = self.conn.get()
# Get all existing ISCSI and NFS pools
pools = conn.listAllStoragePools(
libvirt.VIR_CONNECT_LIST_STORAGE_POOLS_ISCSI |
libvirt.VIR_CONNECT_LIST_STORAGE_POOLS_NETFS
)
for pool in pools:
pool_xml = pool.XMLDesc(0)
root = objectify.fromstring(pool_xml)
if root.get('type') == 'netfs' and root.source.dir is not None:
used_paths.append(root.source.dir.get('path'))
elif root.get('type') == 'iscsi' and root.source.device is not None:
used_paths.append(root.source.device.get('path'))
except libvirt.libvirtError as e:
wok_log.warning(
f'Query storage pool source fails because of {e.get_error_message()}'
)
# Filter target_list to not not show the used paths
target_list = [
elem for elem in target_list if elem.get('target') not in used_paths
]
return [dict(t) for t in set(tuple(t.items()) for t in target_list)]
def _get_storage_server_spec(self, **kwargs):
# Required parameters:
# server:
# target_type:
extra_args = []
server_type = kwargs['target_type']
if server_type == 'netfs':
extra_args.append(E.format(type='nfs'))
else:
extra_args.append(E.format(type=server_type))
host_attr = {'name': kwargs['server']}
server_port = kwargs.get('server_port')
if server_port is not None:
host_attr['port'] = server_port
obj = E.source(E.host(host_attr), *extra_args)
xml = ET.tostring(obj, encoding='unicode')
return xml
def _parse_target_source_result(self, target_type, xml_str):
root = objectify.fromstring(xml_str)
ret = []
for source in root.getchildren():
if target_type == 'netfs':
target_path = source.dir.get('path')
type = source.format.get('type')
if target_type == 'iscsi':
target_path = source.device.get('path')
type = target_type
host_name = source.host.get('name')
ret.append(
dict(host=host_name, target_type=type, target=target_path))
return ret
================================================
FILE: model/storagevolumes.py
================================================
#
# Project Kimchi
#
# Copyright IBM Corp, 2015-2016
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
import contextlib
import os
import tempfile
import threading
import time
import urllib
import libvirt
import lxml.etree as ET
import magic
from lxml.builder import E
from wok.asynctask import AsyncTask
from wok.exception import InvalidOperation
from wok.exception import InvalidParameter
from wok.exception import IsoFormatError
from wok.exception import MissingParameter
from wok.exception import NotFoundError
from wok.exception import OperationFailed
from wok.model.tasks import TaskModel
from wok.plugins.kimchi.config import READONLY_POOL_TYPE
from wok.plugins.kimchi.isoinfo import IsoImage
from wok.plugins.kimchi.kvmusertests import UserTests
from wok.plugins.kimchi.model.diskutils import get_disk_used_by
from wok.plugins.kimchi.model.storagepools import StoragePoolModel
from wok.plugins.kimchi.utils import get_next_clone_name
from wok.utils import get_unique_file_name
from wok.utils import probe_file_permission_as_user
from wok.utils import wok_log
from wok.xmlutils.utils import xpath_get_text
VOLUME_TYPE_MAP = {0: 'file', 1: 'block', 2: 'directory', 3: 'network'}
READ_CHUNK_SIZE = 1048576 # 1 MiB
REQUIRE_NAME_PARAMS = ['capacity']
VALID_RAW_CONTENT = ['dos/mbr boot sector', 'x86 boot sector', 'data']
upload_volumes = dict()
class StorageVolumesModel(object):
def __init__(self, **kargs):
self.conn = kargs['conn']
self.objstore = kargs['objstore']
self.task = TaskModel(**kargs)
def create(self, pool_name, params):
vol_source = ['url', 'capacity']
name = params.get('name')
index_list = list(i for i in range(len(vol_source))
if vol_source[i] in params)
if len(index_list) != 1:
raise InvalidParameter(
'KCHVOL0018E', {'param': ','.join(vol_source)})
create_param = vol_source[index_list[0]]
# Verify if the URL is valid
if create_param == 'url':
url = params['url']
try:
urllib.request.urlopen(url).close()
except Exception:
raise InvalidParameter('KCHVOL0022E', {'url': url})
all_vol_names = self.get_list(pool_name)
if name is None:
# the methods listed in 'REQUIRE_NAME_PARAMS' cannot have
# 'name' == None
if create_param in REQUIRE_NAME_PARAMS:
raise InvalidParameter('KCHVOL0016E')
# if 'name' is omitted - except for the methods listed in
# 'REQUIRE_NAME_PARAMS' - the default volume name will be the
# file/URL basename.
if create_param == 'url':
name = os.path.basename(params['url'])
else:
name = f'upload-{int(time.time())}'
name = get_unique_file_name(all_vol_names, name)
params['name'] = name
try:
create_func = getattr(self, f'_create_volume_with_{create_param}')
except AttributeError:
raise InvalidParameter('KCHVOL0019E', {'param': create_param})
pool_info = StoragePoolModel(conn=self.conn, objstore=self.objstore).lookup(
pool_name
)
if pool_info['type'] in READONLY_POOL_TYPE:
raise InvalidParameter('KCHVOL0012E', {'type': pool_info['type']})
if pool_info['state'] == 'inactive':
raise InvalidParameter(
'KCHVOL0003E', {'pool': pool_name, 'volume': name})
if name in all_vol_names:
raise InvalidParameter('KCHVOL0001E', {'name': name})
params['pool'] = pool_name
params['pool_type'] = pool_info['type']
targeturi = '/plugins/kimchi/storagepools/%s/storagevolumes/%s' % (
pool_name,
name,
)
taskid = AsyncTask(targeturi, create_func, params).id
return self.task.lookup(taskid)
def _create_volume_with_capacity(self, cb, params):
pool_name = params.pop('pool')
vol_xml = """
%(name)s%(allocation)s%(capacity)s
"""
allocation = 0
if params['pool_type'] == 'logical':
allocation = params['capacity']
params.setdefault('allocation', allocation)
params.setdefault('format', 'qcow2')
name = params['name']
try:
pool = StoragePoolModel.get_storagepool(pool_name, self.conn)
xml = vol_xml % params
except KeyError as item:
raise MissingParameter(
'KCHVOL0004E', {'item': str(item), 'volume': name})
try:
pool.createXML(xml, 0)
except libvirt.libvirtError as e:
raise OperationFailed(
'KCHVOL0007E',
{'name': name, 'pool': pool_name, 'err': e.get_error_message()},
)
vol_info = StorageVolumeModel(conn=self.conn, objstore=self.objstore).lookup(
pool_name, name
)
vol_path = vol_info['path']
if params.get('upload', False):
upload_volumes[vol_path] = {
'lock': threading.Lock(),
'offset': 0,
'cb': cb,
'expected_vol_size': params['capacity'],
}
cb('ready for upload')
else:
cb('OK', True)
def _create_volume_with_url(self, cb, params):
pool_name = params['pool']
name = params['name']
url = params['url']
pool_model = StoragePoolModel(conn=self.conn, objstore=self.objstore)
pool = pool_model.lookup(pool_name)
if pool['type'] in ['dir', 'netfs']:
file_path = os.path.join(pool['path'], name)
else:
file_path = tempfile.mkstemp(prefix=name)[1]
with contextlib.closing(urllib.request.urlopen(url)) as response:
with open(file_path, 'w') as volume_file:
remote_size = response.getheader('Content-Length', '-')
downloaded_size = 0
try:
while True:
chunk_data = response.read(
READ_CHUNK_SIZE).decode('utf-8')
if not chunk_data:
break
volume_file.write(chunk_data)
downloaded_size += len(chunk_data)
cb(f'{downloaded_size}/{remote_size}')
except (IOError, libvirt.libvirtError) as e:
if os.path.isfile(file_path):
os.remove(file_path)
raise OperationFailed(
'KCHVOL0007E', {'name': name,
'pool': pool_name, 'err': str(e)}
)
if pool['type'] in ['dir', 'netfs']:
virt_pool = StoragePoolModel.get_storagepool(pool_name, self.conn)
virt_pool.refresh(0)
else:
def _stream_handler(stream, nbytes, fd):
return fd.read(nbytes)
virt_stream = virt_vol = None
try:
task = self.create(
pool_name,
{
'name': name,
'format': 'raw',
'capacity': downloaded_size,
'allocation': downloaded_size,
},
)
self.task.wait(task['id'])
virt_vol = StorageVolumeModel.get_storagevolume(
pool_name, name, self.conn
)
virt_stream = self.conn.get().newStream(0)
virt_vol.upload(virt_stream, 0, downloaded_size, 0)
with open(file_path) as fd:
virt_stream.sendAll(_stream_handler, fd)
virt_stream.finish()
except (IOError, libvirt.libvirtError) as e:
try:
if virt_stream:
virt_stream.abort()
if virt_vol:
virt_vol.delete(0)
except libvirt.libvirtError as e:
wok_log.error(str(e))
finally:
raise OperationFailed(
'KCHVOL0007E', {'name': name,
'pool': pool_name, 'err': str(e)}
)
finally:
os.remove(file_path)
cb('OK', True)
def get_list(self, pool_name):
pool = StoragePoolModel.get_storagepool(pool_name, self.conn)
if not pool.isActive():
raise InvalidOperation('KCHVOL0006E', {'pool': pool_name})
try:
pool.refresh(0)
except Exception as e:
wok_log.error(f'Pool refresh failed: {e}')
return sorted(pool.listVolumes())
class StorageVolumeModel(object):
def __init__(self, **kargs):
self.conn = kargs['conn']
self.objstore = kargs['objstore']
self.task = TaskModel(**kargs)
self.storagevolumes = StorageVolumesModel(**kargs)
self.storagepool = StoragePoolModel(**kargs)
if self.conn.get() is not None:
self.libvirt_user = UserTests().probe_user()
else:
self.libvirt_user = None
@staticmethod
def get_storagevolume(poolname, name, conn):
pool = StoragePoolModel.get_storagepool(poolname, conn)
if not pool.isActive():
raise InvalidOperation('KCHVOL0006E', {'pool': poolname})
try:
return pool.storageVolLookupByName(name)
except libvirt.libvirtError as e:
if e.get_error_code() == libvirt.VIR_ERR_NO_STORAGE_VOL:
raise NotFoundError(
'KCHVOL0002E', {'name': name, 'pool': poolname})
else:
raise
def lookup(self, pool, name):
vol = StorageVolumeModel.get_storagevolume(pool, name, self.conn)
path = vol.path()
info = vol.info()
xml = vol.XMLDesc(0)
try:
fmt = xpath_get_text(xml, '/volume/target/format/@type')[0]
except IndexError:
# Not all types of libvirt storage can provide volume format
# infomation. When there is no format information, we assume
# it's 'raw'.
fmt = 'raw'
iso_img = None
# 'raw' volumes from 'logical' pools may actually be 'iso';
# libvirt always reports them as 'raw'
pool_info = self.storagepool.lookup(pool)
if pool_info['type'] == 'logical' and fmt == 'raw':
try:
iso_img = IsoImage(path)
except IsoFormatError:
# not 'iso' afterall
pass
else:
fmt = 'iso'
# 'raw' volumes can not be valid image disks (e.g. XML, PDF, TXT are
# raw files), so it's necessary check the 'content' of them
isvalid = True
if fmt == 'raw':
# Check if file is a symlink to a real block device,
# if so, don't check it's contents for validity
if not os.path.islink(path):
try:
ms = magic.open(magic.NONE)
ms.load()
if ms.file(path).lower() not in VALID_RAW_CONTENT:
isvalid = False
ms.close()
except UnicodeDecodeError:
isvalid = False
else: # We are a symlink
if '/dev/dm-' in os.path.realpath(path):
# This is most likely a real blockdevice
isvalid = True
wok_log.error('symlink detected, validated the disk')
else:
# Doesn't point to a known blockdevice
isvalid = False
used_by = get_disk_used_by(self.conn, path)
if self.libvirt_user is None:
self.libvirt_user = UserTests().probe_user()
ret, _ = probe_file_permission_as_user(
os.path.realpath(path), self.libvirt_user
)
res = dict(
type=VOLUME_TYPE_MAP[info[0]],
capacity=info[1],
allocation=info[2],
path=path,
used_by=used_by,
format=fmt,
isvalid=isvalid,
has_permission=ret,
)
if fmt == 'iso':
if os.path.islink(path):
path = os.path.join(os.path.dirname(path), os.readlink(path))
os_distro = os_version = 'unknown'
try:
if iso_img is None:
iso_img = IsoImage(path)
os_distro, os_version = iso_img.probe()
bootable = True
except IsoFormatError:
bootable = False
res.update(
dict(
os_distro=os_distro,
os_version=os_version,
path=path,
bootable=bootable,
)
)
return res
def wipe(self, pool, name):
volume = StorageVolumeModel.get_storagevolume(pool, name, self.conn)
try:
volume.wipePattern(libvirt.VIR_STORAGE_VOL_WIPE_ALG_ZERO, 0)
except libvirt.libvirtError as e:
raise OperationFailed(
'KCHVOL0009E', {'name': name, 'err': e.get_error_message()}
)
def delete(self, pool, name):
pool_info = StoragePoolModel(conn=self.conn, objstore=self.objstore).lookup(
pool
)
if pool_info['type'] in READONLY_POOL_TYPE:
raise InvalidParameter('KCHVOL0012E', {'type': pool_info['type']})
volume = StorageVolumeModel.get_storagevolume(pool, name, self.conn)
vol_path = volume.path()
try:
volume.delete(0)
except libvirt.libvirtError as e:
raise OperationFailed(
'KCHVOL0010E', {'name': name, 'err': e.get_error_message()}
)
try:
os.remove(vol_path)
except OSError as e:
wok_log.error(
f"Unable to delete storage volume file: {pool_info['path']}."
f'Details: {e}'
)
def resize(self, pool, name, size):
volume = StorageVolumeModel.get_storagevolume(pool, name, self.conn)
# When decreasing the storage volume capacity, the flag
# VIR_STORAGE_VOL_RESIZE_SHRINK must be used
flags = 0
if volume.info()[1] > size:
# FIXME: Even using VIR_STORAGE_VOL_RESIZE_SHRINK flag it is not
# possible to decrease the volume capacity due a libvirt bug
# For reference:
# - https://bugzilla.redhat.com/show_bug.cgi?id=1021802
flags = libvirt.VIR_STORAGE_VOL_RESIZE_SHRINK
try:
volume.resize(size, flags)
except libvirt.libvirtError as e:
raise OperationFailed(
'KCHVOL0011E', {'name': name, 'err': e.get_error_message()}
)
def clone(self, pool, name, new_pool=None, new_name=None):
"""Clone a storage volume.
Arguments:
pool -- The name of the original pool.
name -- The name of the original volume.
new_pool -- The name of the destination pool (optional). If omitted,
the new volume will be created on the same pool as the
original one.
new_name -- The name of the new volume (optional). If omitted, a new
value based on the original volume's name will be used.
Return:
A Task running the clone operation.
"""
# the same pool will be used if no pool is specified
if new_pool is None:
new_pool = pool
# a default name based on the original name will be used if no name
# is specified
if new_name is None:
base, ext = os.path.splitext(name)
new_name = get_next_clone_name(
self.storagevolumes.get_list(pool), base, ext
)
params = {
'pool': pool,
'name': name,
'new_pool': new_pool,
'new_name': new_name,
}
target_uri = '/plugins/kimchi/storagepools/%s/storagevolumes/%s/clone'
taskid = AsyncTask(target_uri % (pool, new_name),
self._clone_task, params).id
return self.task.lookup(taskid)
def _clone_task(self, cb, params):
"""Asynchronous function which performs the clone operation.
This function copies all the data inside the original volume into the
new one.
Arguments:
cb -- A callback function to signal the Task's progress.
params -- A dict with the following values:
"pool": The name of the original pool.
"name": The name of the original volume.
"new_pool": The name of the destination pool.
"new_name": The name of the new volume.
"""
orig_pool_name = params['pool']
orig_vol_name = params['name']
new_pool_name = params['new_pool']
new_vol_name = params['new_name']
try:
cb('setting up volume cloning')
orig_vir_vol = StorageVolumeModel.get_storagevolume(
orig_pool_name, orig_vol_name, self.conn
)
orig_vol = self.lookup(orig_pool_name, orig_vol_name)
new_vir_pool = StoragePoolModel.get_storagepool(
new_pool_name, self.conn)
cb('building volume XML')
root_elem = E.volume()
root_elem.append(E.name(new_vol_name))
root_elem.append(E.capacity(
str(orig_vol['capacity']), unit='bytes'))
target_elem = E.target()
target_elem.append(E.format(type=orig_vol['format']))
root_elem.append(target_elem)
new_vol_xml = ET.tostring(
root_elem, encoding='unicode', pretty_print=True
)
cb('cloning volume')
new_vir_pool.createXMLFrom(new_vol_xml, orig_vir_vol, 0)
except (InvalidOperation, NotFoundError, libvirt.libvirtError) as e:
raise OperationFailed(
'KCHVOL0023E',
{
'name': orig_vol_name,
'pool': orig_pool_name,
'err': e.get_error_message(),
},
)
self.lookup(new_pool_name, new_vol_name)
cb('OK', True)
def doUpload(self, cb, vol, offset, data, data_size):
try:
st = self.conn.get().newStream(0)
vol.upload(st, offset, data_size)
st.send(data.encode('utf-8'))
st.finish()
except Exception as e:
st and st.abort()
cb('', False)
try:
vol.delete(0)
except Exception:
pass
raise OperationFailed('KCHVOL0029E', {'err': str(e)})
def update(self, pool, name, params):
chunk_data = params['chunk'].fullvalue()
chunk_size = int(params['chunk_size'])
if len(chunk_data) != chunk_size:
raise OperationFailed('KCHVOL0026E')
vol = StorageVolumeModel.get_storagevolume(pool, name, self.conn)
vol_path = vol.path()
vol_capacity = vol.info()[1]
vol_data = upload_volumes.get(vol_path)
if vol_data is None:
raise OperationFailed('KCHVOL0027E', {'vol': vol_path})
cb = vol_data['cb']
lock = vol_data['lock']
with lock:
offset = vol_data['offset']
if (offset + chunk_size) > vol_capacity:
raise OperationFailed('KCHVOL0028E')
cb(f'{offset}/{vol_capacity}')
self.doUpload(cb, vol, offset, chunk_data, chunk_size)
cb(f'{offset + chunk_size}/{vol_capacity}')
vol_data['offset'] += chunk_size
if (vol_data['offset'] == vol_capacity) or (
vol_data['offset'] == vol_data['expected_vol_size']
):
del upload_volumes[vol_path]
cb('OK', True)
class IsoVolumesModel(object):
def __init__(self, **kargs):
self.conn = kargs['conn']
self.storagevolume = StorageVolumeModel(**kargs)
def get_list(self):
iso_volumes = []
conn = self.conn.get()
pools = conn.listStoragePools()
pools += conn.listDefinedStoragePools()
for pool_name in pools:
try:
pool = StoragePoolModel.get_storagepool(pool_name, self.conn)
pool.refresh(0)
volumes = pool.listVolumes()
except Exception as e:
# Skip inactive pools
wok_log.debug(
f'Shallow scan: skipping pool {pool_name} because of ' f'error: {e}'
)
continue
for volume in volumes:
res = self.storagevolume.lookup(pool_name, volume)
if res['format'] == 'iso' and res['bootable']:
res['name'] = f'{volume}'
iso_volumes.append(res)
return iso_volumes
================================================
FILE: model/templates.py
================================================
#
# Project Kimchi
#
# Copyright IBM Corp, 2015-2016
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
import copy
import os
import platform
import stat
import urllib.parse
import libvirt
import magic
import psutil
from wok.exception import InvalidOperation
from wok.exception import InvalidParameter
from wok.exception import NotFoundError
from wok.exception import OperationFailed
from wok.plugins.kimchi.config import get_kimchi_version
from wok.plugins.kimchi.kvmusertests import UserTests
from wok.plugins.kimchi.model.cpuinfo import CPUInfoModel
from wok.plugins.kimchi.utils import create_disk_image
from wok.plugins.kimchi.utils import is_libvirtd_up
from wok.plugins.kimchi.utils import pool_name_from_uri
from wok.plugins.kimchi.vmtemplate import VMTemplate
from wok.utils import probe_file_permission_as_user
from wok.utils import run_setfacl_set_attr
from wok.xmlutils.utils import xpath_get_text
ISO_TYPE = ['DOS/MBR', 'ISO 9660 CD-ROM']
# In PowerPC, memories must be aligned to 256 MiB
PPC_MEM_ALIGN = 256
# Max memory 16TB for PPC and 4TiB for X (according to Red Hat), in KiB
MAX_MEM_LIM = 4294967296 # 4 TiB
if os.uname()[4] in ['ppc', 'ppc64', 'ppc64le']:
MAX_MEM_LIM *= 4 # 16TiB
class TemplatesModel(object):
def __init__(self, **kargs):
self.objstore = kargs['objstore']
self.conn = kargs['conn']
def create(self, params):
name = params.get('name', '').strip()
conn = self.conn.get()
for net_name in params.get(u'networks', []):
try:
conn.networkLookupByName(net_name)
except Exception:
raise InvalidParameter(
'KCHTMPL0003E', {'network': net_name, 'template': name}
)
# Valid interfaces
interfaces = params.get('interfaces', [])
validate_interfaces(interfaces)
if os.uname()[4] not in ['s390x', 's390'] and 'console' in params:
raise InvalidParameter('KCHTMPL0043E')
# get source_media
source_media = params.pop('source_media')
if source_media['type'] == 'netboot':
params['netboot'] = True
return self.save_template(params)
# Get path of source media if it's based on disk type.
path = source_media.get('path', None)
if path is None:
raise InvalidParameter('KCHTMPL0016E')
# not local image: set as remote ISO
if urllib.parse.urlparse(path).scheme in [
'http',
'https',
'tftp',
'ftp',
'ftps',
]:
params['cdrom'] = path
return self.save_template(params)
# Local file (ISO/Img) does not exist: raise error
if not os.path.exists(path):
raise InvalidParameter('KCHTMPL0002E', {'path': path})
# create magic object to discover file type
file_type = magic.open(magic.MAGIC_NONE)
file_type.load()
ftype = file_type.file(path)
# cdrom
iscdrom = [t for t in ISO_TYPE if t in ftype]
if iscdrom:
params['cdrom'] = path
# check search permission
st_mode = os.stat(path).st_mode
if stat.S_ISREG(st_mode) or stat.S_ISBLK(st_mode):
user = UserTests().probe_user()
realpath = os.path.realpath(path)
run_setfacl_set_attr(realpath, user=user)
ret, excp = probe_file_permission_as_user(realpath, user)
if ret is False:
raise InvalidParameter(
'KCHISO0008E', {'filename': path,
'user': user, 'err': excp}
)
# disk
else:
params['disks'] = params.get('disks', [])
params['disks'].append({'base': path})
return self.save_template(params)
def save_template(self, params):
# Creates the template class with necessary information
t = LibvirtVMTemplate(params, scan=True, conn=self.conn)
# Validate cpu info
t.cpuinfo_validate()
# Validate memory
t._validate_memory()
# Validate volumes
for disk in t.info.get('disks'):
volume = disk.get('volume')
# volume can be None
if 'volume' in disk.keys():
self.template_volume_validate(volume, disk['pool'])
# template with the same name already exists: raise exception
name = params['name']
with self.objstore as session:
if name in session.get_list('template'):
raise InvalidOperation('KCHTMPL0001E', {'name': name})
# Store template on objectstore
try:
with self.objstore as session:
session.store('template', name, t.info, get_kimchi_version())
except InvalidOperation:
raise
except Exception as e:
raise OperationFailed('KCHTMPL0020E', {'err': str(e)})
return name
def get_list(self):
if not is_libvirtd_up():
return []
with self.objstore as session:
return session.get_list('template')
def template_volume_validate(self, volume, pool):
kwargs = {'conn': self.conn, 'objstore': self.objstore}
pool_name = pool_name_from_uri(pool['name'])
if pool['type'] in ['iscsi', 'scsi']:
if not volume:
raise InvalidParameter('KCHTMPL0018E')
storagevolumes = __import__(
'wok.plugins.kimchi.model.storagevolumes', fromlist=['']
)
pool_volumes = storagevolumes.StorageVolumesModel(**kwargs).get_list(
pool_name
)
if volume not in pool_volumes:
raise InvalidParameter(
'KCHTMPL0019E', {'pool': pool_name, 'volume': volume}
)
class TemplateModel(object):
def __init__(self, **kargs):
self.objstore = kargs['objstore']
self.conn = kargs['conn']
self.templates = TemplatesModel(**kargs)
@staticmethod
def get_template(name, objstore, conn, overrides=None):
if overrides is None:
overrides = {}
with objstore as session:
params = session.get('template', name)
if overrides and 'storagepool' in overrides:
for i, disk in enumerate(params['disks']):
params['disks'][i]['pool']['name'] = overrides['storagepool']
del overrides['storagepool']
params.update(overrides)
return LibvirtVMTemplate(params, False, conn)
def lookup(self, name):
t = self.get_template(name, self.objstore, self.conn)
return t.validate_integrity()
def clone(self, name):
# set default name
subfixs = [
v[len(name):] for v in self.templates.get_list() if v.startswith(name)
]
indexs = [
int(v.lstrip('-clone'))
for v in subfixs
if v.startswith('-clone') and v.lstrip('-clone').isdigit()
]
indexs.sort()
index = '1' if not indexs else str(indexs[-1] + 1)
clone_name = name + '-clone' + index
temp = self.lookup(name)
temp['name'] = clone_name
ident = self.templates.save_template(temp)
return ident
def delete(self, name):
try:
with self.objstore as session:
session.delete('template', name)
except NotFoundError:
raise
except Exception as e:
raise OperationFailed('KCHTMPL0021E', {'err': str(e)})
def update(self, name, params):
edit_template = self.lookup(name)
# If new name is not same as existing name
# and new name already exists: raise exception
with self.objstore as session:
if (
'name' in params
and name != params['name']
and params['name'] in session.get_list('template')
):
raise InvalidOperation(
'KCHTMPL0001E', {'name': params['name']})
# Valid interfaces
interfaces = params.get('interfaces', [])
validate_interfaces(interfaces)
if os.uname()[4] not in ['s390x', 's390'] and 'console' in params:
raise InvalidParameter('KCHTMPL0043E')
# Merge graphics settings
graph_args = params.get('graphics')
if graph_args:
graphics = dict(edit_template['graphics'])
graphics.update(graph_args)
params['graphics'] = graphics
# Merge cpu_info settings
new_cpu_info = params.get('cpu_info')
if new_cpu_info:
cpu_info = dict(edit_template['cpu_info'])
cpu_info.update(new_cpu_info)
params['cpu_info'] = cpu_info
# Fix memory values, because method update does not work recursively
new_mem = params.get('memory')
if new_mem is not None:
params['memory'] = copy.copy(edit_template.get('memory'))
params['memory'].update(new_mem)
validate_memory(params['memory'])
edit_template.update(params)
for net_name in params.get(u'networks', []):
try:
conn = self.conn.get()
conn.networkLookupByName(net_name)
except Exception:
raise InvalidParameter(
'KCHTMPL0003E', {'network': net_name, 'template': name}
)
try:
# make sure the new template will be created
t = LibvirtVMTemplate(edit_template, scan=True, conn=self.conn)
t.cpuinfo_validate()
t._validate_memory()
# remove the current one
self.delete(name)
# save the template
return self.templates.save_template(edit_template)
except InvalidOperation:
raise
except Exception as e:
raise OperationFailed('KCHTMPL0032E', {'err': str(e)})
return params['name']
def validate_interfaces(interfaces):
#
# Interfaces only supported on s390x or s390 architecture.
# Otherwise FIXME to valid interfaces exist on system.
#
if os.uname()[4] not in ['s390x', 's390'] and interfaces:
raise InvalidParameter('KCHTMPL0039E')
# FIXME to valid interfaces on system.
def validate_memory(memory):
#
# All checking are made in Mib, so, expects memory values in Mib
#
current = memory.get('current')
maxmem = memory.get('maxmemory')
# Check Host Memory
if hasattr(psutil, 'virtual_memory'):
host_memory = psutil.virtual_memory().total >> 10 >> 10
else:
host_memory = psutil.TOTAL_PHYMEM >> 10 >> 10
# Memories must be lesser than 16TiB (PPC) or 4TiB (x86) and the Host
# memory limit
if (current > (MAX_MEM_LIM >> 10)) or (maxmem > (MAX_MEM_LIM >> 10)):
raise InvalidParameter(
'KCHVM0079E', {'value': str(MAX_MEM_LIM / (1024 ** 3))})
if (current > host_memory) or (maxmem > host_memory):
raise InvalidParameter('KCHVM0078E', {'memHost': host_memory})
# Current memory cannot be greater than maxMemory
if current > maxmem:
raise InvalidParameter(
'KCHTMPL0031E', {'mem': str(current), 'maxmem': str(maxmem)}
)
# make sure memory and Maxmemory are alingned in 256MiB in PowerPC
if platform.machine().startswith('ppc'):
if current % PPC_MEM_ALIGN != 0:
raise InvalidParameter(
'KCHVM0071E',
{
'param': 'Memory',
'mem': str(current),
'alignment': str(PPC_MEM_ALIGN),
},
)
elif maxmem % PPC_MEM_ALIGN != 0:
raise InvalidParameter(
'KCHVM0071E',
{
'param': 'Maximum Memory',
'mem': str(maxmem),
'alignment': str(PPC_MEM_ALIGN),
},
)
class LibvirtVMTemplate(VMTemplate):
def __init__(self, args, scan=False, conn=None):
self.conn = conn
netboot = True if 'netboot' in args.keys() else False
VMTemplate.__init__(self, args, scan, netboot)
self.set_cpu_info()
def _validate_memory(self):
validate_memory(self.info['memory'])
def cpuinfo_validate(self):
cpu_model = CPUInfoModel(conn=self.conn)
# validate CPU info values - will raise appropriate exceptions
cpu_model.check_cpu_info(self.info['cpu_info'])
def _get_storage_pool(self, pool_uri):
pool_name = pool_name_from_uri(pool_uri)
try:
conn = self.conn.get()
pool = conn.storagePoolLookupByName(pool_name)
except libvirt.libvirtError:
raise InvalidParameter(
'KCHTMPL0004E', {'pool': pool_uri, 'template': self.name}
)
return pool
def _get_all_networks_name(self):
conn = self.conn.get()
return sorted(conn.listNetworks() + conn.listDefinedNetworks())
def _get_all_storagepools_name(self):
conn = self.conn.get()
names = conn.listStoragePools() + conn.listDefinedStoragePools()
return sorted(map(lambda x: x.decode('utf-8'), names))
def _get_active_storagepools_name(self):
conn = self.conn.get()
names = conn.listStoragePools()
return sorted(names)
def _network_validate(self):
names = self.info.get('networks', [])
for name in names:
try:
conn = self.conn.get()
network = conn.networkLookupByName(name)
except libvirt.libvirtError:
raise InvalidParameter(
'KCHTMPL0003E', {'network': name, 'template': self.name}
)
if not network.isActive():
raise InvalidParameter(
'KCHTMPL0007E', {'network': name, 'template': self.name}
)
def _get_storage_path(self, pool_uri=None):
try:
pool = self._get_storage_pool(pool_uri)
except Exception:
return ''
xml = pool.XMLDesc(0)
return xpath_get_text(xml, '/pool/target/path')[0]
def _get_storage_type(self, pool_uri=None):
try:
pool = self._get_storage_pool(pool_uri)
except Exception:
return ''
xml = pool.XMLDesc(0)
return xpath_get_text(xml, '/pool/@type')[0]
def _get_volume_path(self, pool, vol):
pool = self._get_storage_pool(pool)
try:
return pool.storageVolLookupByName(vol).path()
except Exception:
raise NotFoundError('KCHVOL0002E', {'name': vol, 'pool': pool})
def fork_vm_storage(self, vm_uuid):
# Provision storages:
disk_and_vol_list = self.to_volume_list(vm_uuid)
try:
for v in disk_and_vol_list:
if v['pool'] is not None:
pool = self._get_storage_pool(v['pool'])
# outgoing text to libvirt, decode('utf-8')
pool.createXML(v['xml'].decode('utf-8'), 0)
else:
capacity = v['capacity']
format_type = v['format']
path = v['path']
create_disk_image(
format_type=format_type, path=path, capacity=capacity
)
except libvirt.libvirtError as e:
raise OperationFailed('KCHVMSTOR0008E', {'error': str(e)})
return disk_and_vol_list
def set_cpu_info(self):
# undefined topology: consider these values to calculate maxvcpus
sockets = 1
cores = 1
threads = 1
# get topology values
cpu_info = self.info.get('cpu_info', {})
topology = cpu_info.get('topology', {})
if topology:
sockets = topology['sockets']
cores = topology['cores']
threads = topology['threads']
# maxvcpus not specified: use defaults
if 'maxvcpus' not in cpu_info:
vcpus = cpu_info.get('vcpus')
if vcpus and not topology:
cpu_info['maxvcpus'] = vcpus
else:
cpu_info['maxvcpus'] = sockets * cores * threads
# current vcpus not specified: defaults is maxvcpus
if 'vcpus' not in cpu_info:
cpu_info['vcpus'] = cpu_info['maxvcpus']
# update cpu_info
self.info['cpu_info'] = cpu_info
================================================
FILE: model/users.py
================================================
#
# Project Kimchi
#
# Copyright IBM Corp, 2015-2016
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
import pwd
import ldap
from wok.config import config
from wok.exception import NotFoundError
class UsersModel(object):
def __init__(self, **args):
auth_type = config.get('authentication', 'method')
for klass in UsersModel.__subclasses__():
if auth_type == klass.auth_type:
self.user = klass(**args)
def get_list(self, **args):
return self.user._get_list(**args)
def validate(self, user):
return self.user._validate(user)
class PAMUsersModel(UsersModel):
auth_type = 'pam'
def __init__(self, **kargs):
pass
def _get_list(self):
return [user.pw_name for user in pwd.getpwall()
if user.pw_shell.rsplit('/')[-1] not in ['nologin', 'false']]
def _validate(self, user):
try:
return user in self._get_list()
except Exception:
return False
class LDAPUsersModel(UsersModel):
auth_type = 'ldap'
def __init__(self, **kargs):
pass
def _get_list(self, _user_id=''):
return self._get_user(_user_id)
def _validate(self, user):
try:
self._get_user(user)
return True
except NotFoundError:
return False
def _get_user(self, _user_id):
ldap_server = config.get('authentication', 'ldap_server').strip('"')
ldap_search_base = config.get(
'authentication', 'ldap_search_base').strip('"')
ldap_search_filter = config.get(
'authentication', 'ldap_search_filter',
vars={'username': _user_id.encode('utf-8')}).strip('"')
connect = ldap.open(ldap_server)
try:
result = connect.search_s(
ldap_search_base, ldap.SCOPE_SUBTREE, ldap_search_filter)
if len(result) == 0:
raise NotFoundError('KCHAUTH0004E', {'user_id': _user_id})
return result[0][1]
except ldap.NO_SUCH_OBJECT:
raise NotFoundError('KCHAUTH0004E', {'user_id': _user_id})
================================================
FILE: model/utils.py
================================================
#
# Project Kimchi
#
# Copyright IBM Corp, 2015-2016
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
import base64
import libvirt
from lxml import etree
from lxml.builder import E
from wok.exception import OperationFailed
KIMCHI_META_URL = 'https://github.com/kimchi-project/kimchi'
KIMCHI_NAMESPACE = 'kimchi'
def get_vm_name(vm_name, t_name, name_list):
if vm_name:
return vm_name
for i in range(1, 1000):
# VM will have templace name, but without slashes
vm_name = '%s-vm-%i' % (t_name.replace('/', '-'), i)
if vm_name not in name_list:
return vm_name
raise OperationFailed('KCHUTILS0003E')
def get_ascii_nonascii_name(name):
nonascii_name = None
if name.encode('ascii', 'ignore').decode('utf-8') != name:
nonascii_name = name
name = base64.urlsafe_b64encode(
nonascii_name.encode('utf-8')).decode('utf-8')
name = name.rstrip('=')
return name, nonascii_name
def get_vm_config_flag(dom, mode='persistent'):
# libvirt.VIR_DOMAIN_AFFECT_CURRENT is 0
# VIR_DOMAIN_AFFECT_LIVE is 1, VIR_DOMAIN_AFFECT_CONFIG is 2
flag = {
'live': libvirt.VIR_DOMAIN_AFFECT_LIVE,
'persistent': libvirt.VIR_DOMAIN_AFFECT_CONFIG,
'current': libvirt.VIR_DOMAIN_AFFECT_CURRENT,
'all': libvirt.VIR_DOMAIN_AFFECT_CONFIG + libvirt.VIR_DOMAIN_AFFECT_LIVE
if dom.isActive() and dom.isPersistent()
else libvirt.VIR_DOMAIN_AFFECT_CURRENT,
}
return flag[mode]
# avoid duplicate codes
def update_node(root, node):
old_node = root.find(node.tag)
(root.replace(old_node, node) if old_node is not None else root.append(node))
return root
def get_kimchi_metadata_node(dom, mode='current'):
if not metadata_exists(dom):
return None
try:
xml = dom.metadata(
libvirt.VIR_DOMAIN_METADATA_ELEMENT,
KIMCHI_META_URL,
flags=get_vm_config_flag(dom, mode),
)
return etree.fromstring(xml)
except libvirt.libvirtError:
return None
def set_kimchi_metadata_node(dom, metadata, mode='all'):
metadata_xml = etree.tostring(metadata).decode('utf-8')
# From libvirt doc, Passing None for @metadata says to remove that
# element from the domain XML (passing the empty string leaves the
# element present). Do not support remove the old metadata.
dom.setMetadata(
libvirt.VIR_DOMAIN_METADATA_ELEMENT,
metadata_xml,
KIMCHI_NAMESPACE,
KIMCHI_META_URL,
flags=get_vm_config_flag(dom, mode),
)
def set_metadata_node(dom, nodes, mode='all'):
kimchi = get_kimchi_metadata_node(dom, mode)
kimchi = E.metadata() if kimchi is None else kimchi
for n in nodes:
update_node(kimchi, n)
set_kimchi_metadata_node(dom, kimchi, mode)
def remove_metadata_node(dom, tag, mode='all'):
kimchi = get_kimchi_metadata_node(dom, mode)
if kimchi is not None:
node = kimchi.find(tag)
if node is not None:
kimchi.remove(node)
set_kimchi_metadata_node(dom, kimchi, mode)
def get_metadata_node(dom, tag, mode='current'):
kimchi = get_kimchi_metadata_node(dom, mode)
if kimchi is not None:
node = kimchi.find(tag)
if node is not None:
return etree.tostring(node)
return ''
def metadata_exists(dom):
xml = dom.XMLDesc(libvirt.VIR_DOMAIN_XML_INACTIVE)
root = etree.fromstring(xml)
if root.find('metadata') is None:
return False
return True
def has_cpu_numa(dom):
"""
Verify if domain has NUMA configuration
Returns: True or False
"""
root = etree.fromstring(dom.XMLDesc(0))
return root.find('./cpu/numa') is not None
def set_numa_memory(mem, root):
"""
Set new NUMA memory value
Returns: etree element updated
"""
root.find('./cpu/numa/cell').set('memory', str(mem))
return root
================================================
FILE: model/virtviewerfile.py
================================================
#
# Project Kimchi
#
# Copyright IBM Corp, 2016-2017
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
#
import os
import cherrypy
import libvirt
from wok.exception import InvalidOperation
from wok.exception import OperationFailed
from wok.plugins.kimchi import config as kimchi_config
from wok.plugins.kimchi.model.vms import VMModel
from wok.utils import run_command
from wok.utils import wok_log
def write_virt_viewer_file(params):
file_template = """\
[virt-viewer]
type=%(type)s
host=%(host)s
port=%(graphics_port)s
"""
file_contents = file_template % params
if params.get('graphics_passwd'):
file_contents += f'password={params["graphics_passwd"]}\n'
try:
with open(params.get('path'), 'w') as vv_file:
vv_file.write(file_contents)
except Exception:
raise
def _get_request_host():
host = cherrypy.request.headers.get('Host', 'localhost')
host = host.split(':')[0]
return host
def create_virt_viewer_file(vm_name, graphics_info):
graphics_type = graphics_info[0]
graphics_port = graphics_info[2]
graphics_passwd = graphics_info[3]
try:
host = _get_request_host()
default_dir = kimchi_config.get_virtviewerfiles_path()
file_path = os.path.join(default_dir, f'{vm_name}-access.vv')
file_params = {
'type': graphics_type,
'graphics_port': graphics_port,
'graphics_passwd': graphics_passwd,
'host': host,
'path': file_path,
}
write_virt_viewer_file(file_params)
return file_path
except Exception as e:
raise OperationFailed('KCHVM0084E', {'name': vm_name, 'err': str(e)})
class VMVirtViewerFileModel(object):
def __init__(self, **kargs):
self.conn = kargs['conn']
self.firewall_mngr = FirewallManager()
self.vm_event_callbacks = {}
cherrypy.engine.subscribe('exit', self.cleanup)
def cleanup(self):
wok_log.info(
'Closing any VNC/SPICE firewall ports ' 'opened by Kimchi ...')
self.firewall_mngr.remove_all_vms_ports()
for cb_id in self.vm_event_callbacks.values():
self.conn.get().domainEventDeregisterAny(cb_id)
def _check_if_vm_running(self, name):
dom = VMModel.get_vm(name, self.conn)
d_info = dom.info()
if d_info[0] != libvirt.VIR_DOMAIN_RUNNING:
raise InvalidOperation('KCHVM0083E', {'name': name})
def event_vmshutdown_cb(self, conn, dom, event, detail, *args):
if event == libvirt.VIR_DOMAIN_EVENT_STOPPED:
vm_name = dom.name()
self.firewall_mngr.remove_vm_graphics_port(vm_name)
cb_id = self.vm_event_callbacks.pop(vm_name, None)
if cb_id is not None:
self.conn.get().domainEventDeregisterAny(cb_id)
def handleVMShutdownPowerOff(self, vm_name):
try:
dom = VMModel.get_vm(vm_name, self.conn)
cb_id = self.conn.get().domainEventRegisterAny(
dom,
libvirt.VIR_DOMAIN_EVENT_ID_LIFECYCLE,
self.event_vmshutdown_cb,
None,
)
self.vm_event_callbacks[vm_name] = cb_id
except (libvirt.libvirtError, AttributeError) as e:
if type(e) == AttributeError:
reason = 'Libvirt service is not running'
else:
reason = str(e)
wok_log.error(f'Register of LIFECYCLE event failed: {reason}')
def lookup(self, name):
self._check_if_vm_running(name)
graphics_info = VMModel.get_graphics(name, self.conn)
file_path = create_virt_viewer_file(name, graphics_info)
if not self.vm_event_callbacks.get(name, None):
graphics_port = graphics_info[2]
self.firewall_mngr.add_vm_graphics_port(name, graphics_port)
self.handleVMShutdownPowerOff(name)
return f'plugins/kimchi/data/virtviewerfiles/{os.path.basename(file_path)}'
class FirewallManager(object):
@staticmethod
def check_if_firewall_cmd_enabled():
_, _, r_code = run_command(['firewall-cmd', '--state', '-q'])
return r_code == 0
@staticmethod
def check_if_ufw_enabled():
_, _, r_code = run_command(['ufw', 'status'])
return r_code == 0
def __init__(self):
self.opened_ports = {}
self.firewall_provider = None
if self.check_if_firewall_cmd_enabled():
self.firewall_provider = FirewallCMDProvider()
elif self.check_if_ufw_enabled():
self.firewall_provider = UFWProvider()
else:
self.firewall_provider = IPTablesProvider()
def add_vm_graphics_port(self, vm_name, port):
self.firewall_provider.enable_tcp_port(port)
self.opened_ports[vm_name] = port
def remove_vm_graphics_port(self, vm_name):
port = self.opened_ports.pop(vm_name, None)
if port:
self.firewall_provider.disable_tcp_port(port)
def remove_all_vms_ports(self):
for port in self.opened_ports.values():
self.firewall_provider.disable_tcp_port(port)
self.opened_ports = {}
class FirewallCMDProvider(object):
@staticmethod
def enable_tcp_port(port):
_, err, r_code = run_command(
['firewall-cmd', '--add-port=%s/tcp' % port])
if r_code != 0:
wok_log.error(f'Error when adding port to firewall-cmd: {err}')
@staticmethod
def disable_tcp_port(port):
_, err, r_code = run_command(
['firewall-cmd', f'--remove-port={port}/tcp'])
if r_code != 0:
wok_log.error(f'Error when removing port from firewall-cmd: {err}')
class UFWProvider(object):
@staticmethod
def enable_tcp_port(port):
_, err, r_code = run_command(['ufw', 'allow', f'{port}/tcp'])
if r_code != 0:
wok_log.error(f'Error when adding port to ufw: {err}')
@staticmethod
def disable_tcp_port(port):
_, err, r_code = run_command(['ufw', 'deny', f'{port}/tcp'])
if r_code != 0:
wok_log.error(f'Error when removing port from ufw: {err}')
class IPTablesProvider(object):
@staticmethod
def enable_tcp_port(port):
cmd = ['iptables', '-I', 'INPUT', '-p',
'tcp', '--dport', port, '-j', 'ACCEPT']
_, err, r_code = run_command(cmd)
if r_code != 0:
wok_log.error(f'Error when adding port to iptables: {err}')
@staticmethod
def disable_tcp_port(port):
cmd = ['iptables', '-D', 'INPUT', '-p',
'tcp', '--dport', port, '-j', 'ACCEPT']
_, err, r_code = run_command(cmd)
if r_code != 0:
wok_log.error(f'Error when removing port from itables: {err}')
================================================
FILE: model/vmhostdevs.py
================================================
#
# Project Kimchi
#
# Copyright IBM Corp, 2015-2017
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
import glob
import os
import platform
import threading
from operator import itemgetter
import libvirt
from lxml import etree
from lxml import objectify
from lxml.builder import E
from lxml.builder import ElementMaker
from wok.asynctask import AsyncTask
from wok.exception import InvalidOperation
from wok.exception import InvalidParameter
from wok.exception import NotFoundError
from wok.exception import OperationFailed
from wok.message import WokMessage
from wok.model.tasks import TaskModel
from wok.plugins.kimchi.model.config import CapabilitiesModel
from wok.plugins.kimchi.model.host import DeviceModel
from wok.plugins.kimchi.model.host import DevicesModel
from wok.plugins.kimchi.model.utils import get_vm_config_flag
from wok.plugins.kimchi.model.vms import DOM_STATE_MAP
from wok.plugins.kimchi.model.vms import VMModel
from wok.plugins.kimchi.xmlutils.qemucmdline import get_qemucmdline_xml
from wok.plugins.kimchi.xmlutils.qemucmdline import QEMU_NAMESPACE
from wok.rollbackcontext import RollbackContext
from wok.utils import run_command
from wok.utils import wok_log
CMDLINE_FIELD_NAME = 'spapr-pci-host-bridge.mem_win_size'
USB_MODELS_PCI_HOTPLUG = [
'piix3-uhci',
'piix4-uhci',
'ehci',
'ich9-ehci1',
'ich9-uhci1',
'ich9-uhci2',
'ich9-uhci3',
'vt82c686b-uhci',
'pci-ohci',
'nec-xhci',
]
WINDOW_SIZE_BAR = 0x800000000
class VMHostDevsModel(object):
def __init__(self, **kargs):
self.conn = kargs['conn']
self.objstore = kargs['objstore']
self.events = kargs['eventsloop']
self.caps = CapabilitiesModel(**kargs)
self.devs_model = DevicesModel(**kargs)
self.dev_model = DeviceModel(**kargs)
self.task = TaskModel(**kargs)
self._cb = None
self.events.registerAttachDevicesEvent(
self.conn, self._event_devices, self)
def get_list(self, vmid):
dom = VMModel.get_vm(vmid, self.conn)
xmlstr = dom.XMLDesc(0)
root = objectify.fromstring(xmlstr)
try:
hostdev = root.devices.hostdev
except AttributeError:
return []
return [DeviceModel.deduce_dev_name(e, self.conn) for e in hostdev]
def _passthrough_device_validate(self, dev_name):
eligible_dev_names = self.devs_model.get_list(_passthrough='true')
if dev_name not in eligible_dev_names:
raise InvalidParameter('KCHVMHDEV0002E', {'dev_name': dev_name})
def _event_devices(self, conn, dom, alias, opaque):
"""
Callback to handle add/remove devices event
"""
if opaque._cb is None:
wok_log.error('opaque must be valid')
return
wok_log.info('Device %s added successfuly' % alias)
opaque._cb('OK', True)
def create(self, vmid, params):
dev_name = params['name']
dev_info = self.dev_model.lookup(dev_name)
if dev_info['device_type'] == 'pci':
taskid = AsyncTask(
u'/plugins/kimchi/vms/%s/hostdevs/'
% VMModel.get_vm(vmid, self.conn).name(),
self._attach_pci_device,
{'vmid': vmid, 'dev_info': dev_info, 'lock': threading.RLock()},
).id
return self.task.lookup(taskid)
with RollbackContext() as rollback:
try:
dev = self.conn.get().nodeDeviceLookupByName(dev_name)
dev.dettach()
except Exception:
raise OperationFailed('KCHVMHDEV0005E', {'name': dev_name})
else:
rollback.prependDefer(dev.reAttach)
rollback.commitAll()
taskid = AsyncTask(
u'/plugins/kimchi/vms/%s/hostdevs/'
% VMModel.get_vm(vmid, self.conn).name(),
'_attach_%s_device' % dev_info['device_type'],
{'vmid': vmid, 'dev_info': dev_info, 'lock': threading.RLock()},
).id
return self.task.lookup(taskid)
def _get_pci_devices_xml(self, pci_infos, slot, driver):
hostdevs = ''
# all devices included in the xml will be sorted in reverse (the
# function 0 will be the last one) and will include the guest
# address details
for dev_info in sorted(pci_infos, key=itemgetter('function'), reverse=True):
dev_info['detach_driver'] = driver
hostdevs += self._get_pci_device_xml(dev_info, slot, True)
return '%s' % hostdevs
def have_usb_controller(self, vmid):
dom = VMModel.get_vm(vmid, self.conn)
root = objectify.fromstring(dom.XMLDesc(0))
try:
controllers = root.devices.controller
except AttributeError:
return False
for controller in controllers:
if 'model' not in controller.attrib:
continue
if (
controller.attrib['type'] == 'usb' and
controller.attrib['model'] in USB_MODELS_PCI_HOTPLUG
):
return True
return False
def _get_pci_device_xml(self, dev_info, slot, is_multifunction):
if 'detach_driver' not in dev_info:
dev_info['detach_driver'] = 'kvm'
source = E.source(
E.address(
domain=str(dev_info['domain']),
bus=str(dev_info['bus']),
slot=str(dev_info['slot']),
function=str(dev_info['function']),
)
)
driver = E.driver(name=dev_info['detach_driver'])
if is_multifunction:
if dev_info['function'] == 0:
multi = E.address(
type='pci',
domain='0',
bus='0',
slot=str(slot),
function=str(dev_info['function']),
multifunction='on',
)
else:
multi = E.address(
type='pci',
domain='0',
bus='0',
slot=str(slot),
function=str(dev_info['function']),
)
host_dev = E.hostdev(
source, driver, multi, mode='subsystem', type='pci', managed='yes'
)
else:
host_dev = E.hostdev(
source, driver, mode='subsystem', type='pci', managed='yes'
)
return etree.tostring(host_dev)
@staticmethod
def _validate_pci_passthrough_env():
# Linux kernel < 3.5 doesn't provide /sys/kernel/iommu_groups
if os.path.isdir('/sys/kernel/iommu_groups'):
if not glob.glob('/sys/kernel/iommu_groups/*'):
raise InvalidOperation('KCHVMHDEV0003E')
# Enable virt_use_sysfs on RHEL6 and older distributions
# In recent Fedora, there is no virt_use_sysfs.
out, err, rc = run_command(
['getsebool', 'virt_use_sysfs'], silent=True)
if rc == 0 and out.rstrip('\n') != 'virt_use_sysfs --> on':
out, err, rc = run_command(
['setsebool', '-P', 'virt_use_sysfs=on'])
if rc != 0:
wok_log.warning('Unable to turn on sebool virt_use_sysfs')
def _available_slot(self, dom):
xmlstr = dom.XMLDesc(0)
root = objectify.fromstring(xmlstr)
try:
devices = root.devices
slots = [
self.dev_model._toint(dev.attrib['slot'])
for dev in devices.findall('.//address')
if 'slot' in dev.attrib
]
except AttributeError:
return 1
slots = sorted(slots)
free = 0
for free, slot in enumerate(slots, start=1):
if free < slot:
return free
return free + 1
def _attach_pci_device(self, cb, params):
cb('Attaching PCI device')
self._cb = cb
vmid = params['vmid']
dev_info = params['dev_info']
lock = params['lock']
try:
self._passthrough_device_validate(dev_info['name'])
except InvalidParameter as e:
cb(str(e), False)
raise
with lock:
try:
self._validate_pci_passthrough_env()
except InvalidOperation as e:
cb(str(e), False)
raise
dom = VMModel.get_vm(vmid, self.conn)
driver = 'vfio' if self.caps.kernel_vfio else 'kvm'
# 'vfio' systems requires a usb controller in order to support pci
# hotplug on Power.
if (
driver == 'vfio' and
platform.machine().startswith('ppc') and
DOM_STATE_MAP[dom.info()[0]] != 'shutoff' and
not self.have_usb_controller(vmid)
):
msg = WokMessage('KCHVMHDEV0008E', {'vmid': vmid})
cb(msg.get_text(), False)
raise InvalidOperation('KCHVMHDEV0008E', {'vmid': vmid})
# Attach all PCI devices in the same IOMMU group
affected_names = self.devs_model.get_list(
_passthrough_affected_by=dev_info['name']
)
passthrough_names = self.devs_model.get_list(
_cap='pci', _passthrough='true'
)
group_names = list(set(affected_names) & set(passthrough_names))
pci_infos = [self.dev_model.lookup(
dev_name) for dev_name in group_names]
pci_infos.append(dev_info)
pci_infos = sorted(pci_infos, key=itemgetter('name'))
# does not allow hot-plug of 3D graphic cards
is_3D_device = self.dev_model.is_device_3D_controller(dev_info)
if is_3D_device and DOM_STATE_MAP[dom.info()[0]] != 'shutoff':
msg = WokMessage('KCHVMHDEV0006E', {'name': dev_info['name']})
cb(msg.get_text(), False)
raise InvalidOperation(
'KCHVMHDEV0006E', {'name': dev_info['name']})
# all devices in the group that is going to be attached to the vm
# must be detached from the host first
self._attach_all_devices(pci_infos)
# when attaching a 3D graphic device it might be necessary to
# increase the window size memory in order to be able to attach
# more than one device to the same guest
if is_3D_device:
self.update_mmio_guest(vmid, True)
self._attach_multifunction_devices(dom, pci_infos, driver, vmid)
if DOM_STATE_MAP[dom.info()[0]] == 'shutoff':
cb('OK', True)
def _attach_multifunction_devices(self, dom, pci_infos, driver, vmid):
slot = 0
is_multifunction = len(pci_infos) > 1
device_flags = get_vm_config_flag(dom, mode='all')
with RollbackContext() as rollback:
# multifuction: try to attach all functions together within one
# xml file. It requires libvirt support.
if is_multifunction:
# search for the first available slot in guest xml
slot = self._available_slot(dom)
xmlstr = self._get_pci_devices_xml(pci_infos, slot, driver)
try:
dom.attachDeviceFlags(xmlstr, device_flags)
except libvirt.libvirtError:
# If operation fails, we try the other way, where each
# function is attached individually
pass
else:
rollback.prependDefer(
dom.detachDeviceFlags, xmlstr, device_flags
)
rollback.commitAll()
if DOM_STATE_MAP[dom.info()[0]] == 'shutoff':
self._cb('OK', True)
return
# attach each function individually (multi or single function)
for pci_info in pci_infos:
pci_info['detach_driver'] = driver
xmlstr = self._get_pci_device_xml(
pci_info, slot, is_multifunction)
try:
dom.attachDeviceFlags(xmlstr, device_flags)
except libvirt.libvirtError:
msg = WokMessage(
'KCHVMHDEV0007E', {
'device': pci_info['name'], 'vm': vmid}
)
self._cb(msg.get_text(), False)
wok_log.error(
'Failed to attach host device %s to VM %s: \n%s',
pci_info['name'],
vmid,
xmlstr,
)
raise
rollback.prependDefer(
dom.detachDeviceFlags, xmlstr, device_flags)
rollback.commitAll()
def _attach_all_devices(self, pci_infos):
with RollbackContext() as rollback:
for pci_info in pci_infos:
try:
dev = self.conn.get().nodeDeviceLookupByName(
pci_info['name'])
dev.dettach()
except Exception:
msg = WokMessage('KCHVMHDEV0005E', {
'name': pci_info['name']})
self._cb(msg.get_text(), False)
raise OperationFailed(
'KCHVMHDEV0005E', {'name': pci_info['name']}
)
else:
rollback.prependDefer(dev.reAttach)
rollback.commitAll()
def _count_3D_devices_attached(self, dom):
counter = 0
root = objectify.fromstring(dom.XMLDesc(0))
try:
hostdev = root.devices.hostdev
except AttributeError:
return counter
for device in hostdev:
if device.attrib['type'] != 'pci':
continue
name = DeviceModel.deduce_dev_name(device, self.conn)
info = self.dev_model.lookup(name)
if 'vga3d' in info and info['vga3d']:
counter += 1
return counter
def update_mmio_guest(self, vmid, is_attaching):
dom = VMModel.get_vm(vmid, self.conn)
# get the number of 3D graphic cards already attached to the guest
# based on this number we will decide if the memory size will be
# increased or not
counter = self._count_3D_devices_attached(dom)
if counter == 0 and is_attaching:
return
size = 0
if is_attaching:
# suppose this is the 3rd graphic card to be attached to the same
# guest, counter will be 2+1 (2 existing + this attachment) times
# 32G (0x80000000)
size = hex((counter + 1) * WINDOW_SIZE_BAR)
else:
size = hex(counter * WINDOW_SIZE_BAR)
# if the guest already has the xml file we will simply update the
# value, otherwise we will add the new field
new_xml = self._update_win_memory_size(dom, counter, size)
if new_xml is None and is_attaching:
new_xml = self._add_win_memory_size(dom, size)
# update the XML
if new_xml is not None:
self.conn.get().defineXML(new_xml)
def _update_win_memory_size(self, dom, counter, wnd_size):
root = objectify.fromstring(dom.XMLDesc(0))
# look for the existing argument in and try
# to update the value (or remove if there is only one (or none)
# graphic card attached.
cmdline = root.findall('{%s}commandline' % QEMU_NAMESPACE)
for line in cmdline:
for arg in line.iterchildren():
if not arg.values()[0].startswith(CMDLINE_FIELD_NAME):
continue
if counter > 1:
arg.set('value', CMDLINE_FIELD_NAME + '=' + wnd_size)
else:
line.remove(arg.getprevious())
line.remove(arg)
return etree.tostring(root, encoding='unicode', pretty_print=True)
return None
def _add_win_memory_size(self, dom, wnd_size):
root = objectify.fromstring(dom.XMLDesc(0))
val = CMDLINE_FIELD_NAME + '=' + wnd_size
cmdline = root.find('{%s}commandline' % QEMU_NAMESPACE)
# doesn't exist, create the full commandline xml
# with the required values and return
if cmdline is None:
args = {}
args['-global'] = val
root.append(etree.fromstring(get_qemucmdline_xml(args)))
return etree.tostring(root, encoding='unicode', pretty_print=True)
# exists but there is no
# so, we add those missing arguments inside the exising cmdline
EM = ElementMaker(namespace=QEMU_NAMESPACE,
nsmap={'qemu': QEMU_NAMESPACE})
cmdline.append(EM.arg(value='-global'))
cmdline.append(EM.arg(value=val))
return etree.tostring(root, encoding='unicode', pretty_print=True)
def _get_scsi_device_xml(self, dev_info):
adapter = E.adapter(name=('scsi_host%s' % dev_info['host']))
address = E.address(
type='scsi',
bus=str(dev_info['bus']),
target=str(dev_info['target']),
unit=str(dev_info['lun']),
)
host_dev = E.hostdev(
E.source(adapter, address), mode='subsystem', type='scsi', sgio='unfiltered'
)
return etree.tostring(host_dev)
def _attach_scsi_device(self, cb, params):
cb('Attaching SCSI device...')
self._cb = cb
vmid = params['vmid']
dev_info = params['dev_info']
lock = params['lock']
try:
self._passthrough_device_validate(dev_info['name'])
except InvalidParameter as e:
cb(str(e), False)
raise
with lock:
dom = VMModel.get_vm(vmid, self.conn)
with RollbackContext() as rollback:
xmlstr = self._get_scsi_device_xml(dev_info)
device_flags = get_vm_config_flag(dom, mode='all')
try:
cb('Attaching device to VM')
dom.attachDeviceFlags(xmlstr, device_flags)
except libvirt.libvirtError:
msg = WokMessage(
'KCHVMHDEV0007E', {
'device': dev_info['name'], 'vm': vmid}
)
cb(msg.get_text(), False)
wok_log.error(
'Failed to attach host device %s to VM %s: \n%s',
dev_info['name'],
vmid,
xmlstr,
)
raise
rollback.prependDefer(
dom.detachDeviceFlags, xmlstr, device_flags)
rollback.commitAll()
if DOM_STATE_MAP[dom.info()[0]] == 'shutoff':
cb('OK', True)
def _get_usb_device_xml(self, dev_info):
source = E.source(
E.vendor(id=dev_info['vendor']['id']),
E.product(id=dev_info['product']['id']),
E.address(bus=str(dev_info['bus']),
device=str(dev_info['device'])),
startupPolicy='optional',
)
host_dev = E.hostdev(source, mode='subsystem',
ype='usb', managed='yes')
return etree.tostring(host_dev)
def _attach_usb_device(self, cb, params):
cb('Attaching USB device...')
self._cb = cb
vmid = params['vmid']
dev_info = params['dev_info']
dom = VMModel.get_vm(vmid, self.conn)
lock = params['lock']
try:
self._passthrough_device_validate(dev_info['name'])
except InvalidParameter as e:
cb(str(e), False)
raise
with lock:
with RollbackContext() as rollback:
xmlstr = self._get_usb_device_xml(dev_info)
device_flags = get_vm_config_flag(dom, mode='all')
try:
cb('Attaching device to VM')
dom.attachDeviceFlags(xmlstr, device_flags)
except libvirt.libvirtError:
msg = WokMessage(
'KCHVMHDEV0007E', {
'device': dev_info['name'], 'vm': vmid}
)
cb(msg.get_text(), False)
wok_log.error(
'Failed to attach host device %s to VM %s: \n%s',
dev_info['name'],
vmid,
xmlstr,
)
raise
rollback.prependDefer(
dom.detachDeviceFlags, xmlstr, device_flags)
rollback.commitAll()
if DOM_STATE_MAP[dom.info()[0]] == 'shutoff':
cb('OK', True)
class VMHostDevModel(object):
def __init__(self, **kargs):
self.conn = kargs['conn']
self.objstore = kargs['objstore']
self.events = kargs['eventsloop']
self.task = TaskModel(**kargs)
self.devs_model = DevicesModel(**kargs)
self.dev_model = DeviceModel(**kargs)
self._cb = None
self.events.registerDetachDevicesEvent(
self.conn, self._event_devices, self)
def lookup(self, vmid, dev_name):
dom = VMModel.get_vm(vmid, self.conn)
xmlstr = dom.XMLDesc(0)
root = objectify.fromstring(xmlstr)
try:
hostdev = root.devices.hostdev
except AttributeError:
raise NotFoundError('KCHVMHDEV0001E', {
'vmid': vmid, 'dev_name': dev_name})
for e in hostdev:
deduced_name = DeviceModel.deduce_dev_name(e, self.conn)
if deduced_name == dev_name:
dev_info = self.dev_model.lookup(dev_name)
return {
'name': dev_name,
'type': e.attrib['type'],
'product': dev_info.get('product', None),
'vendor': dev_info.get('vendor', None),
'multifunction': dev_info.get('multifunction', None),
'vga3d': dev_info.get('vga3d', None),
}
raise NotFoundError('KCHVMHDEV0001E', {
'vmid': vmid, 'dev_name': dev_name})
def delete(self, vmid, dev_name):
dom = VMModel.get_vm(vmid, self.conn)
xmlstr = dom.XMLDesc(0)
root = objectify.fromstring(xmlstr)
try:
hostdev = root.devices.hostdev
except AttributeError:
raise NotFoundError('KCHVMHDEV0001E', {
'vmid': vmid, 'dev_name': dev_name})
task_params = {
'vmid': vmid,
'dev_name': dev_name,
'dom': dom,
'hostdev': hostdev,
'lock': threading.RLock(),
}
task_uri = u'/plugins/kimchi/vms/%s/hostdevs/%s' % (
VMModel.get_vm(vmid, self.conn).name(),
dev_name,
)
taskid = AsyncTask(task_uri, self._detach_device, task_params).id
return self.task.lookup(taskid)
def _event_devices(self, conn, dom, alias, opaque):
"""
Callback to handle add/remove devices event
"""
if opaque._cb is None:
wok_log.error('opaque must be valid')
return
wok_log.info('Device %s removed successfully' % alias)
# Re-attach device to host if it's not managed mode
if not opaque._managed:
try:
dev = conn.get().nodeDeviceLookupByName(alias)
dev.reAttach()
except libvirt.libvirtError as e:
wok_log.error(
'Unable to attach device %s back to host. Error: %s', alias, str(
e)
)
else:
wok_log.info(
"Device %s was attached in 'managed' mode. "
'Skipping re-attach().' % alias
)
opaque._cb('OK', True)
def _detach_device(self, cb, params):
cb('Detaching device')
self._cb = cb
vmid = params['vmid']
dev_name = params['dev_name']
dom = params['dom']
hostdev = params['hostdev']
lock = params['lock']
with lock:
pci_devs = {
DeviceModel.deduce_dev_name(e, self.conn): e
for e in hostdev
if e.attrib['type'] == 'pci'
}
dev_info = self.dev_model.lookup(dev_name)
is_3D_device = self.dev_model.is_device_3D_controller(dev_info)
if is_3D_device and DOM_STATE_MAP[dom.info()[0]] != 'shutoff':
raise InvalidOperation(
'KCHVMHDEV0006E', {'name': dev_info['name']})
if not pci_devs.get(dev_name):
raise NotFoundError(
'KCHVMHDEV0001E', {'vmid': vmid, 'dev_name': dev_name}
)
dev_name_elem = pci_devs[dev_name]
self._managed = dev_name_elem.get('managed', 'no') == 'yes'
# check for multifunction and detach all functions together
try:
multi = self.unplug_multifunction_pci(
dom, hostdev, dev_name_elem)
except libvirt.libvirtError:
multi = False
# successfully detached all functions: finish operation
if multi:
if is_3D_device:
devsmodel = VMHostDevsModel(conn=self.conn)
devsmodel.update_mmio_guest(vmid, False)
if DOM_STATE_MAP[dom.info()[0]] == 'shutoff':
cb('OK', True)
return
# detach individually
xmlstr = etree.tostring(dev_name_elem)
dom.detachDeviceFlags(xmlstr, get_vm_config_flag(dom, mode='all'))
if dev_name_elem.attrib['type'] == 'pci':
self._delete_affected_pci_devices(dom, dev_name, pci_devs)
if is_3D_device:
devsmodel = VMHostDevsModel(conn=self.conn)
devsmodel.update_mmio_guest(vmid, False)
if DOM_STATE_MAP[dom.info()[0]] == 'shutoff':
cb('OK', True)
def get_devices_same_addr(self, hostdevs, device_elem):
def elem_has_valid_address(elem):
if (
elem.get('type') != 'pci' or
elem.address is None or
elem.address.get('domain') is None or
elem.address.get('bus') is None or
elem.address.get('slot') is None
):
return False
return True
if not elem_has_valid_address(device_elem):
return []
devices = []
device_domain = device_elem.address.get('domain')
device_bus = device_elem.address.get('bus')
device_slot = device_elem.address.get('slot')
for dev in hostdevs:
if not elem_has_valid_address(dev):
continue
dev_domain = dev.address.get('domain')
dev_bus = dev.address.get('bus')
dev_slot = dev.address.get('slot')
if (
dev_domain == device_domain and
dev_bus == device_bus and
dev_slot == device_slot
):
devices.append(etree.tostring(dev).decode('utf-8'))
return devices
def is_hostdev_multifunction(self, dev_elem):
if (
dev_elem.address is None or
dev_elem.address.get('multifunction') is None or
dev_elem.address.get('function') is None
):
return False
is_multi = (
dev_elem.address.get('multifunction') == 'on' and
dev_elem.address.get('function') == '0x0'
)
return is_multi
def unplug_multifunction_pci(self, dom, hostdevs, dev_elem):
if not self.is_hostdev_multifunction(dev_elem):
return False
devices = self.get_devices_same_addr(hostdevs, dev_elem)
if len(devices) <= 1:
return False
devices_xml = '%s' % ''.join(devices)
dom.detachDeviceFlags(devices_xml, get_vm_config_flag(dom, mode='all'))
return True
def _delete_affected_pci_devices(self, dom, dev_name, pci_devs):
try:
self.dev_model.lookup(dev_name)
except NotFoundError:
return
affected_names = set(
DevicesModel(conn=self.conn).get_list(
_passthrough_affected_by=dev_name)
)
for pci_name, e in pci_devs.items():
if pci_name in affected_names:
xmlstr = etree.tostring(e)
dom.detachDeviceFlags(
xmlstr, get_vm_config_flag(dom, mode='all'))
class VMHoldersModel(object):
def __init__(self, **kargs):
self.conn = kargs['conn']
def get_list(self, device_id):
devsmodel = VMHostDevsModel(conn=self.conn)
conn = self.conn.get()
doms = conn.listAllDomains(0)
res = []
for dom in doms:
dom_name = dom.name()
if device_id in devsmodel.get_list(dom_name):
state = DOM_STATE_MAP[dom.info()[0]]
res.append({'name': dom_name, 'state': state})
return res
================================================
FILE: model/vmifaces.py
================================================
#
# Project Kimchi
#
# Copyright IBM Corp, 2015-2016
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
import os
import random
import libvirt
from lxml import etree
from lxml import objectify
from wok.exception import InvalidOperation
from wok.exception import InvalidParameter
from wok.exception import MissingParameter
from wok.exception import NotFoundError
from wok.plugins.kimchi.model.config import CapabilitiesModel
from wok.plugins.kimchi.model.vms import DOM_STATE_MAP
from wok.plugins.kimchi.model.vms import VMModel
from wok.plugins.kimchi.xmlutils.interface import get_iface_xml
class VMIfacesModel(object):
def __init__(self, **kargs):
self.conn = kargs['conn']
self.caps = CapabilitiesModel(**kargs)
def get_list(self, vm):
macs = []
for iface in self.get_vmifaces(vm, self.conn):
macs.append(iface.mac.get('address'))
return macs
def create(self, vm, params):
conn = self.conn.get()
if params['type'] == 'network':
network = params.get('network')
if network is None:
raise MissingParameter('KCHVMIF0007E')
networks = conn.listNetworks() + conn.listDefinedNetworks()
if network not in networks:
raise InvalidParameter(
'KCHVMIF0002E', {'name': vm, 'network': network})
# For architecture other than s390x/s390 type ovs/macvtap
# and source interface are not supported.
if os.uname()[4] not in ['s390x', 's390']:
if params['type'] in ['ovs', 'macvtap']:
raise InvalidParameter('KCHVMIF0012E')
if params.get('source'):
raise InvalidParameter('KCHVMIF0013E')
# For s390x/s390 architecture
if os.uname()[4] in ['s390x', 's390']:
params['name'] = params.get('source', None)
# For type ovs and mavtap, source interface has to be provided.
if params['name'] is None and params['type'] in ['ovs', 'macvtap']:
raise InvalidParameter('KCHVMIF0015E')
# If source interface provided, only type supported are ovs
# and mavtap.
if params['name'] is not None and params['type'] not in ['ovs', 'macvtap']:
raise InvalidParameter('KCHVMIF0014E')
# FIXME: Validation if source interface exists.
if params['type'] == 'macvtap':
params['type'] = 'direct'
params['mode'] = params.get('mode', None)
elif params['type'] == 'ovs':
params['type'] = 'bridge'
params['virtualport_type'] = 'openvswitch'
macs = (iface.mac.get('address')
for iface in self.get_vmifaces(vm, self.conn))
# user defined customized mac address
if 'mac' in params and params['mac']:
# make sure it is unique
if params['mac'] in macs:
raise InvalidParameter(
'KCHVMIF0009E', {'name': vm, 'mac': params['mac']}
)
# otherwise choose a random mac address
else:
while True:
params['mac'] = VMIfacesModel.random_mac()
if params['mac'] not in macs:
break
dom = VMModel.get_vm(vm, self.conn)
os_data = VMModel.vm_get_os_metadata(dom)
os_version, os_distro = os_data
xml = get_iface_xml(params, conn.getInfo()[0], os_distro, os_version)
flags = 0
if dom.isPersistent():
flags |= libvirt.VIR_DOMAIN_AFFECT_CONFIG
if DOM_STATE_MAP[dom.info()[0]] != 'shutoff':
flags |= libvirt.VIR_DOMAIN_AFFECT_LIVE
dom.attachDeviceFlags(xml, flags)
return params['mac']
@staticmethod
def get_vmifaces(vm, conn):
dom = VMModel.get_vm(vm, conn)
xml = dom.XMLDesc(0)
root = objectify.fromstring(xml)
return root.devices.findall('interface')
@staticmethod
def random_mac():
mac = [
0x52,
0x54,
0x00,
random.randint(0x00, 0x7F),
random.randint(0x00, 0xFF),
random.randint(0x00, 0xFF),
]
return ':'.join(map(lambda x: u'%02x' % x, mac))
class VMIfaceModel(object):
def __init__(self, **kargs):
self.conn = kargs['conn']
def _get_vmiface(self, vm, mac):
ifaces = VMIfacesModel.get_vmifaces(vm, self.conn)
for iface in ifaces:
if iface.mac.get('address') == mac:
return iface
return None
def lookup(self, vm, mac):
info = {}
iface = self._get_vmiface(vm, mac)
if iface is None:
raise NotFoundError('KCHVMIF0001E', {'name': vm, 'iface': mac})
info['type'] = iface.attrib['type']
info['mac'] = iface.mac.get('address')
if iface.find('virtualport') is not None:
info['virtualport'] = iface.virtualport.get('type')
if info['type'] == 'direct':
info['source'] = iface.source.get('dev')
info['mode'] = iface.source.get('mode')
info['type'] = 'macvtap'
elif info['type'] == 'bridge' and info.get('virtualport') == 'openvswitch':
info['source'] = iface.source.get('bridge')
info['type'] = 'ovs'
else:
info['network'] = iface.source.get('network')
if iface.find('model') is not None:
info['model'] = iface.model.get('type')
if info['type'] == 'bridge' and info.get('virtualport') != 'openvswitch':
info['bridge'] = iface.source.get('bridge')
if info.get('network'):
info['ips'] = self._get_ips(vm, info['mac'], info['network'])
info.pop('virtualport', None)
return info
def _get_ips(self, vm, mac, network):
ips = []
# Return empty list if shutoff, even if leases still valid or ARP
# cache has entries for this MAC.
conn = self.conn.get()
dom = VMModel.get_vm(vm, self.conn)
if DOM_STATE_MAP[dom.info()[0]] == 'shutoff':
return ips
# An iface may have multiple IPs
# An IP could have been assigned without libvirt.
# First check the ARP cache.
with open('/proc/net/arp') as f:
ips = [line.split()[0] for line in f.readlines() if mac in line]
# Some ifaces may be inactive, so if the ARP cache didn't have them,
# and they happen to be assigned via DHCP, we can check there too.
try:
# Some type of interfaces may not have a network associated with
net = conn.networkLookupByName(network)
leases = net.DHCPLeases(mac)
for lease in leases:
ip = lease.get('ipaddr')
if ip not in ips:
ips.append(ip)
except libvirt.libvirtError:
pass
return ips
def delete(self, vm, mac):
dom = VMModel.get_vm(vm, self.conn)
iface = self._get_vmiface(vm, mac)
if iface is None:
raise NotFoundError('KCHVMIF0001E', {'name': vm, 'iface': mac})
flags = 0
if dom.isPersistent():
flags |= libvirt.VIR_DOMAIN_AFFECT_CONFIG
if DOM_STATE_MAP[dom.info()[0]] != 'shutoff':
flags |= libvirt.VIR_DOMAIN_AFFECT_LIVE
dom.detachDeviceFlags(etree.tostring(iface).decode('utf-8'), flags)
def update(self, vm, mac, params):
dom = VMModel.get_vm(vm, self.conn)
iface = self._get_vmiface(vm, mac)
if iface is None:
raise NotFoundError('KCHVMIF0001E', {'name': vm, 'iface': mac})
# cannot change mac address in a running system
if DOM_STATE_MAP[dom.info()[0]] != 'shutoff':
raise InvalidOperation('KCHVMIF0011E')
# mac address is a required parameter
if 'mac' not in params:
raise MissingParameter('KCHVMIF0008E')
# new mac address must be unique
if self._get_vmiface(vm, params['mac']) is not None:
raise InvalidParameter(
'KCHVMIF0009E', {'name': vm, 'mac': params['mac']})
flags = 0
if dom.isPersistent():
flags |= libvirt.VIR_DOMAIN_AFFECT_CONFIG
# remove the current nic
xml = etree.tostring(iface).decode('utf-8')
dom.detachDeviceFlags(xml, flags=flags)
# add the nic with the desired mac address
iface.mac.attrib['address'] = params['mac']
xml = etree.tostring(iface).decode('utf-8')
dom.attachDeviceFlags(xml, flags=flags)
return [vm, params['mac']]
================================================
FILE: model/vms.py
================================================
#
# Project Kimchi
#
# Copyright IBM Corp, 2015-2017
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
import copy
import os
import platform
import pwd
import random
import signal
import socket
import string
import subprocess
import threading
import time
import uuid
from xml.etree import ElementTree
import libvirt
import lxml.etree as ET
import paramiko
from lxml import etree
from lxml import objectify
from lxml.builder import E
from wok import websocket
from wok.asynctask import AsyncTask
from wok.config import config
from wok.exception import InvalidOperation
from wok.exception import InvalidParameter
from wok.exception import NotFoundError
from wok.exception import OperationFailed
from wok.model.tasks import TaskModel
from wok.plugins.kimchi import model
from wok.plugins.kimchi import serialconsole
from wok.plugins.kimchi.config import config as kimchi_config
from wok.plugins.kimchi.config import get_kimchi_version
from wok.plugins.kimchi.config import READONLY_POOL_TYPE
from wok.plugins.kimchi.kvmusertests import UserTests
from wok.plugins.kimchi.model.config import CapabilitiesModel
from wok.plugins.kimchi.model.cpuinfo import CPUInfoModel
from wok.plugins.kimchi.model.featuretests import FeatureTests
from wok.plugins.kimchi.model.templates import PPC_MEM_ALIGN
from wok.plugins.kimchi.model.templates import TemplateModel
from wok.plugins.kimchi.model.templates import validate_memory
from wok.plugins.kimchi.model.utils import get_ascii_nonascii_name
from wok.plugins.kimchi.model.utils import get_metadata_node
from wok.plugins.kimchi.model.utils import get_vm_name
from wok.plugins.kimchi.model.utils import remove_metadata_node
from wok.plugins.kimchi.model.utils import set_metadata_node
from wok.plugins.kimchi.osinfo import defaults
from wok.plugins.kimchi.osinfo import MEM_DEV_SLOTS
from wok.plugins.kimchi.screenshot import VMScreenshot
from wok.plugins.kimchi.utils import get_next_clone_name
from wok.plugins.kimchi.utils import is_s390x
from wok.plugins.kimchi.utils import template_name_from_uri
from wok.plugins.kimchi.xmlutils.bootorder import get_bootmenu_node
from wok.plugins.kimchi.xmlutils.bootorder import get_bootorder_node
from wok.plugins.kimchi.xmlutils.cpu import get_topology_xml
from wok.plugins.kimchi.xmlutils.disk import get_vm_disk_info
from wok.plugins.kimchi.xmlutils.disk import get_vm_disks
from wok.rollbackcontext import RollbackContext
from wok.utils import convert_data_size
from wok.utils import import_class
from wok.utils import run_command
from wok.utils import run_setfacl_set_attr
from wok.utils import wok_log
from wok.xmlutils.utils import dictize
from wok.xmlutils.utils import xml_item_insert
from wok.xmlutils.utils import xml_item_remove
from wok.xmlutils.utils import xml_item_update
from wok.xmlutils.utils import xpath_get_text
from .utils import has_cpu_numa
from .utils import set_numa_memory
DOM_STATE_MAP = {
0: 'nostate',
1: 'running',
2: 'blocked',
3: 'paused',
4: 'shutdown',
5: 'shutoff',
6: 'crashed',
7: 'pmsuspended',
}
# update parameters which are updatable when the VM is online
VM_ONLINE_UPDATE_PARAMS = [
'cpu_info',
'graphics',
'groups',
'memory',
'users',
'autostart',
]
# update parameters which are updatable when the VM is offline
VM_OFFLINE_UPDATE_PARAMS = [
'cpu_info',
'graphics',
'groups',
'memory',
'name',
'users',
'bootorder',
'bootmenu',
'description',
'title',
'console',
'autostart',
]
XPATH_DOMAIN_DISK = "/domain/devices/disk[@device='disk']/source/@file"
XPATH_DOMAIN_DISK_BY_FILE = "./devices/disk[@device='disk']/source[@file='%s']"
XPATH_DOMAIN_NAME = '/domain/name'
XPATH_DOMAIN_MAC = '/domain/devices/interface/mac/@address'
XPATH_DOMAIN_MAC_BY_ADDRESS = "./devices/interface/mac[@address='%s']"
XPATH_DOMAIN_MEMORY = '/domain/memory'
XPATH_DOMAIN_MEMORY_UNIT = '/domain/memory/@unit'
XPATH_DOMAIN_UUID = '/domain/uuid'
XPATH_DOMAIN_DEV_CPU_ID = '/domain/devices/spapr-cpu-socket/@id'
XPATH_DOMAIN_CONSOLE_TARGET = '/domain/devices/console/target/@type'
XPATH_BOOT = 'os/boot/@dev'
XPATH_BOOTMENU = 'os/bootmenu/@enable'
XPATH_CPU = './cpu'
XPATH_DESCRIPTION = './description'
XPATH_MEMORY = './memory'
XPATH_NAME = './name'
XPATH_NUMA_CELL = './cpu/numa/cell'
XPATH_SNAP_VM_NAME = './domain/name'
XPATH_SNAP_VM_UUID = './domain/uuid'
XPATH_TITLE = './title'
XPATH_TOPOLOGY = './cpu/topology'
XPATH_VCPU = './vcpu'
XPATH_MAX_MEMORY = './maxMemory'
XPATH_CONSOLE_TARGET = './devices/console/target'
# key: VM name; value: lock object
vm_locks = {}
class VMsModel(object):
def __init__(self, **kargs):
self.conn = kargs['conn']
self.objstore = kargs['objstore']
self.caps = CapabilitiesModel(**kargs)
self.task = TaskModel(**kargs)
def create(self, params):
t_name = template_name_from_uri(params['template'])
vm_list = self.get_list()
name = get_vm_name(params.get('name'), t_name, vm_list)
# incoming text, from js json, is unicode, do not need decode
if name in vm_list:
raise InvalidOperation('KCHVM0001E', {'name': name})
vm_overrides = dict()
pool_uri = params.get('storagepool')
if pool_uri:
vm_overrides['storagepool'] = pool_uri
vm_overrides['fc_host_support'] = self.caps.fc_host_support
t = TemplateModel.get_template(
t_name, self.objstore, self.conn, vm_overrides)
if not self.caps.qemu_stream and t.info.get('iso_stream', False):
raise InvalidOperation('KCHVM0005E')
t.validate()
data = {
'name': name,
'template': t,
'graphics': params.get('graphics', {}),
'title': params.get('title', ''),
'description': params.get('description', ''),
}
taskid = AsyncTask(
f'/plugins/kimchi/vms/{name}', self._create_task, data).id
return self.task.lookup(taskid)
def _create_task(self, cb, params):
"""
params: A dict with the following values:
- vm_uuid: The UUID of the VM being created
- template: The template being used to create the VM
- name: The name for the new VM
"""
vm_uuid = str(uuid.uuid4())
title = params.get('title', '')
description = params.get('description', '')
t = params['template']
name, nonascii_name = get_ascii_nonascii_name(params['name'])
conn = self.conn.get()
cb('Storing VM icon')
# Store the icon for displaying later
icon = t.info.get('icon')
if icon:
try:
with self.objstore as session:
session.store('vm', vm_uuid, {
'icon': icon}, get_kimchi_version())
except Exception as e:
# It is possible to continue Kimchi executions without store
# vm icon info
wok_log.error(
f'Error trying to update database with guest '
f'icon information due error: {e}'
)
cb('Provisioning storages for new VM')
vol_list = t.fork_vm_storage(vm_uuid)
graphics = params.get('graphics', {})
stream_protocols = self.caps.libvirt_stream_protocols
xml = t.to_vm_xml(
name,
vm_uuid,
libvirt_stream_protocols=stream_protocols,
graphics=graphics,
mem_hotplug_support=self.caps.mem_hotplug_support,
title=title,
description=description,
)
cb('Defining new VM')
try:
conn.defineXML(xml)
except libvirt.libvirtError as e:
for v in vol_list:
vol = conn.storageVolLookupByPath(v['path'])
vol.delete(0)
raise OperationFailed(
'KCHVM0007E', {'name': name, 'err': e.get_error_message()}
)
cb('Updating VM metadata')
meta_elements = []
distro = t.info.get('os_distro')
version = t.info.get('os_version')
if distro is not None:
meta_elements.append(E.os({'distro': distro, 'version': version}))
if nonascii_name is not None:
meta_elements.append(E.name(nonascii_name))
set_metadata_node(VMModel.get_vm(name, self.conn), meta_elements)
cb('OK', True)
def get_list(self):
return VMsModel.get_vms(self.conn)
@staticmethod
def get_vms(conn):
conn_ = conn.get()
names = []
for dom in conn_.listAllDomains(0):
nonascii_xml = get_metadata_node(dom, 'name')
if nonascii_xml:
nonascii_node = ET.fromstring(nonascii_xml)
names.append(nonascii_node.text)
else:
names.append(dom.name())
names = sorted(names, key=str.lower)
return names
class VMModel(object):
def __init__(self, **kargs):
self.conn = kargs['conn']
self.objstore = kargs['objstore']
self.caps = CapabilitiesModel(**kargs)
self.vmscreenshot = VMScreenshotModel(**kargs)
self.users = import_class(
'wok.plugins.kimchi.model.users.UsersModel')(**kargs)
self.groups = import_class('wok.plugins.kimchi.model.groups.GroupsModel')(
**kargs
)
self.vms = VMsModel(**kargs)
self.task = TaskModel(**kargs)
self.storagepool = model.storagepools.StoragePoolModel(**kargs)
self.storagevolume = model.storagevolumes.StorageVolumeModel(**kargs)
self.storagevolumes = model.storagevolumes.StorageVolumesModel(**kargs)
cls = import_class(
'wok.plugins.kimchi.model.vmsnapshots.VMSnapshotModel')
self.vmsnapshot = cls(**kargs)
cls = import_class(
'wok.plugins.kimchi.model.vmsnapshots.VMSnapshotsModel')
self.vmsnapshots = cls(**kargs)
self.stats = {}
self._serial_procs = []
def has_topology(self, dom):
xml = dom.XMLDesc(0)
sockets = xpath_get_text(xml, XPATH_TOPOLOGY + '/@sockets')
cores = xpath_get_text(xml, XPATH_TOPOLOGY + '/@cores')
threads = xpath_get_text(xml, XPATH_TOPOLOGY + '/@threads')
return sockets and cores and threads
def update(self, name, params):
if platform.machine() not in ['s390x', 's390'] and 'console' in params:
raise InvalidParameter('KCHVM0087E')
lock = vm_locks.get(name)
if lock is None:
lock = threading.Lock()
vm_locks[name] = lock
with lock:
dom = self.get_vm(name, self.conn)
if 'autostart' in params:
dom.setAutostart(1 if params['autostart'] is True else 0)
# You can only change offline, updating guest XML
if (
('memory' in params)
and ('maxmemory' in params['memory'])
and (DOM_STATE_MAP[dom.info()[0]] != 'shutoff')
):
raise InvalidParameter('KCHVM0080E')
if DOM_STATE_MAP[dom.info()[0]] == 'shutoff':
ext_params = set(params.keys()) - set(VM_OFFLINE_UPDATE_PARAMS)
if len(ext_params) > 0:
raise InvalidParameter(
'KCHVM0073E', {'params': ', '.join(ext_params)}
)
else:
ext_params = set(params.keys()) - set(VM_ONLINE_UPDATE_PARAMS)
if len(ext_params) > 0:
raise InvalidParameter(
'KCHVM0074E', {'params': ', '.join(ext_params)}
)
# METADATA can be updated offline or online
self._vm_update_access_metadata(dom, params)
# GRAPHICS can be updated offline or online
if 'graphics' in params:
# some parameters cannot change while vm is running
if DOM_STATE_MAP[dom.info()[0]] != 'shutoff':
if 'type' in params['graphics']:
raise InvalidParameter(
'KCHVM0074E', {'params': 'graphics type'}
)
dom = self._update_graphics(dom, params)
# Live updates
if dom.isActive():
self._live_vm_update(dom, params)
vm_name = name
if DOM_STATE_MAP[dom.info()[0]] == 'shutoff':
vm_name, dom = self._static_vm_update(name, dom, params)
return vm_name
def clone(self, name):
"""Clone a virtual machine based on an existing one.
The new virtual machine will have the exact same configuration as the
original VM, except for the name, UUID, MAC addresses and disks. The
name will have the form "-clone-", with starting
at 1; the UUID will be generated randomly; the MAC addresses will be
generated randomly with no conflicts within the original and the new
VM; and the disks will be new volumes [mostly] on the same storage
pool, with the same content as the original disks. The storage pool
'default' will always be used when cloning SCSI and iSCSI disks and
when the original storage pool cannot hold the new volume.
An exception will be raised if the virtual machine is not
shutoff, if there is no available space to copy a new volume to the
storage pool 'default' (when there was also no space to copy it to the
original storage pool) and if one of the virtual machine's disks belong
to a storage pool not supported by Kimchi.
Parameters:
name -- The name of the existing virtual machine to be cloned.
Return:
A Task running the clone operation.
"""
# VM must be shutoff in order to clone it
info = self.lookup(name)
if info['state'] != 'shutoff':
raise InvalidParameter('KCHVM0033E', {'name': name})
# the new VM's name will be used as the Task's 'target_uri' so it needs
# to be defined now.
vms_being_created = []
# lookup names of VMs being created right now
with self.objstore as session:
task_names = session.get_list('task')
for tn in task_names:
t = session.get('task', tn)
if t['target_uri'].startswith('/plugins/kimchi/vms/'):
uri_name = t['target_uri'].lstrip('/plugins/kimchi/vms/')
vms_being_created.append(uri_name)
current_vm_names = self.vms.get_list() + vms_being_created
new_name = get_next_clone_name(current_vm_names, name, ts=True)
# create a task with the actual clone function
taskid = AsyncTask(
f'/plugins/kimchi/vms/{new_name}/clone',
self._clone_task,
{'name': name, 'new_name': new_name},
).id
return self.task.lookup(taskid)
def _clone_task(self, cb, params):
"""Asynchronous function which performs the clone operation.
Parameters:
cb -- A callback function to signal the Task's progress.
params -- A dict with the following values:
"name": the name of the original VM.
"new_name": the name of the new VM.
"""
name = params['name']
new_name = params['new_name']
# fetch base XML
cb('reading source VM XML')
try:
vir_dom = self.get_vm(name, self.conn)
flags = libvirt.VIR_DOMAIN_XML_SECURE
xml = vir_dom.XMLDesc(flags)
except libvirt.libvirtError as e:
raise OperationFailed('KCHVM0035E', {'name': name, 'err': str(e)})
# update UUID
cb('updating VM UUID')
old_uuid = xpath_get_text(xml, XPATH_DOMAIN_UUID)[0]
new_uuid = str(uuid.uuid4())
xml = xml_item_update(xml, './uuid', new_uuid)
# update MAC addresses
cb('updating VM MAC addresses')
xml = self._clone_update_mac_addresses(xml)
with RollbackContext() as rollback:
# copy disks
cb('copying VM disks')
xml = self._clone_update_disks(xml, rollback)
# update objstore entry
cb('updating object store')
self._clone_update_objstore(old_uuid, new_uuid, rollback)
# update name
cb('updating VM name')
new_name, nonascii_name = get_ascii_nonascii_name(new_name)
xml = xml_item_update(xml, './name', new_name)
# create new guest
cb('defining new VM')
try:
vir_conn = self.conn.get()
dom = vir_conn.defineXML(xml)
self._update_metadata_name(dom, nonascii_name)
except libvirt.libvirtError as e:
raise OperationFailed(
'KCHVM0035E', {'name': name, 'err': str(e)})
rollback.commitAll()
cb('OK', True)
@staticmethod
def _clone_update_mac_addresses(xml):
"""Update the MAC addresses with new values in the XML descriptor of a
cloning domain.
The new MAC addresses will be generated randomly, and their values are
guaranteed to be distinct from the ones in the original VM.
Arguments:
xml -- The XML descriptor of the original domain.
Return:
The XML descriptor with the new MAC addresses instead of the
old ones.
"""
old_macs = xpath_get_text(xml, XPATH_DOMAIN_MAC)
new_macs = []
for mac in old_macs:
while True:
new_mac = model.vmifaces.VMIfacesModel.random_mac()
# make sure the new MAC doesn't conflict with the original VM
# and with the new values on the new VM.
if new_mac not in (old_macs + new_macs):
new_macs.append(new_mac)
break
xml = xml_item_update(
xml, XPATH_DOMAIN_MAC_BY_ADDRESS % mac, new_mac, 'address'
)
return xml
def _clone_update_disks(self, xml, rollback):
"""Clone disks from a virtual machine. The disks are copied as new
volumes and the new VM's XML is updated accordingly.
Arguments:
xml -- The XML descriptor of the original VM + new value for
"/domain/uuid".
rollback -- A rollback context so the new volumes can be removed if an
error occurs during the cloning operation.
Return:
The XML descriptor with the new disk paths instead of the
old ones.
"""
# the UUID will be used to create the disk paths
uuid = xpath_get_text(xml, XPATH_DOMAIN_UUID)[0]
all_paths = xpath_get_text(xml, XPATH_DOMAIN_DISK)
vir_conn = self.conn.get()
domain_name = xpath_get_text(xml, XPATH_DOMAIN_NAME)[0]
for i, path in enumerate(all_paths):
try:
vir_orig_vol = vir_conn.storageVolLookupByPath(path)
vir_pool = vir_orig_vol.storagePoolLookupByVolume()
orig_pool_name = vir_pool.name()
orig_vol_name = vir_orig_vol.name()
except libvirt.libvirtError as e:
raise OperationFailed(
'KCHVM0035E', {'name': domain_name, 'err': str(e)}
)
orig_pool = self.storagepool.lookup(orig_pool_name)
orig_vol = self.storagevolume.lookup(orig_pool_name, orig_vol_name)
new_pool_name = orig_pool_name
new_pool = orig_pool
if orig_pool['type'] in ['dir', 'netfs', 'logical']:
# if a volume in a pool 'dir', 'netfs' or 'logical' cannot hold
# a new volume with the same size, the pool 'default' should
# be used
if orig_vol['capacity'] > orig_pool['available']:
wok_log.warning(
f"storage pool '{orig_pool_name}' doesn't have "
f'enough free space to store image '
f"'{path}'; falling back to 'default'"
)
new_pool_name = 'default'
new_pool = self.storagepool.lookup('default')
# ...and if even the pool 'default' cannot hold a new
# volume, raise an exception
if orig_vol['capacity'] > new_pool['available']:
domain_name = xpath_get_text(xml, XPATH_DOMAIN_NAME)[0]
raise InvalidOperation(
'KCHVM0034E', {'name': domain_name})
elif orig_pool['type'] in ['scsi', 'iscsi']:
# SCSI and iSCSI always fall back to the storage pool 'default'
wok_log.warning(
f'cannot create new volume for clone in '
f"storage pool '{orig_pool_name}'; falling back to "
f"'default'"
)
new_pool_name = 'default'
new_pool = self.storagepool.lookup('default')
# if the pool 'default' cannot hold a new volume, raise
# an exception
if orig_vol['capacity'] > new_pool['available']:
domain_name = xpath_get_text(xml, XPATH_DOMAIN_NAME)[0]
raise InvalidOperation('KCHVM0034E', {'name': domain_name})
else:
# unexpected storage pool type
raise InvalidOperation(
'KCHPOOL0014E', {'type': orig_pool['type']})
# new volume name: -.
# e.g. 1234-5678-9012-3456-0.img
ext = os.path.splitext(path)[1]
new_vol_name = f'{uuid}-{i}{ext}'
task = self.storagevolume.clone(
orig_pool_name, orig_vol_name, new_name=new_vol_name
)
self.task.wait(task['id'], 3600) # 1 h
# get the new volume path and update the XML descriptor
new_vol = self.storagevolume.lookup(new_pool_name, new_vol_name)
xml = xml_item_update(
xml, XPATH_DOMAIN_DISK_BY_FILE % path, new_vol['path'], 'file'
)
# remove the new volume should an error occur later
rollback.prependDefer(
self.storagevolume.delete, new_pool_name, new_vol_name
)
return xml
def _clone_update_objstore(self, old_uuid, new_uuid, rollback):
"""Update Kimchi's object store with the cloning VM.
Arguments:
old_uuid -- The UUID of the original VM.
new_uuid -- The UUID of the new, clonning VM.
rollback -- A rollback context so the object store entry can be removed
if an error occurs during the cloning operation.
"""
with self.objstore as session:
try:
vm = session.get('vm', old_uuid)
icon = vm['icon']
session.store('vm', new_uuid, {
'icon': icon}, get_kimchi_version())
except NotFoundError:
# if we cannot find an object store entry for the original VM,
# don't store one with an empty value.
pass
else:
# we need to define a custom function to prepend to the
# rollback context because the object store session needs to be
# opened and closed correctly (i.e. "prependDefer" only
# accepts one command at a time but we need more than one to
# handle an object store).
def _rollback_objstore():
with self.objstore as session_rb:
session_rb.delete('vm', new_uuid, ignore_missing=True)
# remove the new object store entry should an error occur later
rollback.prependDefer(_rollback_objstore)
def _build_access_elem(self, dom, users, groups):
auth = config.get('authentication', 'method')
access_xml = get_metadata_node(dom, 'access')
auth_elem = None
if not access_xml:
# there is no metadata element 'access'
access_elem = E.access()
else:
access_elem = ET.fromstring(access_xml)
same_auth = access_elem.xpath(f'./auth[@type="{auth}"]')
if len(same_auth) > 0:
# there is already a sub-element 'auth' with the same type;
# update it.
auth_elem = same_auth[0]
if users is not None:
for u in auth_elem.findall('user'):
auth_elem.remove(u)
if groups is not None:
for g in auth_elem.findall('group'):
auth_elem.remove(g)
if auth_elem is None:
# there is no sub-element 'auth' with the same type
# (or no 'auth' at all); create it.
auth_elem = E.auth(type=auth)
access_elem.append(auth_elem)
if users is not None:
for u in users:
auth_elem.append(E.user(u))
if groups is not None:
for g in groups:
auth_elem.append(E.group(g))
return access_elem
def _vm_update_access_metadata(self, dom, params):
users = groups = None
if 'users' in params:
users = params['users']
for user in users:
if not self.users.validate(user):
raise InvalidParameter('KCHVM0027E', {'users': user})
if 'groups' in params:
groups = params['groups']
for group in groups:
if not self.groups.validate(group):
raise InvalidParameter('KCHVM0028E', {'groups': group})
if users is None and groups is None:
return
node = self._build_access_elem(dom, users, groups)
set_metadata_node(dom, [node])
def _get_access_info(self, dom):
users = groups = list()
access_xml = get_metadata_node(
dom, 'access') or """"""
access_info = dictize(access_xml)
auth = config.get('authentication', 'method')
if 'auth' in access_info['access'] and (
'type' in access_info['access']['auth']
or len(access_info['access']['auth']) > 1
):
users = xpath_get_text(
access_xml, f"/access/auth[@type='{auth}']/user")
groups = xpath_get_text(
access_xml, f"/access/auth[@type='{auth}']/group")
elif auth == 'pam':
# Compatible to old permission tagging
users = xpath_get_text(access_xml, '/access/user')
groups = xpath_get_text(access_xml, '/access/group')
return users, groups
@staticmethod
def vm_get_os_metadata(dom):
os_xml = get_metadata_node(dom, 'os') or """"""
os_elem = ET.fromstring(os_xml)
return (os_elem.attrib.get('version'), os_elem.attrib.get('distro'))
def _update_graphics(self, dom, params):
root = objectify.fromstring(dom.XMLDesc(0))
graphics = root.devices.find('graphics')
if graphics is None:
return dom
password = params['graphics'].get('passwd')
if password is not None and len(password.strip()) == 0:
password = ''.join(random.sample(
string.ascii_letters + string.digits, 8))
if password is not None:
graphics.attrib['passwd'] = password
expire = params['graphics'].get('passwdValidTo')
to = graphics.attrib.get('passwdValidTo')
if to is not None:
if time.mktime(time.strptime(to, '%Y-%m-%dT%H:%M:%S')) - time.time() <= 0:
expire = expire if expire is not None else 30
if expire is not None:
expire_time = time.gmtime(time.time() + float(expire))
valid_to = time.strftime('%Y-%m-%dT%H:%M:%S', expire_time)
graphics.attrib['passwdValidTo'] = valid_to
gtype = params['graphics'].get('type')
if gtype is not None:
graphics.attrib['type'] = gtype
conn = self.conn.get()
if not dom.isActive():
return conn.defineXML(ET.tostring(root, encoding='unicode'))
xml = dom.XMLDesc(libvirt.VIR_DOMAIN_XML_SECURE)
dom.updateDeviceFlags(
etree.tostring(graphics).decode(
'utf-8'), libvirt.VIR_DOMAIN_AFFECT_LIVE
)
return conn.defineXML(xml)
def _backup_snapshots(self, snap, all_info):
""" Append "snap" and the children of "snap" to the list "all_info".
The list *must* always contain the parent snapshots before their
children so the function "_redefine_snapshots" can work correctly.
Arguments:
snap -- a native domain snapshot.
all_info -- a list of dict keys:
"{'xml': , 'current': '}"
"""
all_info.append({'xml': snap.getXMLDesc(
0), 'current': snap.isCurrent(0)})
for child in snap.listAllChildren(0):
self._backup_snapshots(child, all_info)
def _redefine_snapshots(self, dom, all_info):
""" Restore the snapshots stored in "all_info" to the domain "dom".
Arguments:
dom -- the domain which will have its snapshots restored.
all_info -- a list of dict keys, as described in "_backup_snapshots",
containing the original snapshot information.
"""
for info in all_info:
flags = libvirt.VIR_DOMAIN_SNAPSHOT_CREATE_REDEFINE
if info['current']:
flags |= libvirt.VIR_DOMAIN_SNAPSHOT_CREATE_CURRENT
# Snapshot XML contains the VM xml from the time it was created.
# Thus VM name and uuid must be updated to current ones. Otherwise,
# when reverted, the vm name will be inconsistent.
name = dom.name()
uuid = dom.UUIDString()
xml = xml_item_update(info['xml'], XPATH_SNAP_VM_NAME, name, None)
xml = xml_item_update(xml, XPATH_SNAP_VM_UUID, uuid, None)
dom.snapshotCreateXML(xml, flags)
def _update_metadata_name(self, dom, nonascii_name):
if nonascii_name is not None:
set_metadata_node(dom, [E.name(nonascii_name)])
else:
remove_metadata_node(dom, 'name')
def _update_bootorder(self, xml, params):
# get element tree from xml
et = ET.fromstring(xml)
# get machine type
os = et.find('os')
# add new bootorder
if 'bootorder' in params:
# remove old order
[os.remove(device) for device in os.findall('boot')]
for device in get_bootorder_node(params['bootorder']):
os.append(device)
# update bootmenu
if params.get('bootmenu') is False:
[os.remove(bm) for bm in os.findall('bootmenu')]
elif params.get('bootmenu') is True:
os.append(get_bootmenu_node())
# update
return ET.tostring(et, encoding='unicode')
def _update_s390x_console(self, xml, params):
if xpath_get_text(xml, XPATH_DOMAIN_CONSOLE_TARGET):
# if console is defined, update console
return xml_item_update(
xml, XPATH_CONSOLE_TARGET, params.get('console'), 'type'
)
# if console is not defined earlier, add console
console = E.console(type='pty')
console.append(E.target(type=params.get('console'), port='0'))
et = ET.fromstring(xml)
devices = et.find('devices')
devices.append(console)
return ET.tostring(et, encoding='unicode')
def _update_title(self, new_xml, title):
if len(xpath_get_text(new_xml, XPATH_TITLE)) > 0:
new_xml = xml_item_update(
new_xml, XPATH_TITLE, title, None)
else:
et = ET.fromstring(new_xml)
et.append(E.title(title))
new_xml = ET.tostring(et, encoding='unicode')
return new_xml
def _update_description(self, new_xml, description):
if len(xpath_get_text(new_xml, XPATH_DESCRIPTION)) > 0:
new_xml = xml_item_update(
new_xml, XPATH_DESCRIPTION, description, None
)
else:
et = ET.fromstring(new_xml)
et.append(E.description(description))
new_xml = ET.tostring(et, encoding='unicode')
return new_xml
def _update_topology(self, dom, new_xml, topology):
sockets = str(topology['sockets'])
cores = str(topology['cores'])
threads = str(topology['threads'])
if self.has_topology(dom):
# topology is being updated
xpath = XPATH_TOPOLOGY
new_xml = xml_item_update(new_xml, xpath, sockets, 'sockets')
new_xml = xml_item_update(new_xml, xpath, cores, 'cores')
new_xml = xml_item_update(new_xml, xpath, threads, 'threads')
else:
# topology is being added
new_xml = xml_item_insert(
new_xml, XPATH_CPU, get_topology_xml(topology)
)
return new_xml
def _static_vm_update(self, vm_name, dom, params):
old_xml = new_xml = dom.XMLDesc(libvirt.VIR_DOMAIN_XML_SECURE)
params = copy.deepcopy(params)
# Update name
name = params.get('name')
nonascii_name = None
if name is not None:
name, nonascii_name = get_ascii_nonascii_name(name)
new_xml = xml_item_update(new_xml, XPATH_NAME, name, None)
if 'title' in params:
new_xml = self._update_title(new_xml, params['title'])
if 'description' in params:
new_xml = self._update_description(new_xml, params['description'])
# Update CPU info
cpu_info = params.get('cpu_info', {})
cpu_info = self._update_cpu_info(new_xml, dom, cpu_info)
vcpus = str(cpu_info['vcpus'])
new_xml = xml_item_update(new_xml, XPATH_VCPU, vcpus, 'current')
maxvcpus = str(cpu_info['maxvcpus'])
new_xml = xml_item_update(new_xml, XPATH_VCPU, maxvcpus, None)
topology = cpu_info['topology']
if topology:
new_xml = self._update_topology(dom, new_xml, topology)
elif self.has_topology(dom):
# topology is being undefined: remove it
new_xml = xml_item_remove(new_xml, XPATH_TOPOLOGY)
# Updating memory
if 'memory' in params and params['memory'] != {}:
new_xml = self._update_memory_config(new_xml, params, dom)
# update bootorder or bootmenu
if 'bootorder' in params or 'bootmenu' in params:
new_xml = self._update_bootorder(new_xml, params)
if platform.machine() in ['s390', 's390x'] and params.get('console'):
new_xml = self._update_s390x_console(new_xml, params)
snapshots_info = []
conn = self.conn.get()
try:
if 'name' in params:
lflags = libvirt.VIR_DOMAIN_SNAPSHOT_LIST_ROOTS
dflags = (
libvirt.VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN
| libvirt.VIR_DOMAIN_SNAPSHOT_DELETE_METADATA_ONLY
)
for virt_snap in dom.listAllSnapshots(lflags):
snapshots_info.append(
{
'xml': virt_snap.getXMLDesc(0),
'current': virt_snap.isCurrent(0),
}
)
self._backup_snapshots(virt_snap, snapshots_info)
virt_snap.delete(dflags)
# Undefine old vm, only if name is going to change
dom.undefine()
new_xml = new_xml.decode(
'utf-8') if isinstance(new_xml, bytes) else new_xml
dom = conn.defineXML(new_xml)
self._update_metadata_name(dom, nonascii_name)
if 'name' in params:
self._redefine_snapshots(dom, snapshots_info)
except libvirt.libvirtError as e:
dom = conn.defineXML(old_xml)
if 'name' in params:
self._redefine_snapshots(dom, snapshots_info)
raise OperationFailed(
'KCHVM0008E', {'name': vm_name, 'err': e.get_error_message()}
)
if name is not None:
vm_name = name
return nonascii_name if nonascii_name is not None else vm_name, dom
def _get_new_memory(self, root, newMem, oldMem, memDevs):
memDevsAmount = self._get_mem_dev_total_size(
ET.tostring(root, encoding='unicode'))
if newMem > (oldMem << 10):
return newMem - memDevsAmount
if newMem < (oldMem << 10):
memDevs.reverse()
totRemoved = 0
for dev in memDevs:
size = dev.find('./target/size')
totRemoved += int(
convert_data_size(size.text, size.get('unit'), 'KiB')
)
root.find('./devices').remove(dev)
if ((oldMem << 10) - totRemoved) <= newMem:
return newMem - self._get_mem_dev_total_size(
ET.tostring(root, encoding='unicode')
)
if newMem == (oldMem << 10):
return newMem - memDevsAmount
def _set_max_memory(self, root, newMem, newMaxMem, maxMemTag):
# Conditions:
if (maxMemTag is None) and (newMem != newMaxMem):
# Creates the maxMemory tag
max_mem_xml = E.maxMemory(
str(newMaxMem), unit='Kib', slots=str(defaults['mem_dev_slots'])
)
root.insert(0, max_mem_xml)
elif (maxMemTag is None) and (newMem == newMaxMem):
# Nothing to do
pass
elif (maxMemTag is not None) and (newMem != newMaxMem):
# Just update value in max memory tag
maxMemTag.text = str(newMaxMem)
elif (maxMemTag is not None) and (newMem == newMaxMem):
if self._get_mem_dev_total_size(ET.tostring(root, encoding='unicode')) == 0:
# Remove the tag
root.remove(maxMemTag)
else:
maxMemTag.text = str(newMaxMem)
return root, maxMemTag
def _update_memory_config(self, xml, params, dom):
# Cannot pass max memory if there is not support to memory hotplug
# Then set max memory as memory, just to continue with the update
if not self.caps.mem_hotplug_support:
if 'maxmemory' in params['memory']:
raise InvalidOperation('KCHVM0046E')
else:
params['memory']['maxmemory'] = params['memory']['current']
root = ET.fromstring(xml)
# MiB to KiB
hasMem = 'current' in params['memory']
hasMaxMem = 'maxmemory' in params['memory']
oldMem = int(xpath_get_text(xml, XPATH_DOMAIN_MEMORY)[0]) >> 10
maxMemTag = root.find(XPATH_MAX_MEMORY)
if maxMemTag is not None:
oldMaxMem = int(xpath_get_text(xml, XPATH_MAX_MEMORY)[0]) >> 10
else:
oldMaxMem = oldMem
newMem = (params['memory'].get('current', oldMem)) << 10
newMaxMem = (params['memory'].get('maxmemory', oldMaxMem)) << 10
validate_memory(
{'current': newMem >> 10, 'maxmemory': newMaxMem >> 10})
# Adjust memory devices to new memory, if necessary
memDevs = root.findall('./devices/memory')
if len(memDevs) != 0 and hasMem:
newMem = self._get_new_memory(root, newMem, oldMem, memDevs)
# There is an issue in Libvirt/Qemu, where Guest does not start if
# memory and max memory are the same. So we decided to remove max
# memory and only add it if user explicitly provides it, willing to
# do memory hotplug
if hasMaxMem:
root, maxMemTag = self._set_max_memory(
root, newMem, newMaxMem, maxMemTag)
# Update memory, if necessary
if hasMem:
# Remove currentMemory, automatically set later by libvirt, with
# memory value
currentMem = root.find('.currentMemory')
if currentMem is not None:
root.remove(currentMem)
memory = root.find('.memory')
# Set NUMA parameterers if necessary. NUMA is not required for CPU
# and Memory hotplug anymore on PowerPC systems
if has_cpu_numa(dom):
if memory is not None:
# Libvirt is going to set the value automatically with
# the value configured in NUMA tag
root.remove(memory)
root = set_numa_memory(newMem, root)
else:
# update the memory tag directly
if memory is not None:
memory.text = str(newMem)
if (maxMemTag is not None) and (not hasMaxMem):
if newMem == newMaxMem and (
self._get_mem_dev_total_size(
ET.tostring(root, encoding='unicode')) == 0
):
root.remove(maxMemTag)
# Setting memory hard limit to max_memory + 1GiB
memtune = root.find('memtune')
if memtune is not None:
hl = memtune.find('hard_limit')
if hl is not None:
memtune.remove(hl)
memtune.insert(0, E.hard_limit(
str(newMaxMem + 1048576), unit='Kib'))
return ET.tostring(root, encoding='unicode')
def get_vm_cpu_cores(self, vm_xml):
return xpath_get_text(vm_xml, XPATH_TOPOLOGY + '/@cores')[0]
def get_vm_cpu_sockets(self, vm_xml):
return xpath_get_text(vm_xml, XPATH_TOPOLOGY + '/@sockets')[0]
def get_vm_cpu_threads(self, vm_xml):
return xpath_get_text(vm_xml, XPATH_TOPOLOGY + '/@threads')[0]
def get_vm_cpu_topology(self, dom):
topology = {}
if self.has_topology(dom):
sockets = int(self.get_vm_cpu_sockets(dom.XMLDesc(0)))
cores = int(self.get_vm_cpu_cores(dom.XMLDesc(0)))
threads = int(self.get_vm_cpu_threads(dom.XMLDesc(0)))
topology = {'sockets': sockets, 'cores': cores, 'threads': threads}
return topology
def _update_cpu_info(self, new_xml, dom, new_info):
topology = self.get_vm_cpu_topology(dom)
# if current is not defined in vcpu, vcpus is equal to maxvcpus
xml_maxvcpus = xpath_get_text(new_xml, 'vcpu')
maxvcpus = int(xml_maxvcpus[0])
xml_vcpus = xpath_get_text(new_xml, './vcpu/@current')
vcpus = int(xml_vcpus[0]) if xml_vcpus else maxvcpus
cpu_info = {'maxvcpus': maxvcpus, 'vcpus': vcpus, 'topology': topology}
cpu_info.update(new_info)
# Revalidate cpu info - may raise CPUInfo exceptions
cpu_model = CPUInfoModel(conn=self.conn)
cpu_model.check_cpu_info(cpu_info)
return cpu_info
def _live_vm_update(self, dom, params):
# Memory Hotplug/Unplug
if ('memory' in params) and ('current' in params['memory']):
self._update_memory_live(dom, params)
if 'vcpus' in params.get('cpu_info', {}):
self.cpu_hotplug_precheck(dom, params)
vcpus = params['cpu_info'].get('vcpus')
self.update_cpu_live(dom, vcpus)
def cpu_hotplug_precheck(self, dom, params):
if ('maxvcpus' in params['cpu_info']) or ('topology' in params['cpu_info']):
raise InvalidParameter('KCHCPUHOTP0001E')
topology = self.get_vm_cpu_topology(dom)
xml_maxvcpus = xpath_get_text(dom.XMLDesc(0), 'vcpu')
maxvcpus = int(xml_maxvcpus[0])
vcpus = params['cpu_info'].get('vcpus')
cpu_info = {'maxvcpus': maxvcpus, 'vcpus': vcpus, 'topology': topology}
cpu_model = CPUInfoModel(conn=self.conn)
cpu_model.check_cpu_info(cpu_info)
def update_cpu_live(self, dom, vcpus):
flags = libvirt.VIR_DOMAIN_AFFECT_LIVE | libvirt.VIR_DOMAIN_AFFECT_CONFIG
try:
dom.setVcpusFlags(vcpus, flags)
except libvirt.libvirtError as e:
raise OperationFailed('KCHCPUHOTP0002E', {'err': str(e)})
def _get_mem_dev_total_size(self, xml):
root = ET.fromstring(xml)
totMemDevs = 0
for size in root.findall('./devices/memory/target/size'):
totMemDevs += convert_data_size(size.text, size.get('unit'), 'KiB')
return int(totMemDevs)
def _update_memory_live(self, dom, params):
# Check if host supports memory device
if not self.caps.mem_hotplug_support:
raise InvalidOperation('KCHVM0046E')
xml = dom.XMLDesc(0)
max_mem = xpath_get_text(xml, './maxMemory')
if max_mem == []:
raise InvalidOperation('KCHVM0042E', {'name': dom.name()})
new_mem = params['memory']['current']
old_mem = int(xpath_get_text(xml, XPATH_DOMAIN_MEMORY)[0]) >> 10
memory = new_mem - old_mem
flags = libvirt.VIR_DOMAIN_MEM_CONFIG | libvirt.VIR_DOMAIN_MEM_LIVE
if platform.machine().startswith('ppc'):
# make sure memory is alingned in 256MiB in PowerPC
if new_mem % PPC_MEM_ALIGN != 0:
raise InvalidParameter(
'KCHVM0071E',
{
'param': 'Memory',
'mem': str(new_mem),
'alignment': str(PPC_MEM_ALIGN),
},
)
# Check number of slots supported
if (
len(xpath_get_text(xml, './devices/memory'))
== MEM_DEV_SLOTS[os.uname()[4]]
):
raise InvalidOperation('KCHVM0045E')
if memory == 0:
# Nothing to do
return
if memory < 0:
raise InvalidOperation('KCHVM0043E')
# Finally HotPlug operation ( memory > 0 )
try:
# Create memory device xml
tmp_xml = E.memory(
E.target(E.size(str(memory), unit='MiB')), model='dimm')
if has_cpu_numa(dom):
tmp_xml.find('target').append(E.node('0'))
dom.attachDeviceFlags(etree.tostring(
tmp_xml.decode('utf-8')), flags)
except Exception as e:
raise OperationFailed('KCHVM0047E', {'error': str(e)})
def _has_video(self, dom):
dom = ElementTree.fromstring(dom.XMLDesc(0))
return dom.find('devices/video') is not None
def _update_guest_stats(self, name):
try:
dom = VMModel.get_vm(name, self.conn)
vm_uuid = dom.UUIDString()
info = dom.info()
state = DOM_STATE_MAP[info[0]]
if state != 'running':
self.stats[vm_uuid] = {}
return
if self.stats.get(vm_uuid, None) is None:
self.stats[vm_uuid] = {}
timestamp = time.time()
prevStats = self.stats.get(vm_uuid, {})
seconds = timestamp - prevStats.get('timestamp', 0)
self.stats[vm_uuid].update({'timestamp': timestamp})
self._get_percentage_cpu_usage(vm_uuid, info, seconds)
self._get_percentage_mem_usage(vm_uuid, dom, seconds)
self._get_network_io_rate(vm_uuid, dom, seconds)
self._get_disk_io_rate(vm_uuid, dom, seconds)
except Exception as e:
# VM might be deleted just after we get the list.
# This is OK, just skip.
wok_log.debug(f'Error processing VM stats: {e}')
def _get_percentage_cpu_usage(self, vm_uuid, info, seconds):
prevCpuTime = self.stats[vm_uuid].get('cputime', 0)
cpus = info[3]
cpuTime = info[4] - prevCpuTime
base = ((cpuTime) * 100.0) / (seconds * 1000.0 * 1000.0 * 1000.0)
percentage = max(0.0, min(100.0, base / cpus))
self.stats[vm_uuid].update({'cputime': info[4], 'cpu': percentage})
def _get_percentage_mem_usage(self, vm_uuid, dom, seconds):
# Get the guest's memory stats
memStats = dom.memoryStats()
if ('available' in memStats) and ('unused' in memStats):
memUsed = memStats.get('available') - memStats.get('unused')
percentage = (memUsed * 100.0) / memStats.get('available')
elif ('rss' in memStats) and ('actual' in memStats):
percentage = memStats.get('rss') * 100.0 / memStats.get('actual')
else:
wok_log.error('Failed to measure memory usage of the guest.')
percentage = max(0.0, min(100.0, percentage))
self.stats[vm_uuid].update({'mem_usage': percentage})
def _get_network_io_rate(self, vm_uuid, dom, seconds):
prevNetRxKB = self.stats[vm_uuid].get('netRxKB', 0)
prevNetTxKB = self.stats[vm_uuid].get('netTxKB', 0)
currentMaxNetRate = self.stats[vm_uuid].get('max_net_io', 100)
rx_bytes = 0
tx_bytes = 0
tree = ElementTree.fromstring(dom.XMLDesc(0))
for target in tree.findall('devices/interface/target'):
dev = target.get('dev')
io = dom.interfaceStats(dev)
rx_bytes += io[0]
tx_bytes += io[4]
netRxKB = float(rx_bytes) / 1000
netTxKB = float(tx_bytes) / 1000
rx_stats = (netRxKB - prevNetRxKB) / seconds
tx_stats = (netTxKB - prevNetTxKB) / seconds
rate = rx_stats + tx_stats
max_net_io = round(max(currentMaxNetRate, int(rate)), 1)
self.stats[vm_uuid].update(
{
'net_io': rate,
'max_net_io': max_net_io,
'netRxKB': netRxKB,
'netTxKB': netTxKB,
}
)
def _get_disk_io_rate(self, vm_uuid, dom, seconds):
prevDiskRdKB = self.stats[vm_uuid].get('diskRdKB', 0)
prevDiskWrKB = self.stats[vm_uuid].get('diskWrKB', 0)
currentMaxDiskRate = self.stats[vm_uuid].get('max_disk_io', 100)
rd_bytes = 0
wr_bytes = 0
tree = ElementTree.fromstring(dom.XMLDesc(0))
for target in tree.findall('devices/disk/target'):
dev = target.get('dev')
io = dom.blockStats(dev)
rd_bytes += io[1]
wr_bytes += io[3]
diskRdKB = float(rd_bytes) / 1024
diskWrKB = float(wr_bytes) / 1024
rd_stats = (diskRdKB - prevDiskRdKB) / seconds
wr_stats = (diskWrKB - prevDiskWrKB) / seconds
rate = rd_stats + wr_stats
max_disk_io = round(max(currentMaxDiskRate, int(rate)), 1)
self.stats[vm_uuid].update(
{
'disk_io': rate,
'max_disk_io': max_disk_io,
'diskRdKB': diskRdKB,
'diskWrKB': diskWrKB,
}
)
def lookup(self, name):
dom = self.get_vm(name, self.conn)
try:
# Avoid race condition, where guests may be deleted before below
# command.
info = dom.info()
except libvirt.libvirtError as e:
wok_log.error(
f'Operation error while retrieving virtual machine '
f'"{name}" information: {e}'
)
raise OperationFailed('KCHVM0009E', {'name': name, 'err': str(e)})
state = DOM_STATE_MAP[info[0]]
screenshot = None
# (type, listen, port, passwd, passwdValidTo)
graphics = self.get_graphics(name, self.conn)
graphics_port = graphics[2]
graphics_port = graphics_port if state == 'running' else None
# only take a screenshot if configured to do so
take_screenshot = kimchi_config.get('kimchi', {}).get('take_screenshot', True)
try:
if take_screenshot and state == 'running' and self._has_video(dom):
screenshot = self.vmscreenshot.lookup(name)
elif state == 'shutoff':
# reset vm stats when it is powered off to avoid sending
# incorrect (old) data
self.stats[dom.UUIDString()] = {}
except NotFoundError:
pass
with self.objstore as session:
try:
extra_info = session.get('vm', dom.UUIDString(), True)
except NotFoundError:
extra_info = {}
icon = extra_info.get('icon')
self._update_guest_stats(name)
vm_stats = self.stats.get(dom.UUIDString(), {})
res = {}
res['cpu_utilization'] = vm_stats.get('cpu', 0)
res['mem_utilization'] = vm_stats.get('mem_usage', 0)
res['net_throughput'] = vm_stats.get('net_io', 0)
res['net_throughput_peak'] = vm_stats.get('max_net_io', 100)
res['io_throughput'] = vm_stats.get('disk_io', 0)
res['io_throughput_peak'] = vm_stats.get('max_disk_io', 100)
users, groups = self._get_access_info(dom)
xml = dom.XMLDesc(0)
maxvcpus = int(xpath_get_text(xml, XPATH_VCPU)[0])
cpu_info = {'vcpus': info[3], 'maxvcpus': maxvcpus, 'topology': {}}
if self.has_topology(dom):
sockets = int(xpath_get_text(xml, XPATH_TOPOLOGY + '/@sockets')[0])
cores = int(xpath_get_text(xml, XPATH_TOPOLOGY + '/@cores')[0])
threads = int(xpath_get_text(xml, XPATH_TOPOLOGY + '/@threads')[0])
cpu_info['topology'] = {
'sockets': sockets,
'cores': cores,
'threads': threads,
}
# Kimchi does not make use of 'currentMemory' tag, it only updates
# NUMA memory config or 'memory' tag directly. In memory hotplug,
# Libvirt always updates 'memory', so we can use this tag retrieving
# from Libvirt API maxMemory() function, regardeless of the VM state
# Case VM changed currentMemory outside Kimchi, sum mem devs
memory = dom.maxMemory() >> 10
curr_mem = info[2] >> 10
# On CentOS, dom.info does not retrieve memory. So, if machine does
# not have memory hotplug, parse memory from xml
if curr_mem == 0:
curr_mem = int(xpath_get_text(xml, XPATH_MEMORY)[0]) >> 10
if memory != curr_mem:
memory = curr_mem + (self._get_mem_dev_total_size(xml) >> 10)
# assure there is no zombie process left
for proc in self._serial_procs[:]:
if not proc.is_alive():
proc.join(1)
self._serial_procs.remove(proc)
# Get max memory, or return "memory" if not set
maxmemory = xpath_get_text(xml, XPATH_MAX_MEMORY)
if len(maxmemory) > 0:
maxmemory = convert_data_size(maxmemory[0], 'KiB', 'MiB')
else:
maxmemory = memory
# get boot order and bootmenu
boot = xpath_get_text(xml, XPATH_BOOT)
bootmenu = 'yes' if 'yes' in xpath_get_text(
xml, XPATH_BOOTMENU) else 'no'
vm_info = {
'name': name,
'title': ''.join(xpath_get_text(xml, XPATH_TITLE)),
'description': ''.join(xpath_get_text(xml, XPATH_DESCRIPTION)),
'state': state,
'stats': res,
'uuid': dom.UUIDString(),
'memory': {'current': memory, 'maxmemory': maxmemory},
'cpu_info': cpu_info,
'screenshot': screenshot,
'icon': icon,
# (type, listen, port, passwd, passwdValidTo)
'graphics': {
'type': graphics[0],
'listen': graphics[1],
'port': graphics_port,
'passwd': graphics[3],
'passwdValidTo': graphics[4],
},
'users': users,
'groups': groups,
'access': 'full',
'persistent': True if dom.isPersistent() else False,
'bootorder': boot,
'bootmenu': bootmenu,
'autostart': dom.autostart(),
}
if platform.machine() in ['s390', 's390x']:
vm_console = xpath_get_text(xml, XPATH_DOMAIN_CONSOLE_TARGET)
vm_info['console'] = vm_console[0] if vm_console else ''
return vm_info
def _vm_get_disk_paths(self, dom):
xml = dom.XMLDesc(0)
xpath = "/domain/devices/disk[@device='disk']/source/@file"
return xpath_get_text(xml, xpath)
@staticmethod
def get_vm(name, conn):
def raise_exception(error_code):
if error_code == libvirt.VIR_ERR_NO_DOMAIN:
raise NotFoundError('KCHVM0002E', {'name': name})
else:
raise OperationFailed(
'KCHVM0009E', {'name': name, 'err': error_code})
conn = conn.get()
FeatureTests.disable_libvirt_error_logging()
try:
return conn.lookupByName(name)
except libvirt.libvirtError as e:
name, nonascii_name = get_ascii_nonascii_name(name)
if nonascii_name is None:
raise_exception(e.get_error_code())
try:
return conn.lookupByName(name)
except libvirt.libvirtError as e:
raise_exception(e.get_error_code())
FeatureTests.enable_libvirt_error_logging()
def delete(self, name):
conn = self.conn.get()
dom = self.get_vm(name, self.conn)
if not dom.isPersistent():
raise InvalidOperation('KCHVM0036E', {'name': name})
self._vmscreenshot_delete(dom.UUIDString())
paths = self._vm_get_disk_paths(dom)
info = self.lookup(name)
if info['state'] != 'shutoff':
self.poweroff(name)
# delete existing snapshots before deleting VM
# libvirt's Test driver does not support the function
# "virDomainListAllSnapshots", so "VMSnapshots.get_list" will raise
# "OperationFailed" in that case.
try:
snapshot_names = self.vmsnapshots.get_list(name)
except OperationFailed as e:
wok_log.error(
f'cannot list snapshots: {e}; ' f'skipping snapshot deleting...'
)
else:
for s in snapshot_names:
self.vmsnapshot.delete(name, s)
try:
dom.undefine()
except libvirt.libvirtError as e:
raise OperationFailed(
'KCHVM0021E', {'name': name, 'err': e.get_error_message()}
)
for path in paths:
try:
vol = conn.storageVolLookupByPath(path)
pool = vol.storagePoolLookupByVolume()
xml = pool.XMLDesc(0)
pool_type = xpath_get_text(xml, '/pool/@type')[0]
if pool_type not in READONLY_POOL_TYPE:
vol.delete(0)
except libvirt.libvirtError as e:
wok_log.error(f'Unable to get storage volume by path: {e}')
try:
if is_s390x() and os.path.exists(path):
os.remove(path)
except Exception as e:
wok_log.error(f'Unable to delete storage path: {e}')
except Exception as e:
raise OperationFailed('KCHVOL0017E', {'err': str(e)})
try:
with self.objstore as session:
session.delete('vm', dom.UUIDString(), ignore_missing=True)
except Exception as e:
# It is possible to delete vm without delete its database info
wok_log.error(f'Error deleting vm information from database: {e}')
websocket.remove_proxy_token(name)
def start(self, name):
# make sure the ISO file has read permission
dom = self.get_vm(name, self.conn)
xml = dom.XMLDesc(0)
xpath = "/domain/devices/disk[@device='cdrom']/source/@file"
isofiles = xpath_get_text(xml, xpath)
user = UserTests.probe_user()
for iso in isofiles:
run_setfacl_set_attr(iso, user=user)
dom = self.get_vm(name, self.conn)
# vm already running: return error 400
if DOM_STATE_MAP[dom.info()[0]] == 'running':
raise InvalidOperation('KCHVM0048E', {'name': name})
try:
dom.create()
except libvirt.libvirtError as e:
raise OperationFailed(
'KCHVM0019E', {'name': name, 'err': e.get_error_message()}
)
def poweroff(self, name):
dom = self.get_vm(name, self.conn)
# vm already powered off: return error 400
if DOM_STATE_MAP[dom.info()[0]] == 'shutoff':
raise InvalidOperation('KCHVM0049E', {'name': name})
try:
dom.destroy()
except libvirt.libvirtError as e:
raise OperationFailed(
'KCHVM0020E', {'name': name, 'err': e.get_error_message()}
)
def shutdown(self, name):
dom = self.get_vm(name, self.conn)
# vm already powered off: return error 400
if DOM_STATE_MAP[dom.info()[0]] == 'shutoff':
raise InvalidOperation('KCHVM0050E', {'name': name})
try:
dom.shutdown()
except libvirt.libvirtError as e:
raise OperationFailed(
'KCHVM0029E', {'name': name, 'err': e.get_error_message()}
)
def reset(self, name):
dom = self.get_vm(name, self.conn)
# vm already powered off: return error 400
if DOM_STATE_MAP[dom.info()[0]] == 'shutoff':
raise InvalidOperation('KCHVM0051E', {'name': name})
try:
dom.reset(flags=0)
except libvirt.libvirtError as e:
raise OperationFailed(
'KCHVM0022E', {'name': name, 'err': e.get_error_message()}
)
def _vm_check_serial(self, name):
dom = self.get_vm(name, self.conn)
xml = dom.XMLDesc(libvirt.VIR_DOMAIN_XML_SECURE)
expr = '/domain/devices/serial/@type'
# on s390x serial is not supported
if platform.machine() != 's390x' and not xpath_get_text(xml, expr):
return False
expr = '/domain/devices/console/@type'
if not xpath_get_text(xml, expr):
return False
return True
@staticmethod
def get_graphics(name, conn):
dom = VMModel.get_vm(name, conn)
xml = dom.XMLDesc(libvirt.VIR_DOMAIN_XML_SECURE)
expr = '/domain/devices/graphics/@type'
res = xpath_get_text(xml, expr)
graphics_type = res[0] if res else None
expr = '/domain/devices/graphics/@listen'
res = xpath_get_text(xml, expr)
graphics_listen = res[0] if res else None
graphics_port = graphics_passwd = graphics_passwdValidTo = None
if graphics_type:
expr = "/domain/devices/graphics[@type='%s']/@port"
res = xpath_get_text(xml, expr % graphics_type)
graphics_port = int(res[0]) if res else None
expr = "/domain/devices/graphics[@type='%s']/@passwd"
res = xpath_get_text(xml, expr % graphics_type)
graphics_passwd = res[0] if res else None
expr = "/domain/devices/graphics[@type='%s']/@passwdValidTo"
res = xpath_get_text(xml, expr % graphics_type)
if res:
to = time.mktime(time.strptime(res[0], '%Y-%m-%dT%H:%M:%S'))
graphics_passwdValidTo = to - time.mktime(time.gmtime())
return (
graphics_type,
graphics_listen,
graphics_port,
graphics_passwd,
graphics_passwdValidTo,
)
def serial(self, name):
if not self._vm_check_serial(name):
raise OperationFailed('KCHVM0076E', {'name': name})
if not os.path.isdir(serialconsole.BASE_DIRECTORY):
try:
os.mkdir(serialconsole.BASE_DIRECTORY)
except OSError:
raise OperationFailed(
'KCHVM0081E', {'dir': serialconsole.BASE_DIRECTORY}
)
websocket.add_proxy_token(
name +
'-console', os.path.join(serialconsole.BASE_DIRECTORY, name), True
)
try:
proc = serialconsole.main(name, self.conn.get().getURI())
proc.join(2)
if not proc.is_alive():
raise OperationFailed('KCHVM0082E', {'name': name})
self._serial_procs.append(proc)
except OperationFailed:
raise
except Exception as e:
wok_log.error(str(e))
raise OperationFailed('KCHVM0077E', {'name': name})
def connect(self, name):
# (type, listen, port, passwd, passwdValidTo)
graphics_port = self.get_graphics(name, self.conn)[2]
if graphics_port is not None:
websocket.add_proxy_token(name, graphics_port)
else:
raise OperationFailed('KCHVM0010E', {'name': name})
def _vmscreenshot_delete(self, vm_uuid):
screenshot = VMScreenshotModel.get_screenshot(
vm_uuid, self.objstore, self.conn)
screenshot.delete()
try:
with self.objstore as session:
session.delete('screenshot', vm_uuid)
except Exception as e:
# It is possible to continue Kimchi executions without delete
# screenshots
wok_log.error(
f'Error trying to delete vm screenshot from ' f'database due error: {e}'
)
def suspend(self, name):
"""Suspend the virtual machine's execution and puts it in the
state 'paused'. Use the function "resume" to restore its state.
If the VM is not running, an exception will be raised.
Parameters:
name -- the name of the VM to be suspended.
"""
vm = self.lookup(name)
if vm['state'] != 'running':
raise InvalidOperation('KCHVM0037E', {'name': name})
vir_dom = self.get_vm(name, self.conn)
try:
vir_dom.suspend()
except libvirt.libvirtError as e:
raise OperationFailed('KCHVM0038E', {'name': name, 'err': str(e)})
def resume(self, name):
"""Resume the virtual machine's execution and puts it in the
state 'running'. The VM should have been suspended previously by the
function "suspend" and be in the state 'paused', otherwise an exception
will be raised.
Parameters:
name -- the name of the VM to be resumed.
"""
vm = self.lookup(name)
if vm['state'] != 'paused':
raise InvalidOperation('KCHVM0039E', {'name': name})
vir_dom = self.get_vm(name, self.conn)
try:
vir_dom.resume()
except libvirt.libvirtError as e:
raise OperationFailed('KCHVM0040E', {'name': name, 'err': str(e)})
def _check_if_host_not_localhost(self, remote_host):
hostname = socket.gethostname()
if remote_host in ['localhost', '127.0.0.1', hostname]:
raise OperationFailed('KCHVM0055E', {'host': remote_host})
def _check_if_migrating_same_arch_hypervisor(self, remote_host, user='root'):
remote_conn = None
try:
remote_conn = self._get_remote_libvirt_conn(remote_host, user)
source_hyp = self.conn.get().getType()
dest_hyp = remote_conn.getType()
if source_hyp != dest_hyp:
raise OperationFailed(
'KCHVM0065E',
{'host': remote_host, 'srchyp': source_hyp, 'desthyp': dest_hyp},
)
source_arch = self.conn.get().getInfo()[0]
dest_arch = remote_conn.getInfo()[0]
if source_arch != dest_arch:
raise OperationFailed(
'KCHVM0064E',
{
'host': remote_host,
'srcarch': source_arch,
'destarch': dest_arch,
},
)
except Exception as e:
raise OperationFailed('KCHVM0066E', {'error': str(e)})
finally:
if remote_conn:
remote_conn.close()
def _check_ppc64_subcores_per_core(self, remote_host, user):
"""
Output expected from command-line:
$ ppc64_cpu --subcores-per-core
Subcores per core: N
"""
def _get_local_ppc64_subpercore():
local_cmd = ['ppc64_cpu', '--subcores-per-core']
out, err, returncode = run_command(local_cmd, 5, silent=True)
if returncode != 0:
return None
local_sub_per_core = out.strip()[-1]
return local_sub_per_core
def _get_remote_ppc64_subpercore(remote_host, user):
username_host = f'{user}@{remote_host}'
ssh_cmd = [
'ssh',
'-oNumberOfPasswordPrompts=0',
'-oStrictHostKeyChecking=no',
username_host,
'ppc64_cpu',
'--subcores-per-core',
]
out, err, returncode = run_command(ssh_cmd, 5, silent=True)
if returncode != 0:
return None
remote_sub_per_core = out.strip()[-1]
return remote_sub_per_core
local_sub_per_core = _get_local_ppc64_subpercore()
if local_sub_per_core is None:
return
remote_sub_per_core = _get_remote_ppc64_subpercore(remote_host, user)
if local_sub_per_core != remote_sub_per_core:
raise OperationFailed('KCHVM0067E', {'host': remote_host})
def _check_if_password_less_login_enabled(self, remote_host, user, password):
username_host = f'{user}@{remote_host}'
ssh_cmd = [
'ssh',
'-oNumberOfPasswordPrompts=0',
'-oStrictHostKeyChecking=no',
username_host,
'echo',
'hello',
]
stdout, stderr, returncode = run_command(ssh_cmd, 5, silent=True)
if returncode != 0:
if password is None:
raise OperationFailed(
'KCHVM0056E', {'host': remote_host, 'user': user})
else:
self._set_password_less_login(remote_host, user, password)
def _set_password_less_login(self, remote_host, user, passwd):
home_dir = '/root' if user == 'root' else f'/home/{user}'
id_rsa_file = f'{home_dir}/.ssh/id_rsa'
id_rsa_pub_file = id_rsa_file + '.pub'
ssh_port = 22
ssh_client = None
def read_id_rsa_pub_file():
data = None
with open(id_rsa_pub_file, 'r') as id_file:
data = id_file.read()
return data
def create_root_ssh_key_if_required():
if os.path.isfile(id_rsa_pub_file):
return
with open('/dev/zero') as zero_input:
cmd = ['ssh-keygen', '-q', '-N', '', '-f', id_rsa_file]
proc = subprocess.Popen(
cmd, stdin=zero_input, stdout=open(os.devnull, 'wb')
)
out, err = proc.communicate()
if not os.path.isfile(id_rsa_pub_file):
raise OperationFailed('KCHVM0070E')
if user != 'root':
id_rsa_content = read_id_rsa_pub_file()
updated_content = id_rsa_content.replace(
' root@', f' {user}@')
with open(id_rsa_pub_file, 'w+') as f:
f.write(updated_content)
user_uid = pwd.getpwnam(user).pw_uid
user_gid = pwd.getpwnam(user).pw_gid
os.chown(id_rsa_pub_file, user_uid, user_gid)
os.chown(id_rsa_file, user_uid, user_gid)
def get_ssh_client(remote_host, user, passwd):
ssh_client = paramiko.SSHClient()
ssh_client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh_client.connect(
remote_host, ssh_port, username=user, password=passwd, timeout=4
)
return ssh_client
def append_id_rsa_to_remote_authorized_keys(ssh_client, id_rsa_data):
sftp_client = ssh_client.open_sftp()
ssh_dir = f'{home_dir}/.ssh'
try:
sftp_client.chdir(ssh_dir)
except IOError:
raise OperationFailed(
'KCHVM0089E', {'host': remote_host,
'user': user, 'sshdir': ssh_dir}
)
file_handler = sftp_client.file(
f'{home_dir}/.ssh/authorized_keys', mode='a', bufsize=1
)
file_handler.write(id_rsa_data)
file_handler.flush()
file_handler.close()
sftp_client.close()
try:
create_root_ssh_key_if_required()
id_rsa_data = read_id_rsa_pub_file()
ssh_client = get_ssh_client(remote_host, user, passwd)
append_id_rsa_to_remote_authorized_keys(ssh_client, id_rsa_data)
except Exception as e:
raise OperationFailed(
'KCHVM0068E', {'host': remote_host,
'user': user, 'error': str(e)}
)
finally:
if ssh_client:
ssh_client.close()
def _check_remote_libvirt_conn(self, remote_host, user='root', transport='ssh'):
dest_uri = f'qemu+{transport}://{user}@{remote_host}/system'
cmd = ['virsh', '-c', dest_uri, 'list']
proc = subprocess.Popen(
cmd, stdout=subprocess.PIPE, shell=True, preexec_fn=os.setsid
)
timeout = 0
while proc.poll() is None:
time.sleep(1)
timeout += 1
if timeout == 5:
os.killpg(os.getpgid(proc.pid), signal.SIGTERM)
raise OperationFailed(
'KCHVM0090E', {'host': remote_host, 'user': user})
def _get_remote_libvirt_conn(self, remote_host, user='root', transport='ssh'):
dest_uri = f'qemu+{transport}://{user}@{remote_host}/system'
# TODO: verify why LibvirtConnection(dest_uri) does not work here
return libvirt.open(dest_uri)
def migration_pre_check(self, remote_host, user, password):
self._check_if_host_not_localhost(remote_host)
self._check_if_password_less_login_enabled(remote_host, user, password)
self._check_remote_libvirt_conn(remote_host, user)
self._check_if_migrating_same_arch_hypervisor(remote_host, user)
if platform.machine() in ['ppc64', 'ppc64le']:
self._check_ppc64_subcores_per_core(remote_host, user)
def _check_if_path_exists_in_remote_host(self, path, remote_host, user):
username_host = f'{user}@{remote_host}'
cmd = ['ssh', '-oStrictHostKeyChecking=no',
username_host, 'test', '-e', path]
_, _, returncode = run_command(cmd, 5, silent=True)
return returncode == 0
def _get_vm_devices_infos(self, vm_name):
dom = VMModel.get_vm(vm_name, self.conn)
infos = [
get_vm_disk_info(dom, dev_name) for dev_name in get_vm_disks(dom).keys()
]
return infos
def _check_if_nonshared_migration(self, vm_name, remote_host, user):
for dev_info in self._get_vm_devices_infos(vm_name):
dev_path = dev_info.get('path')
if not self._check_if_path_exists_in_remote_host(
dev_path, remote_host, user
):
return True
return False
def _create_remote_path(self, path, remote_host, user):
username_host = f'{user}@{remote_host}'
cmd = ['ssh', '-oStrictHostKeyChecking=no',
username_host, 'touch', path]
_, _, returncode = run_command(cmd, 5, silent=True)
if returncode != 0:
raise OperationFailed(
'KCHVM0061E', {'path': path, 'host': remote_host, 'user': user}
)
def _get_img_size(self, disk_path):
try:
conn = self.conn.get()
vol_obj = conn.storageVolLookupByPath(disk_path)
return vol_obj.info()[1]
except Exception as e:
raise OperationFailed(
'KCHVM0062E', {'path': disk_path, 'error': str(e)})
def _create_remote_disk(self, disk_info, remote_host, user):
username_host = f'{user}@{remote_host}'
disk_fmt = disk_info.get('format')
disk_path = disk_info.get('path')
disk_size = self._get_img_size(disk_path)
cmd = [
'ssh',
'-oStrictHostKeyChecking=no',
username_host,
'qemu-img',
'create',
'-f',
disk_fmt,
disk_path,
str(disk_size),
]
out, err, returncode = run_command(cmd, silent=True)
if returncode != 0:
raise OperationFailed(
'KCHVM0063E',
{'error': err, 'path': disk_path,
'host': remote_host, 'user': user},
)
def _create_vm_remote_paths(self, vm_name, remote_host, user):
for dev_info in self._get_vm_devices_infos(vm_name):
dev_path = dev_info.get('path')
if not self._check_if_path_exists_in_remote_host(
dev_path, remote_host, user
):
if dev_info.get('type') == 'cdrom':
self._create_remote_path(dev_path, remote_host, user)
else:
self._create_remote_disk(dev_info, remote_host, user)
def migrate(self, name, remote_host, user=None, password=None, enable_rdma=None):
name = name.decode('utf-8')
remote_host = remote_host.decode('utf-8')
if user is None:
user = 'root'
if enable_rdma is None:
enable_rdma = False
self.migration_pre_check(remote_host, user, password)
dest_conn = self._get_remote_libvirt_conn(remote_host, user)
non_shared = self._check_if_nonshared_migration(
name, remote_host, user)
params = {
'name': name,
'dest_conn': dest_conn,
'non_shared': non_shared,
'remote_host': remote_host,
'user': user,
'enable_rdma': enable_rdma,
}
task_id = AsyncTask(
f'/plugins/kimchi/vms/{name}/migrate', self._migrate_task, params
).id
return self.task.lookup(task_id)
def _migrate_task(self, cb, params):
name = params['name'].decode('utf-8')
dest_conn = params['dest_conn']
non_shared = params['non_shared']
remote_host = params['remote_host']
user = params['user']
enable_rdma = params['enable_rdma']
cb('starting a migration')
dom = self.get_vm(name, self.conn)
state = DOM_STATE_MAP[dom.info()[0]]
flags = libvirt.VIR_MIGRATE_PEER2PEER
if state == 'shutoff':
flags |= libvirt.VIR_MIGRATE_OFFLINE | libvirt.VIR_MIGRATE_PERSIST_DEST
elif state in ['running', 'paused']:
flags |= libvirt.VIR_MIGRATE_LIVE | libvirt.VIR_MIGRATE_TUNNELLED
if dom.isPersistent():
flags |= libvirt.VIR_MIGRATE_PERSIST_DEST
else:
dest_conn.close()
raise OperationFailed('KCHVM0057E', {'name': name, 'state': state})
if non_shared:
flags |= libvirt.VIR_MIGRATE_NON_SHARED_DISK
self._create_vm_remote_paths(name, remote_host, user)
try:
if enable_rdma:
param_uri = 'rdma://' + remote_host
dom.migrate(dest_conn, flags, uri=param_uri)
else:
dom.migrate(dest_conn, flags)
except libvirt.libvirtError as e:
cb('Migrate failed', False)
raise OperationFailed('KCHVM0058E', {'err': str(e), 'name': name})
finally:
dest_conn.close()
cb('Migrate finished', True)
class VMScreenshotModel(object):
def __init__(self, **kargs):
self.objstore = kargs['objstore']
self.conn = kargs['conn']
def lookup(self, name):
dom = VMModel.get_vm(name, self.conn)
d_info = dom.info()
vm_uuid = dom.UUIDString()
if DOM_STATE_MAP[d_info[0]] != 'running':
raise NotFoundError('KCHVM0004E', {'name': name})
screenshot = self.get_screenshot(vm_uuid, self.objstore, self.conn)
img_path = screenshot.lookup()
# screenshot info changed after scratch generation
try:
with self.objstore as session:
session.store(
'screenshot', vm_uuid, screenshot.info, get_kimchi_version()
)
except Exception as e:
# It is possible to continue Kimchi executions without store
# screenshots
wok_log.error(
f'Error trying to update database with guest '
f'screenshot information due error: {e}'
)
return img_path
@staticmethod
def get_screenshot(vm_uuid, objstore, conn):
try:
with objstore as session:
try:
params = session.get('screenshot', vm_uuid)
except NotFoundError:
params = {'uuid': vm_uuid}
session.store('screenshot', vm_uuid,
params, get_kimchi_version())
except Exception as e:
# The 'except' outside of 'with' is necessary to catch possible
# exception from '__exit__' when calling 'session.store'
# It is possible to continue Kimchi vm executions without
# screenshots
wok_log.error(
f'Error trying to update database with guest '
f'screenshot information due error:{e}'
)
return LibvirtVMScreenshot(params, conn)
class LibvirtVMScreenshot(VMScreenshot):
def __init__(self, vm_uuid, conn):
VMScreenshot.__init__(self, vm_uuid)
self.conn = conn
def _generate_scratch(self, thumbnail):
def handler(stream, buf, opaque):
fd = opaque
os.write(fd, buf)
fd = os.open(thumbnail, os.O_WRONLY | os.O_TRUNC | os.O_CREAT, 0o644)
try:
conn = self.conn.get()
dom = conn.lookupByUUIDString(self.vm_uuid)
vm_name = dom.name()
stream = conn.newStream(0)
dom.screenshot(stream, 0, 0)
stream.recvAll(handler, fd)
except libvirt.libvirtError:
try:
stream.abort()
except Exception:
pass
raise NotFoundError('KCHVM0006E', {'name': vm_name})
else:
stream.finish()
finally:
os.close(fd)
================================================
FILE: model/vmsnapshots.py
================================================
#
# Project Kimchi
#
# Copyright IBM Corp, 2015-2017
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
import time
import libvirt
import lxml.etree as ET
from lxml import objectify
from lxml.builder import E
from wok.asynctask import AsyncTask
from wok.exception import InvalidOperation
from wok.exception import NotFoundError
from wok.exception import OperationFailed
from wok.model.tasks import TaskModel
from wok.plugins.kimchi.model.vms import VMModel
from wok.plugins.kimchi.model.vmstorages import VMStorageModel
from wok.plugins.kimchi.model.vmstorages import VMStoragesModel
from wok.xmlutils.utils import xpath_get_text
class VMSnapshotsModel(object):
def __init__(self, **kargs):
self.conn = kargs['conn']
self.objstore = kargs['objstore']
self.task = TaskModel(**kargs)
self.vmstorages = VMStoragesModel(**kargs)
self.vmstorage = VMStorageModel(**kargs)
def create(self, vm_name, params=None):
"""Create a snapshot with the current domain state.
The VM must be stopped and contain only disks with format 'qcow2';
otherwise an exception will be raised.
Parameters:
vm_name -- the name of the VM where the snapshot will be created.
params -- a dict with the following values:
"name": The snapshot name (optional). If omitted, a default value
based on the current time will be used.
Return:
A Task running the operation.
"""
if params is None:
params = {}
# if the VM has a non-CDROM disk with type 'raw', abort.
for storage_name in self.vmstorages.get_list(vm_name):
storage = self.vmstorage.lookup(vm_name, storage_name)
type = storage['type']
format = storage['format']
if type != u'cdrom' and format != u'qcow2':
raise InvalidOperation(
'KCHSNAP0010E', {'vm': vm_name, 'format': format}
)
name = params.get('name', str(int(time.time())))
task_params = {'vm_name': vm_name, 'name': name}
taskid = AsyncTask(
u'/plugins/kimchi/vms/%s/snapshots/%s' % (vm_name, name),
self._create_task,
task_params,
).id
return self.task.lookup(taskid)
def _create_task(self, cb, params):
"""Asynchronous function which actually creates the snapshot.
Parameters:
cb -- a callback function to signal the Task's progress.
params -- a dict with the following values:
"vm_name": the name of the VM where the snapshot will be created.
"name": the snapshot name.
"""
vm_name = params['vm_name']
name = params['name']
cb('building snapshot XML')
root_elem = E.domainsnapshot()
root_elem.append(E.name(name))
xml = ET.tostring(root_elem, encoding='unicode')
try:
cb('fetching snapshot domain')
vir_dom = VMModel.get_vm(vm_name, self.conn)
cb('creating snapshot')
vir_dom.snapshotCreateXML(xml, 0)
except (NotFoundError, OperationFailed, libvirt.libvirtError) as e:
raise OperationFailed(
'KCHSNAP0002E', {'name': name, 'vm': vm_name, 'err': str(e)}
)
cb('OK', True)
def get_list(self, vm_name):
vir_dom = VMModel.get_vm(vm_name, self.conn)
try:
vir_snaps = vir_dom.listAllSnapshots(0)
return sorted([s.getName() for s in vir_snaps], key=str.lower)
except libvirt.libvirtError as e:
raise OperationFailed(
'KCHSNAP0005E', {'vm': vm_name, 'err': str(e)})
class VMSnapshotModel(object):
def __init__(self, **kargs):
self.conn = kargs['conn']
def lookup(self, vm_name, name):
vir_snap = self.get_vmsnapshot(vm_name, name)
try:
snap_xml_str = vir_snap.getXMLDesc(0)
except libvirt.libvirtError as e:
raise OperationFailed(
'KCHSNAP0004E', {'name': name, 'vm': vm_name, 'err': str(e)}
)
snap_xml = objectify.fromstring(snap_xml_str)
try:
parent = str(snap_xml.parent.name)
except AttributeError:
parent = u''
return {
'created': str(snap_xml.creationTime),
'name': str(snap_xml.name),
'parent': parent,
'state': str(snap_xml.state),
}
def delete(self, vm_name, name):
try:
vir_snap = self.get_vmsnapshot(vm_name, name)
vir_snap.delete(0)
except libvirt.libvirtError as e:
raise OperationFailed(
'KCHSNAP0006E', {'name': name, 'vm': vm_name, 'err': str(e)}
)
def revert(self, vm_name, name):
try:
vir_dom = VMModel.get_vm(vm_name, self.conn)
vir_snap = self.get_vmsnapshot(vm_name, name)
vir_dom.revertToSnapshot(vir_snap, 0)
# get vm name recorded in the snapshot and return new uri params
vm_new_name = xpath_get_text(
vir_snap.getXMLDesc(0), 'domain/name')[0]
return [vm_new_name, name]
except libvirt.libvirtError as e:
raise OperationFailed(
'KCHSNAP0009E', {'name': name, 'vm': vm_name, 'err': str(e)}
)
def get_vmsnapshot(self, vm_name, name):
vir_dom = VMModel.get_vm(vm_name, self.conn)
try:
return vir_dom.snapshotLookupByName(name, 0)
except libvirt.libvirtError as e:
code = e.get_error_code()
if code == libvirt.VIR_ERR_NO_DOMAIN_SNAPSHOT:
raise NotFoundError(
'KCHSNAP0003E', {'name': name, 'vm': vm_name})
else:
raise OperationFailed(
'KCHSNAP0004E', {'name': name,
'vm': vm_name, 'err': str(e)}
)
class CurrentVMSnapshotModel(object):
def __init__(self, **kargs):
self.conn = kargs['conn']
self.vmsnapshot = VMSnapshotModel(**kargs)
def lookup(self, vm_name):
vir_dom = VMModel.get_vm(vm_name, self.conn)
try:
vir_snap = vir_dom.snapshotCurrent(0)
snap_name = vir_snap.getName()
except libvirt.libvirtError as e:
if e.get_error_code() == libvirt.VIR_ERR_NO_DOMAIN_SNAPSHOT:
return {}
raise OperationFailed(
'KCHSNAP0008E', {'vm': vm_name, 'err': str(e)})
return self.vmsnapshot.lookup(vm_name, snap_name)
================================================
FILE: model/vmstorages.py
================================================
#
# Project Kimchi
#
# Copyright IBM Corp, 2015-2016
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
import os
import string
from lxml import etree
from wok.exception import InvalidOperation
from wok.exception import InvalidParameter
from wok.exception import NotFoundError
from wok.exception import OperationFailed
from wok.plugins.kimchi.model.config import CapabilitiesModel
from wok.plugins.kimchi.model.diskutils import get_disk_used_by
from wok.plugins.kimchi.model.storagevolumes import StorageVolumeModel
from wok.plugins.kimchi.model.utils import get_vm_config_flag
from wok.plugins.kimchi.model.vms import DOM_STATE_MAP
from wok.plugins.kimchi.model.vms import VMModel
from wok.plugins.kimchi.osinfo import lookup
from wok.plugins.kimchi.utils import create_disk_image
from wok.plugins.kimchi.utils import is_s390x
from wok.plugins.kimchi.xmlutils.disk import get_device_node
from wok.plugins.kimchi.xmlutils.disk import get_disk_xml
from wok.plugins.kimchi.xmlutils.disk import get_vm_disk_info
from wok.plugins.kimchi.xmlutils.disk import get_vm_disks
from wok.utils import wok_log
HOTPLUG_TYPE = ['scsi', 'virtio']
def _get_device_bus(dev_type, dom):
try:
version, distro = VMModel.vm_get_os_metadata(dom)
except Exception:
version, distro = ('unknown', 'unknown')
return lookup(distro, version)[dev_type + '_bus']
class VMStoragesModel(object):
def __init__(self, **kargs):
self.conn = kargs['conn']
self.objstore = kargs['objstore']
self.caps = CapabilitiesModel(**kargs)
def _get_available_bus_address(self, bus_type, vm_name):
if bus_type not in ['ide']:
return dict()
# libvirt limitation of just 1 ide controller
# each controller have at most 2 buses and each bus 2 units.
dom = VMModel.get_vm(vm_name, self.conn)
disks = self.get_list(vm_name)
valid_id = [('0', '0'), ('0', '1'), ('1', '0'), ('1', '1')]
controller_id = '0'
for dev_name in disks:
disk = get_device_node(dom, dev_name)
if disk.target.attrib['bus'] == 'ide':
controller_id = disk.address.attrib['controller']
bus_id = disk.address.attrib['bus']
unit_id = disk.address.attrib['unit']
if (bus_id, unit_id) in valid_id:
valid_id.remove((bus_id, unit_id))
continue
if not valid_id:
raise OperationFailed(
'KCHVMSTOR0014E', {'type': 'ide', 'limit': 4})
else:
address = {
'controller': controller_id,
'bus': valid_id[0][0],
'unit': valid_id[0][1],
}
return dict(address=address)
def create(self, vm_name, params):
# Path will never be blank due to API.json verification.
# There is no need to cover this case here.
if not ('vol' in params) ^ ('path' in params):
if not is_s390x():
raise InvalidParameter('KCHVMSTOR0017E')
if 'dir_path' not in params:
raise InvalidParameter('KCHVMSTOR0019E')
dom = VMModel.get_vm(vm_name, self.conn)
params['bus'] = _get_device_bus(params['type'], dom)
if is_s390x() and params['type'] == 'disk' and 'dir_path' in params:
if 'format' not in params:
raise InvalidParameter('KCHVMSTOR0020E')
size = params['size']
name = params['name']
dir_path = params.get('dir_path')
params['path'] = dir_path + '/' + name
if os.path.exists(params['path']):
raise InvalidParameter(
'KCHVMSTOR0021E', {'disk_path': params['path']})
create_disk_image(
format_type=params['format'], path=params['path'], capacity=size
)
else:
params['format'] = 'raw'
dev_list = [
dev for dev, bus in get_vm_disks(dom).items() if bus == params['bus']
]
dev_list.sort()
if len(dev_list) == 0:
params['index'] = 0
else:
char = dev_list.pop()[2]
params['index'] = string.ascii_lowercase.index(char) + 1
if (
params['bus'] not in HOTPLUG_TYPE and
DOM_STATE_MAP[dom.info()[0]] != 'shutoff'
):
raise InvalidOperation('KCHVMSTOR0011E')
if params.get('vol'):
vol_info = self._get_vol_info(params)
params['path'] = vol_info['path']
params['disk'] = vol_info['type']
params.update(self._get_available_bus_address(params['bus'], vm_name))
# Add device to VM
dev, xml = get_disk_xml(params)
try:
dom = VMModel.get_vm(vm_name, self.conn)
dom.attachDeviceFlags(xml, get_vm_config_flag(dom, 'all'))
except Exception as e:
raise OperationFailed('KCHVMSTOR0008E', {'error': str(e)})
# Don't put a try-block here. Let the exception be raised. If we
# allow disks used_by to be out of sync, data corruption could
# occur if a disk is added to two guests unknowingly.
if params.get('vol'):
used_by = vol_info['used_by']
used_by.append(vm_name)
return dev
def get_list(self, vm_name):
dom = VMModel.get_vm(vm_name, self.conn)
return get_vm_disks(dom).keys()
def _get_vol_info(self, params):
try:
pool = params['pool']
vol_model = StorageVolumeModel(
conn=self.conn, objstore=self.objstore)
vol_info = vol_model.lookup(pool, params['vol'])
except KeyError:
raise InvalidParameter('KCHVMSTOR0012E')
except Exception as e:
raise InvalidParameter('KCHVMSTOR0015E', {'error': e})
if len(vol_info['used_by']) != 0:
raise InvalidParameter('KCHVMSTOR0016E')
valid_format = {
'disk': ['raw', 'qcow', 'qcow2', 'qed', 'vmdk', 'vpc'],
'cdrom': 'iso',
}
if vol_info['type'] == 'file':
if (
params['type'] == 'disk' and
vol_info['format'] in valid_format[params['type']]
):
params['format'] = vol_info['format']
else:
raise InvalidParameter(
'KCHVMSTOR0018E',
{'format': vol_info['format'], 'type': params['type']},
)
if params['format'] == 'raw' and not vol_info['isvalid']:
message = 'This is not a valid RAW disk image.'
raise OperationFailed('KCHVMSTOR0008E', {'error': message})
return vol_info
class VMStorageModel(object):
def __init__(self, **kargs):
self.conn = kargs['conn']
self.objstore = kargs['objstore']
self.caps = CapabilitiesModel(**kargs)
def lookup(self, vm_name, dev_name):
# Retrieve disk xml and format return dict
dom = VMModel.get_vm(vm_name, self.conn)
return get_vm_disk_info(dom, dev_name)
def delete(self, vm_name, dev_name):
try:
bus_type = self.lookup(vm_name, dev_name)['bus']
dom = VMModel.get_vm(vm_name, self.conn)
except NotFoundError:
raise
if bus_type not in HOTPLUG_TYPE and DOM_STATE_MAP[dom.info()[0]] != 'shutoff':
raise InvalidOperation('KCHVMSTOR0011E')
try:
disk = get_device_node(dom, dev_name)
path = get_vm_disk_info(dom, dev_name)['path']
if path is None or len(path) < 1:
path = self.lookup(vm_name, dev_name)['path']
# This has to be done before it's detached. If it wasn't
# in the obj store, its ref count would have been updated
# by get_disk_used_by()
if path is not None:
used_by = get_disk_used_by(self.conn, path)
else:
wok_log.error(
'Unable to decrement volume used_by on'
' delete because no path could be found.'
)
dom.detachDeviceFlags(
etree.tostring(disk).decode(
'utf-8'), get_vm_config_flag(dom, 'all')
)
except Exception as e:
raise OperationFailed('KCHVMSTOR0010E', {'error': str(e)})
if used_by is not None and vm_name in used_by:
used_by.remove(vm_name)
else:
wok_log.error(
'Unable to update %s:%s used_by on delete.' % (
vm_name, dev_name)
)
def update(self, vm_name, dev_name, params):
old_disk_used_by = None
new_disk_used_by = None
dom = VMModel.get_vm(vm_name, self.conn)
dev_info = self.lookup(vm_name, dev_name)
if dev_info['type'] != 'cdrom':
raise InvalidOperation('KCHVMSTOR0006E')
params['path'] = params.get('path', '')
old_disk_path = dev_info['path']
new_disk_path = params['path']
if new_disk_path != old_disk_path:
# An empty path means a CD-ROM was empty or ejected:
if old_disk_path != '':
old_disk_used_by = get_disk_used_by(self.conn, old_disk_path)
if new_disk_path != '':
new_disk_used_by = get_disk_used_by(self.conn, new_disk_path)
dev_info.update(params)
dev, xml = get_disk_xml(dev_info)
try:
# FIXME: when updating from local file to remote file (http)
# libvirt adds a new device with same name instead of replacing
# the existing one
dom.updateDeviceFlags(xml, get_vm_config_flag(dom, 'all'))
except Exception as e:
raise OperationFailed('KCHVMSTOR0009E', {'error': str(e)})
try:
if old_disk_used_by is not None and vm_name in old_disk_used_by:
old_disk_used_by.remove(vm_name)
if new_disk_used_by is not None:
new_disk_used_by.append(vm_name)
except Exception as e:
wok_log.error(
'Unable to update dev used_by on update due to' ' %s:' % str(e)
)
return dev
================================================
FILE: network.py
================================================
#
# Project Kimchi
#
# Copyright IBM Corp, 2015-2017
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
#
import glob
import ipaddress
import os
from distutils.spawn import find_executable
import ethtool
from wok.stringutils import encode_value
from wok.utils import run_command
APrivateNets = ipaddress.IPv4Network('10.0.0.0/8', False)
BPrivateNets = ipaddress.IPv4Network('172.16.0.0/12', False)
CPrivateNets = ipaddress.IPv4Network('192.168.0.0/16', False)
PrivateNets = [CPrivateNets, BPrivateNets, APrivateNets]
DefaultNetsPool = [ipaddress.IPv4Network('192.168.122.0/23', False),
ipaddress.IPv4Network('192.168.124.0/22', False),
ipaddress.IPv4Network('192.168.128.0/17', False)]
NET_PATH = '/sys/class/net'
NIC_PATH = '/sys/class/net/*/device'
BRIDGE_PATH = '/sys/class/net/*/bridge'
BONDING_PATH = '/sys/class/net/*/bonding'
WLAN_PATH = '/sys/class/net/*/wireless'
NET_BRPORT = '/sys/class/net/%s/brport'
NET_MASTER = '/sys/class/net/%s/master'
PROC_NET_VLAN = '/proc/net/vlan/'
BONDING_SLAVES = '/sys/class/net/%s/bonding/slaves'
BRIDGE_PORTS = '/sys/class/net/%s/brif'
def wlans():
"""Get all wlans declared in /sys/class/net/*/wireless.
Returns:
List[str]: a list with the wlans found.
"""
return [b.split('/')[-2] for b in glob.glob(WLAN_PATH)]
def nics():
"""Get all nics of the host.
This function returns every nic, including those
that might be loaded from an usb port.
Returns:
List[str]: a list with the nics found.
"""
return list(set([b.split('/')[-2] for b in glob.glob(NIC_PATH)]) -
set(wlans()))
def is_nic(iface):
"""Checks if iface is a nic.
Args:
iface (str): name of the interface.
Returns:
bool: True if iface is a nic, False otherwise.
"""
return encode_value(iface) in map(encode_value, nics())
def bondings():
"""Get all bondings of the host.
Returns:
List[str]: a list with the bonds found.
"""
return [b.split('/')[-2] for b in glob.glob(BONDING_PATH)]
def is_bonding(iface):
"""Checks if iface is a bond.
Args:
iface (str): name of the interface.
Returns:
bool: True if iface is a bond, False otherwise.
"""
return encode_value(iface) in map(encode_value, bondings())
def vlans():
"""Get all vlans of the host.
Returns:
List[str]: a list with the vlans found.
"""
return list(
set([b.split('/')[-1] for b in glob.glob(NET_PATH + '/*')]) &
set([b.split('/')[-1] for b in glob.glob(PROC_NET_VLAN + '*')])
)
def is_vlan(iface):
"""Checks if iface is a vlan.
Args:
iface (str): name of the interface.
Returns:
bool: True if iface is a vlan, False otherwise.
"""
return encode_value(iface) in map(encode_value, vlans())
def bridges():
"""Get all bridges of the host.
Returns:
List[str]: a list with the bridges found.
"""
return list(set([b.split('/')[-2] for b in glob.glob(BRIDGE_PATH)] +
ovs_bridges()))
def is_bridge(iface):
"""Checks if iface is a bridge.
Args:
iface (str): name of the interface.
Returns:
bool: True if iface is a bridge, False otherwise.
"""
return encode_value(iface) in map(encode_value, bridges())
def is_openvswitch_running():
"""Checks if the openvswitch service is running in the host.
Returns:
bool: True if openvswitch service is running, False otherwise.
"""
cmd = ['systemctl', 'is-active', 'openvswitch', '--quiet']
_, _, r_code = run_command(cmd, silent=True)
return r_code == 0
def ovs_bridges():
"""Get the OVS Bridges of the host.
In some distributions, like Fedora, the files bridge and brif are
not created under /sys/class/net/ for OVS bridges.
These specific functions allows one to differentiate OVS bridges
from other types of bridges.
Returns:
List[str]: a list with the OVS bridges found.
"""
if not is_openvswitch_running():
return []
ovs_cmd = find_executable('ovs-vsctl')
# openvswitch not installed: there is no OVS bridge configured
if ovs_cmd is None:
return []
out, _, r_code = run_command([ovs_cmd, 'list-br'], silent=True)
if r_code != 0:
return []
return [x.strip() for x in out.rstrip('\n').split('\n') if x.strip()]
def is_ovs_bridge(iface):
"""Checks if iface is an OVS bridge.
In some distributions, like Fedora, the files bridge and brif are
not created under /sys/class/net/ for OVS bridges.
These specific functions allows one to differentiate OVS bridges
from other types of bridges.
Args:
iface (str): name of the interface.
Returns:
bool: True if iface is an OVS bridge, False otherwise.
"""
return iface in ovs_bridges()
def ovs_bridge_ports(ovsbr):
"""Get the ports of a OVS bridge.
In some distributions, like Fedora, the files bridge and brif are
not created under /sys/class/net/ for OVS bridges.
These specific functions allows one to differentiate OVS bridges
from other types of bridges.
Args:
ovsbr (str): name of the OVS bridge
Returns:
List[str]: a list with the ports of this bridge.
"""
if not is_openvswitch_running():
return []
ovs_cmd = find_executable('ovs-vsctl')
# openvswitch not installed: there is no OVS bridge configured
if ovs_cmd is None:
return []
out, _, r_code = run_command([ovs_cmd, 'list-ports', ovsbr], silent=True)
if r_code != 0:
return []
return [x.strip() for x in out.rstrip('\n').split('\n') if x.strip()]
def all_interfaces():
"""Returns all interfaces of the host.
Returns:
List[str]: a list with all interfaces of the host.
"""
return [d.rsplit('/', 1)[-1] for d in glob.glob(NET_PATH + '/*')]
def slaves(bonding):
"""Get all slaves from a bonding.
Args:
bonding (str): the name of the bond.
Returns:
List[str]: a list with all slaves.
"""
with open(BONDING_SLAVES % bonding) as bonding_file:
res = bonding_file.readline().split()
return res
def ports(bridge):
"""Get all ports from a bridge.
Args:
bridge (str): the name of the OVS bridge.
Returns:
List[str]: a list with all ports.
"""
if bridge in ovs_bridges():
return ovs_bridge_ports(bridge)
return os.listdir(BRIDGE_PORTS % bridge)
def is_brport(nic):
"""Checks if nic is a port of a bridge.
Args:
iface (str): name of the interface.
Returns:
bool: True if iface is a port of a bridge, False otherwise.
"""
ovs_brports = []
for ovsbr in ovs_bridges():
ovs_brports += ovs_bridge_ports(ovsbr)
return os.path.exists(NET_BRPORT % nic) or nic in ovs_brports
def is_bondlave(nic):
"""Checks if nic is a bond slave.
Args:
iface (str): name of the interface.
Returns:
bool: True if iface is a bond slave, False otherwise.
"""
return os.path.exists(NET_MASTER % nic)
def operstate(dev):
"""Get the operstate status of a device.
Args:
dev (str): name of the device.
Returns:
str: "up" or "down"
"""
flags = ethtool.get_flags(encode_value(dev))
return 'up' if flags & (ethtool.IFF_RUNNING | ethtool.IFF_UP) else 'down'
def get_vlan_device(vlan):
""" Return the device of the given VLAN.
Args:
vlan (str): the vlan name.
Returns:
str: the device of the VLAN.
"""
dev = None
if os.path.exists(PROC_NET_VLAN + vlan):
with open(PROC_NET_VLAN + vlan) as vlan_file:
for line in vlan_file:
if 'Device:' in line:
dummy, dev = line.split()
break
return dev
def get_bridge_port_device(bridge):
"""Return the nics list that belongs to a port of 'bridge'.
Args:
bridge (str): the bridge name.
Returns:
List[str]: the nic list.
"""
# br --- v --- bond --- nic1
if encode_value(bridge) not in map(encode_value, bridges()):
raise ValueError('unknown bridge %s' % bridge)
nics_list = []
for port in ports(bridge):
if encode_value(port) in map(encode_value, vlans()):
device = get_vlan_device(port)
if encode_value(device) in map(encode_value, bondings()):
nics_list.extend(slaves(device))
else:
nics_list.append(device)
if encode_value(port) in map(encode_value, bondings()):
nics_list.extend(slaves(port))
else:
nics_list.append(port)
return nics_list
def aggregated_bridges():
"""Get the list of aggregated bridges of the host.
Returns:
List[str]: the aggregated bridges list.
"""
return [bridge for bridge in bridges() if
(set(get_bridge_port_device(bridge)) & set(nics()))]
def bare_nics():
"""Get the list of bare nics of the host.
A nic is called bare when it is not a port of a bridge
or a slave of bond.
Returns:
List[str]: the list of bare nics of the host.
"""
return [nic for nic in nics() if not (is_brport(nic) or is_bondlave(nic))]
def is_bare_nic(iface):
"""Checks if iface is a bare nic.
Args:
iface (str): name of the interface.
Returns:
bool: True if iface is a bare nic, False otherwise.
"""
return encode_value(iface) in map(encode_value, bare_nics())
# The nic will not be exposed when it is a port of a bridge or
# a slave of bond.
# The bridge will not be exposed when all it's port are tap.
def all_favored_interfaces():
"""Get the list of all favored interfaces of the host.
The nic will not be exposed when it is a port of a bridge or
a slave of bond. The bridge will not be exposed when all its
port are tap.
Returns:
List[str]: the list of favored interfaces.
"""
return aggregated_bridges() + bare_nics() + bondings()
def get_interface_type(iface):
"""Get the interface type of iface.
Types supported: nic, bonding, bridge, vlan. If the type
can't be verified, 'unknown' is returned.
Args:
iface (str): the interface name.
Returns:
str: the interface type.
"""
try:
if is_nic(iface):
return 'nic'
if is_bonding(iface):
return 'bonding'
if is_bridge(iface):
return 'bridge'
if is_vlan(iface):
return 'vlan'
return 'unknown'
except IOError:
return 'unknown'
def get_dev_macaddr(dev):
info = ethtool.get_interfaces_info(dev)[0]
return info.mac_address
def get_dev_netaddr(dev):
info = ethtool.get_interfaces_info(dev)[0]
return (info.ipv4_address and
'%s/%s' % (info.ipv4_address, info.ipv4_netmask) or '')
def get_dev_netaddrs():
nets = []
for dev in ethtool.get_devices():
devnet = get_dev_netaddr(dev)
devnet and nets.append(ipaddress.IPv4Network(devnet, False))
return nets
# used_nets should include all the subnet allocated in libvirt network
# will get host network by get_dev_netaddrs
def get_one_free_network(used_nets, nets_pool=None):
if nets_pool is None:
nets_pool = PrivateNets
def _get_free_network(nets, used_nets):
for net in nets.subnets(new_prefix=24):
if not any(net.overlaps(used) for used in used_nets):
return str(net)
return None
used_nets = used_nets + get_dev_netaddrs()
for nets in nets_pool:
net = _get_free_network(nets, used_nets)
if net:
return net
return None
================================================
FILE: osinfo.py
================================================
#
# Project Kimchi
#
# Copyright IBM Corp, 2015-2017
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
import copy
import glob
import os
import distro
from collections import defaultdict
from distutils.version import LooseVersion
import psutil
from configobj import ConfigObj
from wok.config import PluginPaths
from wok.exception import InvalidParameter
from wok.plugins.kimchi.config import kimchiPaths
from wok.utils import wok_log
SUPPORTED_ARCHS = {
'x86': ('i386', 'i686', 'x86_64'),
'power': ('ppc', 'ppc64'),
'ppc64le': ('ppc64le'),
's390x': ('s390x'),
}
# Memory devices slot limits by architecture
HOST_DISTRO = distro.linux_distribution(full_distribution_name=False)
MEM_DEV_SLOTS = {
'ppc64': 32 if HOST_DISTRO and HOST_DISTRO[0] == 'Ubuntu' else 256,
'ppc64le': 32 if HOST_DISTRO and HOST_DISTRO[0] == 'Ubuntu' else 256,
'x86_64': 256,
'i686': 256,
'i386': 256,
's390x': 256,
}
template_specs = {
'x86': {
'old': dict(disk_bus='ide', nic_model='e1000', sound_model='ich6'),
'modern': dict(
disk_bus='virtio', nic_model='virtio', sound_model='ich6', tablet_bus='usb'
),
},
'power': {
'old': dict(
disk_bus='scsi',
nic_model='spapr-vlan',
cdrom_bus='scsi',
kbd_type='kbd',
kbd_bus='usb',
mouse_bus='usb',
tablet_bus='usb',
),
'modern': dict(
disk_bus='virtio',
nic_model='virtio',
cdrom_bus='scsi',
kbd_bus='usb',
kbd_type='kbd',
mouse_bus='usb',
tablet_bus='usb',
),
},
'ppc64le': {
'old': dict(
disk_bus='virtio',
nic_model='virtio',
cdrom_bus='scsi',
kbd_bus='usb',
kbd_type='keyboard',
mouse_bus='usb',
tablet_bus='usb',
),
'modern': dict(
disk_bus='virtio',
nic_model='virtio',
cdrom_bus='scsi',
kbd_bus='usb',
kbd_type='keyboard',
mouse_bus='usb',
tablet_bus='usb',
),
},
's390x': {
'old': dict(disk_bus='virtio', nic_model='virtio', cdrom_bus='scsi'),
'modern': dict(disk_bus='virtio', nic_model='virtio', cdrom_bus='scsi'),
},
}
custom_specs = {
'fedora': {'22': {'x86': dict(video_model='qxl')}},
'windows': {'xp': {'x86': dict(nic_model='pcnet')}},
}
modern_version_bases = {
'x86': {
'debian': '6.0',
'ubuntu': '7.10',
'opensuse': '10.3',
'centos': '5.3',
'rhel': '6.0',
'fedora': '16',
'gentoo': '0',
'sles': '11',
'arch': '0',
},
'power': {
'rhel': '6.5',
'fedora': '19',
'ubuntu': '14.04',
'opensuse': '13.1',
'sles': '11sp3',
},
'ppc64le': {
'rhel': '6.5',
'fedora': '19',
'ubuntu': '14.04',
'opensuse': '13.1',
'sles': '11sp3',
},
}
icon_available_distros = [
icon[5:-4]
for icon in glob.glob1('%s/images/' % PluginPaths('kimchi').ui_dir, 'icon-*.png')
]
def _get_arch():
for arch, sub_archs in SUPPORTED_ARCHS.items():
if os.uname()[4] in sub_archs:
return arch
def _get_default_template_mem():
if hasattr(psutil, 'virtual_memory'):
mem = psutil.virtual_memory().total >> 10 >> 10
else:
mem = psutil.TOTAL_PHYMEM >> 10 >> 10
return 2048 if mem > 2048 else mem
def _get_tmpl_defaults():
"""
ConfigObj returns a dict like below when no changes were made in the
template configuration file (template.conf)
{'main': {}, 'memory': {}, 'storage': {'disk.0': {}}, 'processor': {},
'graphics': {}}
The default values should be like below:
{'main': {'networks': ['default']},
'memory': {'current': 1024, 'maxmemory': 1024},
'storage': { 'disk.0': {'format': 'qcow2', 'size': '10',
'pool': '/plugins/kimchi/storagepools/default'}},
'processor': {'vcpus': '1', 'maxvcpus': 1},
'graphics': {'type': 'spice', 'listen': '127.0.0.1'}}
The default values on s390x architecture:
{'memory': {'current': 1024, 'maxmemory': 1024},
'storage': { 'disk.0': {'format': 'qcow2', 'size': '10',
'pool': '/plugins/kimchi/storagepools/default'}},
'processor': {'vcpus': '1', 'maxvcpus': 1},
'graphics': {'type': 'spice', 'listen': '127.0.0.1'}}
"""
# Create dict with default values
tmpl_defaults = defaultdict(dict)
host_arch = _get_arch()
tmpl_defaults['main']['networks'] = ['default']
if host_arch in ['s390x', 's390']:
tmpl_defaults['main']['networks'] = []
tmpl_defaults['memory'] = {
'current': _get_default_template_mem(),
'maxmemory': _get_default_template_mem(),
}
tmpl_defaults['storage']['disk.0'] = {
'size': 10,
'format': 'qcow2',
'pool': 'default',
}
is_on_s390x = True if _get_arch() == 's390x' else False
if is_on_s390x:
tmpl_defaults['storage']['disk.0']['path'] = '/var/lib/libvirt/images/'
del tmpl_defaults['storage']['disk.0']['pool']
tmpl_defaults['processor']['vcpus'] = 1
tmpl_defaults['processor']['maxvcpus'] = 1
tmpl_defaults['graphics'] = {'type': 'vnc', 'listen': '127.0.0.1'}
default_config = ConfigObj(tmpl_defaults)
# Load template configuration file
config_file = os.path.join(kimchiPaths.sysconf_dir, 'template.conf')
config = ConfigObj(config_file)
# File configuration takes preference.
# In s390x, file configuration can have storage pool or path.
# Default configuration for s390x is storage path.
# In case file conf has storage pool then storage pool takes preference.
# When conf file has explicitly storage pool: "defaults" should
# have storage pool and default configured path should be removed,
# as either storage can be path or pool, cannot be both.
# When conf file does not explicity storage pool or have explicitly
# storage path: "default" should have storage path only and cannot
# have default pool.
#
# Check file conf has storage configured.
if is_on_s390x and config.get('storage').get('disk.0'):
# remove storage from default_config as file configuration takes
# preference.
default_config.pop('storage')
# Get storage configuration present in conf file
config_pool = config.get('storage').get('disk.0').get('pool')
config_path = config.get('storage').get('disk.0').get('path')
# If storage configured in conf file then it should have either
# pool or path.
if not config_pool and not config_path:
raise InvalidParameter('KCHTMPL0040E')
# On s390x if config file has both path and pool uncommented
# then path should take preference.
if config_pool and config_path:
wok_log.warning(
'Both default pool and path are specified in'
+ ' template.conf. Hence default pool is being'
+ ' ignored and only default path will be used'
)
config.get('storage').get('disk.0').pop('pool')
# Merge default configuration with file configuration
default_config.merge(config)
# Create a dict with default values according to data structure
# expected by VMTemplate
defaults = {
'domain': 'kvm',
'arch': os.uname()[4],
'cdrom_bus': 'ide',
'cdrom_index': 2,
'mouse_bus': 'ps2',
}
# Parse main section to get networks and memory values
defaults.update(default_config.pop('main'))
defaults['memory'] = default_config.pop('memory')
defaults['memory']['current'] = int(defaults['memory']['current'])
defaults['memory']['maxmemory'] = int(defaults['memory']['maxmemory'])
# for s390x architecture, set default console as virtio
if is_on_s390x:
defaults['console'] = 'virtio'
# Parse storage section to get disks values
storage_section = default_config.pop('storage')
defaults['disks'] = []
for index, disk in enumerate(storage_section.keys()):
data = storage_section[disk]
data['index'] = int(disk.split('.')[1])
# Right now 'Path' is only supported on s390x
if storage_section[disk].get('path') and is_on_s390x:
data['path'] = storage_section[disk].pop('path')
if 'size' not in storage_section[disk]:
data['size'] = tmpl_defaults['storage']['disk.0']['size']
else:
data['size'] = storage_section[disk].pop('size')
if 'format' not in storage_section[disk]:
data['format'] = tmpl_defaults['storage']['disk.0']['format']
else:
data['format'] = storage_section[disk].pop('format')
else:
data['pool'] = {
'name': '/plugins/kimchi/storagepools/'
+ storage_section[disk].pop('pool')
}
defaults['disks'].append(data)
# Parse processor section to get vcpus and cpu_topology values
processor_section = default_config.pop('processor')
defaults['cpu_info'] = {
'vcpus': processor_section.pop('vcpus'),
'maxvcpus': processor_section.pop('maxvcpus'),
}
if len(processor_section.keys()) > 0:
defaults['cpu_info']['topology'] = processor_section
# Update defaults values with graphics values
defaults['graphics'] = default_config.pop('graphics')
# Setting default memory device slots
defaults['mem_dev_slots'] = MEM_DEV_SLOTS.get(os.uname()[4], 256)
return defaults
# Set defaults values according to template.conf file
defaults = _get_tmpl_defaults()
def get_template_default(template_type, field):
host_arch = _get_arch()
# Assuming 'power' = 'ppc64le' because lookup() does the same,
# claiming libvirt compatibility.
host_arch = 'power' if host_arch == 'ppc64le' else host_arch
tmpl_defaults = copy.deepcopy(defaults)
tmpl_defaults.update(template_specs[host_arch][template_type])
return tmpl_defaults[field]
def lookup(distro, version):
"""
Lookup all parameters needed to run a VM of a known or unknown operating
system type and version. The data is constructed by starting with the
'defaults' and merging the parameters given for the identified OS. If
known, a link to a remote install CD is added.
"""
params = copy.deepcopy(defaults)
params['os_distro'] = distro
params['os_version'] = version
arch = _get_arch()
# set up arch to ppc64 instead of ppc64le due to libvirt compatibility
if params['arch'] == 'ppc64le':
params['arch'] = 'ppc64'
# On s390x, template spec does not change based on version.
if params['arch'] == 's390x' or arch == 's390x':
params.update(template_specs[arch]['old'])
if not distro:
params['os_distro'] = params['os_version'] = 'unknown'
elif distro in modern_version_bases[arch]:
if LooseVersion(version) >= LooseVersion(modern_version_bases[arch][distro]):
params.update(template_specs[arch]['modern'])
else:
params.update(template_specs[arch]['old'])
else:
params['os_distro'] = params['os_version'] = 'unknown'
params.update(template_specs[arch]['old'])
# Get custom specifications
specs = custom_specs.get(distro, {})
for v, config in specs.items():
if LooseVersion(version) >= LooseVersion(v):
params.update(config.get(arch, {}))
if distro in icon_available_distros:
params['icon'] = 'plugins/kimchi/images/icon-%s.png' % distro
else:
params['icon'] = 'plugins/kimchi/images/icon-vm.png'
return params
================================================
FILE: po/LINGUAS
================================================
en_US
pt_BR
zh_CN
de_DE
es_ES
fr_FR
it_IT
ja_JP
ko_KR
ru_RU
zh_TW
================================================
FILE: po/Makefile.in.in
================================================
# Makefile for PO directory in any package using GNU gettext.
# Copyright (C) 1995-1997, 2000-2007, 2009-2010 by Ulrich Drepper
#
# This file can be copied and used freely without restrictions. It can
# be used in projects which are not available under the GNU General Public
# License but which still want to provide support for the GNU gettext
# functionality.
# Please note that the actual code of GNU gettext is covered by the GNU
# General Public License and is *not* in the public domain.
#
# Origin: gettext-0.18
GETTEXT_MACRO_VERSION = 0.18
PACKAGE = @PACKAGE@
VERSION = @VERSION@
PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
SHELL = /bin/sh
@SET_MAKE@
srcdir = @srcdir@
top_srcdir = @top_srcdir@
VPATH = @srcdir@
prefix = @prefix@
exec_prefix = @exec_prefix@
datarootdir = @datarootdir@
datadir = @datadir@
localedir = @prefix@/share/locale
gettextsrcdir = $(datadir)/gettext/po
INSTALL = @INSTALL@
INSTALL_DATA = @INSTALL_DATA@
# We use $(MKDIR_P).
# This macro uses the 'mkdir -p' command if possible. Otherwise, it falls back
# on invoking install-sh with the -d option, so your package should contain
# install-sh as described under AC_PROG_INSTALL.
mkinstalldirs = $(SHELL) @install_sh@ -d
install_sh = $(SHELL) @install_sh@
MKDIR_P = @MKDIR_P@
MKDIR_P = @MKDIR_P@
GMSGFMT_ = @GMSGFMT@
GMSGFMT_no = @GMSGFMT@
GMSGFMT_yes = @GMSGFMT_015@
GMSGFMT = $(GMSGFMT_$(USE_MSGCTXT))
MSGFMT_ = @MSGFMT@
MSGFMT_no = @MSGFMT@
MSGFMT_yes = @MSGFMT_015@
MSGFMT = $(MSGFMT_$(USE_MSGCTXT))
XGETTEXT_ = @XGETTEXT@
XGETTEXT_no = @XGETTEXT@
XGETTEXT_yes = @XGETTEXT_015@
XGETTEXT = $(XGETTEXT_$(USE_MSGCTXT))
MSGMERGE = msgmerge
MSGMERGE_UPDATE = @MSGMERGE@ --update
MSGINIT = msginit
MSGCONV = msgconv
MSGFILTER = msgfilter
POFILES = @POFILES@
GMOFILES = @GMOFILES@
UPDATEPOFILES = @UPDATEPOFILES@
DUMMYPOFILES = @DUMMYPOFILES@
DISTFILES.common = Makefile.in.in \
$(DISTFILES.common.extra1) $(DISTFILES.common.extra2) $(DISTFILES.common.extra3)
DISTFILES = $(DISTFILES.common) Makevars POTFILES.in gen-pot.in \
$(POFILES) $(GMOFILES) \
$(DISTFILES.extra1) $(DISTFILES.extra2) $(DISTFILES.extra3)
POTFILES = \
CATALOGS = @CATALOGS@
# Makevars gets inserted here. (Don't remove this line!)
.SUFFIXES:
.SUFFIXES: .po .gmo .mo .sed .sin .nop .po-create .po-update
.po.mo:
@echo "$(MSGFMT) -c -o $@ $<"; \
$(MSGFMT) -c -o t-$@ $< && mv t-$@ $@
.po.gmo:
@lang=`echo $* | sed -e 's,.*/,,'`; \
test "$(srcdir)" = . && cdcmd="" || cdcmd="cd $(srcdir) && "; \
echo "$${cdcmd}rm -f $${lang}.gmo && $(GMSGFMT) -c --statistics --verbose -o $${lang}.gmo $${lang}.po"; \
cd $(srcdir) && rm -f $${lang}.gmo && $(GMSGFMT) -c --statistics --verbose -o t-$${lang}.gmo $${lang}.po && mv t-$${lang}.gmo $${lang}.gmo
.sin.sed:
sed -e '/^#/d' $< > t-$@
mv t-$@ $@
all: check-macro-version update-gmo all-@USE_NLS@
all-yes: stamp-po
all-no:
# Ensure that the gettext macros and this Makefile.in.in are in sync.
check-macro-version:
@test "$(GETTEXT_MACRO_VERSION)" = "@GETTEXT_MACRO_VERSION@" \
|| { echo "*** error: gettext infrastructure mismatch: using a Makefile.in.in from gettext version $(GETTEXT_MACRO_VERSION) but the autoconf macros are from gettext version @GETTEXT_MACRO_VERSION@" 1>&2; \
exit 1; \
}
# $(srcdir)/$(DOMAIN).pot is only created when needed. When xgettext finds no
# internationalized messages, no $(srcdir)/$(DOMAIN).pot is created (because
# we don't want to bother translators with empty POT files). We assume that
# LINGUAS is empty in this case, i.e. $(POFILES) and $(GMOFILES) are empty.
# In this case, stamp-po is a nop (i.e. a phony target).
# stamp-po is a timestamp denoting the last time at which the CATALOGS have
# been loosely updated. Its purpose is that when a developer or translator
# checks out the package via CVS, and the $(DOMAIN).pot file is not in CVS,
# "make" will update the $(DOMAIN).pot and the $(CATALOGS), but subsequent
# invocations of "make" will do nothing. This timestamp would not be necessary
# if updating the $(CATALOGS) would always touch them; however, the rule for
# $(POFILES) has been designed to not touch files that don't need to be
# changed.
stamp-po: $(srcdir)/$(DOMAIN).pot
test ! -f $(srcdir)/$(DOMAIN).pot || \
test -z "$(GMOFILES)" || $(MAKE) $(GMOFILES)
@test ! -f $(srcdir)/$(DOMAIN).pot || { \
echo "touch stamp-po" && \
echo timestamp > stamp-poT && \
mv stamp-poT stamp-po; \
}
# Note: Target 'all' must not depend on target '$(DOMAIN).pot-update',
# otherwise packages like GCC can not be built if only parts of the source
# have been downloaded.
$(DOMAIN).pot-update: $(POTFILES) $(srcdir)/POTFILES.in
$(srcdir)/gen-pot $(POTFILES)
# This rule has no dependencies: we don't need to update $(DOMAIN).pot at
# every "make" invocation, only create it when it is missing.
# Only "make $(DOMAIN).pot-update" or "make dist" will force an update.
$(srcdir)/$(DOMAIN).pot:
$(MAKE) $(DOMAIN).pot-update
# This target rebuilds a PO file if $(DOMAIN).pot has changed.
# Note that a PO file is not touched if it doesn't need to be changed.
$(POFILES): $(srcdir)/$(DOMAIN).pot
@lang=`echo $@ | sed -e 's,.*/,,' -e 's/\.po$$//'`; \
if test -f "$(srcdir)/$${lang}.po"; then \
test "$(srcdir)" = . && cdcmd="" || cdcmd="cd $(srcdir) && "; \
echo "$${cdcmd}$(MSGMERGE_UPDATE) $(MSGMERGE_OPTIONS) --lang=$${lang} $${lang}.po $(DOMAIN).pot"; \
cd $(srcdir) \
&& { case `$(MSGMERGE_UPDATE) --version | sed 1q | sed -e 's,^[^0-9]*,,'` in \
'' | 0.[0-9] | 0.[0-9].* | 0.1[0-7] | 0.1[0-7].*) \
$(MSGMERGE_UPDATE) $(MSGMERGE_OPTIONS) $${lang}.po $(DOMAIN).pot;; \
*) \
$(MSGMERGE_UPDATE) $(MSGMERGE_OPTIONS) --lang=$${lang} $${lang}.po $(DOMAIN).pot;; \
esac; \
}; \
else \
$(MAKE) $${lang}.po-create; \
fi
install: install-exec install-data
install-exec:
install-data: install-data-@USE_NLS@
if test "$(PACKAGE)" = "gettext-tools"; then \
$(MKDIR_P) $(DESTDIR)$(gettextsrcdir); \
for file in $(DISTFILES.common) Makevars.template; do \
$(INSTALL_DATA) $(srcdir)/$$file \
$(DESTDIR)$(gettextsrcdir)/$$file; \
done; \
for file in Makevars; do \
rm -f $(DESTDIR)$(gettextsrcdir)/$$file; \
done; \
else \
: ; \
fi
install-data-no: all
install-data-yes: all
@catalogs='$(CATALOGS)'; \
for cat in $$catalogs; do \
cat=`basename $$cat`; \
lang=`echo $$cat | sed -e 's/\.gmo$$//'`; \
dir=$(localedir)/$$lang/LC_MESSAGES; \
$(MKDIR_P) $(DESTDIR)$$dir; \
if test -r $$cat; then realcat=$$cat; else realcat=$(srcdir)/$$cat; fi; \
$(INSTALL_DATA) $$realcat $(DESTDIR)$$dir/$(DOMAIN).mo; \
echo "installing $$realcat as $(DESTDIR)$$dir/$(DOMAIN).mo"; \
for lc in '' $(EXTRA_LOCALE_CATEGORIES); do \
if test -n "$$lc"; then \
if (cd $(DESTDIR)$(localedir)/$$lang && LC_ALL=C ls -l -d $$lc 2>/dev/null) | grep ' -> ' >/dev/null; then \
link=`cd $(DESTDIR)$(localedir)/$$lang && LC_ALL=C ls -l -d $$lc | sed -e 's/^.* -> //'`; \
mv $(DESTDIR)$(localedir)/$$lang/$$lc $(DESTDIR)$(localedir)/$$lang/$$lc.old; \
mkdir $(DESTDIR)$(localedir)/$$lang/$$lc; \
(cd $(DESTDIR)$(localedir)/$$lang/$$lc.old && \
for file in *; do \
if test -f $$file; then \
ln -s ../$$link/$$file $(DESTDIR)$(localedir)/$$lang/$$lc/$$file; \
fi; \
done); \
rm -f $(DESTDIR)$(localedir)/$$lang/$$lc.old; \
else \
if test -d $(DESTDIR)$(localedir)/$$lang/$$lc; then \
:; \
else \
rm -f $(DESTDIR)$(localedir)/$$lang/$$lc; \
mkdir $(DESTDIR)$(localedir)/$$lang/$$lc; \
fi; \
fi; \
rm -f $(DESTDIR)$(localedir)/$$lang/$$lc/$(DOMAIN).mo; \
ln -s ../LC_MESSAGES/$(DOMAIN).mo $(DESTDIR)$(localedir)/$$lang/$$lc/$(DOMAIN).mo 2>/dev/null || \
ln $(DESTDIR)$(localedir)/$$lang/LC_MESSAGES/$(DOMAIN).mo $(DESTDIR)$(localedir)/$$lang/$$lc/$(DOMAIN).mo 2>/dev/null || \
cp -p $(DESTDIR)$(localedir)/$$lang/LC_MESSAGES/$(DOMAIN).mo $(DESTDIR)$(localedir)/$$lang/$$lc/$(DOMAIN).mo; \
echo "installing $$realcat link as $(DESTDIR)$(localedir)/$$lang/$$lc/$(DOMAIN).mo"; \
fi; \
done; \
done
install-strip: install
installdirs: installdirs-exec installdirs-data
installdirs-exec:
installdirs-data: installdirs-data-@USE_NLS@
if test "$(PACKAGE)" = "gettext-tools"; then \
$(MKDIR_P) $(DESTDIR)$(gettextsrcdir); \
else \
: ; \
fi
installdirs-data-no:
installdirs-data-yes:
@catalogs='$(CATALOGS)'; \
for cat in $$catalogs; do \
cat=`basename $$cat`; \
lang=`echo $$cat | sed -e 's/\.gmo$$//'`; \
dir=$(localedir)/$$lang/LC_MESSAGES; \
$(MKDIR_P) $(DESTDIR)$$dir; \
for lc in '' $(EXTRA_LOCALE_CATEGORIES); do \
if test -n "$$lc"; then \
if (cd $(DESTDIR)$(localedir)/$$lang && LC_ALL=C ls -l -d $$lc 2>/dev/null) | grep ' -> ' >/dev/null; then \
link=`cd $(DESTDIR)$(localedir)/$$lang && LC_ALL=C ls -l -d $$lc | sed -e 's/^.* -> //'`; \
mv $(DESTDIR)$(localedir)/$$lang/$$lc $(DESTDIR)$(localedir)/$$lang/$$lc.old; \
mkdir $(DESTDIR)$(localedir)/$$lang/$$lc; \
(cd $(DESTDIR)$(localedir)/$$lang/$$lc.old && \
for file in *; do \
if test -f $$file; then \
ln -s ../$$link/$$file $(DESTDIR)$(localedir)/$$lang/$$lc/$$file; \
fi; \
done); \
rm -f $(DESTDIR)$(localedir)/$$lang/$$lc.old; \
else \
if test -d $(DESTDIR)$(localedir)/$$lang/$$lc; then \
:; \
else \
rm -f $(DESTDIR)$(localedir)/$$lang/$$lc; \
mkdir $(DESTDIR)$(localedir)/$$lang/$$lc; \
fi; \
fi; \
fi; \
done; \
done
# Define this as empty until I found a useful application.
installcheck:
uninstall: uninstall-exec uninstall-data
uninstall-exec:
uninstall-data: uninstall-data-@USE_NLS@
if test "$(PACKAGE)" = "gettext-tools"; then \
for file in $(DISTFILES.common) Makevars.template; do \
rm -f $(DESTDIR)$(gettextsrcdir)/$$file; \
done; \
else \
: ; \
fi
uninstall-data-no:
uninstall-data-yes:
catalogs='$(CATALOGS)'; \
for cat in $$catalogs; do \
cat=`basename $$cat`; \
lang=`echo $$cat | sed -e 's/\.gmo$$//'`; \
for lc in LC_MESSAGES $(EXTRA_LOCALE_CATEGORIES); do \
rm -f $(DESTDIR)$(localedir)/$$lang/$$lc/$(DOMAIN).mo; \
done; \
done
check: all
info dvi ps pdf html tags TAGS ctags CTAGS ID:
mostlyclean:
rm -f remove-potcdate.sed
rm -f stamp-poT
rm -f core core.* $(DOMAIN).po $(DOMAIN).1po $(DOMAIN).2po *.new.po
rm -fr *.o
clean: mostlyclean
distclean: clean
rm -f Makefile Makefile.in POTFILES *.mo
maintainer-clean: distclean
@echo "This command is intended for maintainers to use;"
@echo "it deletes files that may require special tools to rebuild."
rm -f stamp-po $(GMOFILES)
distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir)
dist distdir:
@$(MAKE) dist2
# This is a separate target because 'update-po' must be executed before.
dist2: stamp-po $(DISTFILES)
dists="$(DISTFILES)"; \
if test "$(PACKAGE)" = "gettext-tools"; then \
dists="$$dists Makevars.template"; \
fi; \
if test -f $(srcdir)/$(DOMAIN).pot; then \
dists="$$dists $(DOMAIN).pot stamp-po"; \
fi; \
if test -f $(srcdir)/LINGUAS; then dists="$$dists LINGUAS"; fi; \
for file in $$dists; do \
if test -f $$file; then \
cp -p $$file $(distdir) || exit 1; \
else \
cp -p $(srcdir)/$$file $(distdir) || exit 1; \
fi; \
done
update-po: Makefile
$(MAKE) $(DOMAIN).pot-update
test -z "$(UPDATEPOFILES)" || $(MAKE) $(UPDATEPOFILES)
$(MAKE) update-gmo
# General rule for creating PO files.
.nop.po-create:
@lang=`echo $@ | sed -e 's/\.po-create$$//'`; \
echo "File $$lang.po does not exist. If you are a translator, you can create it through 'msginit'." 1>&2; \
exit 1
# General rule for updating PO files.
.nop.po-update:
@lang=`echo $@ | sed -e 's/\.po-update$$//'`; \
if test "$(PACKAGE)" = "gettext-tools"; then PATH=`pwd`/../src:$$PATH; fi; \
tmpdir=`pwd`; \
echo "$$lang:"; \
test "$(srcdir)" = . && cdcmd="" || cdcmd="cd $(srcdir) && "; \
echo "$${cdcmd}$(MSGMERGE) $(MSGMERGE_OPTIONS) --lang=$$lang $$lang.po $(DOMAIN).pot -o $$lang.new.po"; \
cd $(srcdir); \
if { case `$(MSGMERGE) --version | sed 1q | sed -e 's,^[^0-9]*,,'` in \
'' | 0.[0-9] | 0.[0-9].* | 0.1[0-7] | 0.1[0-7].*) \
$(MSGMERGE) $(MSGMERGE_OPTIONS) -o $$tmpdir/$$lang.new.po $$lang.po $(DOMAIN).pot;; \
*) \
$(MSGMERGE) $(MSGMERGE_OPTIONS) --lang=$$lang -o $$tmpdir/$$lang.new.po $$lang.po $(DOMAIN).pot;; \
esac; \
}; then \
if cmp $$lang.po $$tmpdir/$$lang.new.po >/dev/null 2>&1; then \
rm -f $$tmpdir/$$lang.new.po; \
else \
if mv -f $$tmpdir/$$lang.new.po $$lang.po; then \
:; \
else \
echo "msgmerge for $$lang.po failed: cannot move $$tmpdir/$$lang.new.po to $$lang.po" 1>&2; \
exit 1; \
fi; \
fi; \
else \
echo "msgmerge for $$lang.po failed!" 1>&2; \
rm -f $$tmpdir/$$lang.new.po; \
fi
$(DUMMYPOFILES):
update-gmo: Makefile $(GMOFILES)
@:
# Recreate Makefile by invoking config.status. Explicitly invoke the shell,
# because execution permission bits may not work on the current file system.
# Use @SHELL@, which is the shell determined by autoconf for the use by its
# scripts, not $(SHELL) which is hardwired to /bin/sh and may be deficient.
Makefile: Makefile.in.in Makevars $(top_builddir)/config.status @POMAKEFILEDEPS@
cd $(top_builddir) \
&& @SHELL@ ./config.status $(subdir)/$@.in po-directories
force:
# Tell versions [3.59,3.63) of GNU make not to export all variables.
# Otherwise a system limit (for SysV at least) may be exceeded.
.NOEXPORT:
================================================
FILE: po/Makevars
================================================
# Makefile variables for PO directory in any package using GNU gettext.
# Usually the message domain is the same as the package name.
DOMAIN = kimchi
# These two variables depend on the location of this directory.
subdir = po
top_builddir = ..
# These options get passed to xgettext.
XGETTEXT_OPTIONS = --keyword=_ --keyword=N_
# This is the copyright holder that gets inserted into the header of the
# $(DOMAIN).pot file. Set this to the copyright holder of the surrounding
# package. (Note that the msgstr strings, extracted from the package's
# sources, belong to the copyright holder of the package.) Translators are
# expected to transfer the copyright for their translations to this person
# or entity, or to disclaim their copyright. The empty string stands for
# the public domain; in this case the translators are expected to disclaim
# their copyright.
COPYRIGHT_HOLDER =
# This is the email address or URL to which the translators shall report
# bugs in the untranslated strings:
# - Strings which are not entire sentences, see the maintainer guidelines
# in the GNU gettext documentation, section 'Preparing Strings'.
# - Strings which use unclear terms or require additional context to be
# understood.
# - Strings which make invalid assumptions about notation of date, time or
# money.
# - Pluralisation problems.
# - Incorrect English spelling.
# - Incorrect formatting.
# It can be your email address, or a mailing list address where translators
# can write to without being subscribed, or the URL of a web page through
# which the translators can contact you.
MSGID_BUGS_ADDRESS = project-kimchi@googlegroups.com
# This is the list of locale categories, beyond LC_MESSAGES, for which the
# message catalogs shall be used. It is usually empty.
EXTRA_LOCALE_CATEGORIES =
================================================
FILE: po/POTFILES.in
================================================
# List of source files which contain translatable strings.
i18n.py
ui/pages/*.tmpl
ui/pages/tabs/*.tmpl
================================================
FILE: po/de_DE.po
================================================
# German translations for kimchi package.
# Copyright IBM Corp, 2014-2017
# Adam Litke , 2013.
#
msgid ""
msgstr ""
"Project-Id-Version: kimchi 0.1\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2017-06-30 10:27-0300\n"
"PO-Revision-Date: 2013-07-11 17:32-0400\n"
"Last-Translator: Crístian Viana \n"
"Language-Team: English\n"
"Language: de_DE\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: pygettext.py 1.5\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
#, python-format
msgid "Unknown parameter %(value)s"
msgstr "Unbekannter Parameter %(value)s"
#, python-format
msgid "User %(user_id)s not found with given LDAP settings."
msgstr ""
"Benutzer %(user_id)s mit den angegebenen LDAP-Einstellungen wurde nicht "
"gefunden."
#, python-format
msgid "Partition %(name)s does not exist in the host"
msgstr "Partition %(name)s ist im Host nicht vorhanden"
#, python-format
msgid "Error while accessing dev mapper device, %(err)s"
msgstr ""
msgid "Block device not found."
msgstr ""
#, python-format
msgid "Block device %(device)s not found."
msgstr ""
#, python-format
msgid "Unable to retrieve LVM information. Details: %(err)s"
msgstr ""
msgid "Unknown \"_cap\" specified"
msgstr "Unbekanntes Element \"_cap\" angegeben"
msgid "\"_passthrough\" should be \"true\" or \"false\""
msgstr "Für \"_passthrough\" muss \"true\" oder \"false\" angegeben werden"
msgid "\"_passthrough_affected_by\" should be a device name string"
msgstr ""
"Für \"_passthrough_affected_by\" muss eine Einheitennamenszeichenfolge "
"angegeben werden"
msgid "\"_available_only\" should be \"true\" or \"false\""
msgstr "Für \"_available_only\" muss \"true\" oder \"false\" angegeben werden"
#, python-format
msgid "Unable to find distro file: %(filename)s"
msgstr "Distro-Datei konnte nicht gefunden werden: %(filename)s"
#, python-format
msgid ""
"Unable to parse distro file: %(filename)s. Make sure, it is a JSON file."
msgstr ""
"Distro-Datei konnte nicht analysiert werden: %(filename)s. Stellen Sie "
"sicher, dass es sich um eine JSON-Datei handelt."
#, python-format
msgid "Unable to login to iSCSI host target %(portal)s. Details: %(err)s"
msgstr "Fehler beim Anmelden bei iSCSI-Hostziel %(portal)s. Details: %(err)s"
#, python-format
msgid "Unable to login to iSCSI host %(host)s target %(target)s"
msgstr "Anmeldung bei iSCSI-Host %(host)s Ziel %(target)s nicht möglich"
#, python-format
msgid "Unable to find ISO file %(filename)s"
msgstr "ISO-Datei %(filename)s konnte nicht gefunden werden"
#, python-format
msgid "The ISO file %(filename)s is not bootable"
msgstr "Die ISO-Datei %(filename)s ist nicht bootfähig"
#, python-format
msgid "The ISO file %(filename)s does not have a valid El Torito boot record"
msgstr "Die ISO-Datei %(filename)s hat keinen gültigen El Torito-Bootsatz"
#, python-format
msgid "Invalid El Torito validation entry in ISO %(filename)s"
msgstr "Ungültiger El Torito-Prüfeintrag in ISO-Datei %(filename)s"
#, python-format
msgid "Invalid El Torito boot indicator in ISO %(filename)s"
msgstr "Ungültiger El Torito-Boot-Indikator in ISO-Datei %(filename)s"
#, python-format
msgid "Unexpected volume type for primary volume in ISO %(filename)s"
msgstr ""
"Unerwarteter Datenträgertyp für Primärdatenträger in ISO-Datei %(filename)s"
#, python-format
msgid "Bad format while reading volume descriptor in ISO %(filename)s"
msgstr ""
"Ungültiges Format beim Lesen des Datenträgerdeskriptors in ISO-Datei "
"%(filename)s"
#, python-format
msgid ""
"The hypervisor doesn't have permission to use this ISO %(filename)s. "
"Consider moving it under /var/lib/libvirt, or set the search permission to "
"file access control lists for '%(user)s' user if possible, or add the "
"'%(user)s' to the ISO path group, or (not recommended) 'chmod -R o+x "
"'path_to_iso'.Details: %(err)s"
msgstr ""
"Der Hypervisor hat nicht die Berechtigung, die ISO-Datei %(filename)s zu "
"verwenden.Verschieben Sie sie entweder nach /var/lib/libvirt oder setzen "
"Sie, sofern möglich, die Suchberechtigung auf Dateizugriffssteuerungslisten "
"für den Benutzer '%(user)s' oder fügen Sie '%(user)s' der ISO-Pfadgruppe "
"hinzu oder (nicht empfohlen) 'chmod -R o+x 'path_to_iso'. Details: %(err)s"
#, python-format
msgid "Unable to access remote ISO. Details: %(err)s"
msgstr ""
#, python-format
msgid "Error probing image OS information: %(err)s"
msgstr ""
#, python-format
msgid "Unable to read image file %(filename)s"
msgstr "Die Imagedatei %(filename)s konnte nicht gelesen werden"
#, python-format
msgid ""
"Image file must be an existing file on system. %(filename)s is not a valid "
"input."
msgstr ""
"Bei der Imagedatei muss es sich um eine auf dem System vorhandene Datei "
"handeln. %(filename)s ist nicht gültig Eingabe."
#, python-format
msgid "Virtual machine %(name)s already exists"
msgstr "Virtuelle Maschine %(name)s ist bereits vorhanden"
#, python-format
msgid "Virtual machine %(name)s does not exist"
msgstr "Virtuelle Maschine %(name)s ist nicht vorhanden"
#, python-format
msgid "Unable to retrieve screenshot for stopped virtual machine %(name)s"
msgstr ""
"Screenshot für gestoppte virtuelle Maschine %(name)s konnte nicht abgerufen "
"werden"
msgid "Remote ISO image is not supported by this server."
msgstr "Fernes ISO-Image wird von diesem Server nicht unterstützt."
#, python-format
msgid "Screenshot is not supported on virtual machine %(name)s"
msgstr "Screenshot wird auf virtueller Maschine %(name)s nicht unterstützt"
#, python-format
msgid "Unable to create virtual machine %(name)s. Details: %(err)s"
msgstr ""
"Virtuelle Maschine %(name)s konnte nicht erstellt werden. Details: %(err)s"
#, python-format
msgid "Unable to update virtual machine %(name)s. Details: %(err)s"
msgstr ""
"Virtuelle Maschine %(name)s konnte nicht aktualisiert werden. Details: "
"%(err)s"
#, python-format
msgid "Unable to retrieve virtual machine %(name)s. Details: %(err)s"
msgstr ""
"Virtuelle Maschine %(name)s konnte nicht abgerufen werden. Details: %(err)s"
#, python-format
msgid "Unable to connect to powered off virtual machine %(name)s."
msgstr ""
"Verbindung zu ausgeschalteter virtueller Maschine %(name)s konnte nicht "
"hergestellt werden."
msgid "Virtual machine name must be a string without slashes (/)"
msgstr ""
"Name der virtuellen Maschine muss eine Zeichenfolge ohne Schrägstriche (/) "
"sein"
#, python-format
msgid "Invalid template URI %(value)s specified for virtual machine"
msgstr "Ungültiger Vorlagen-URI %(value)s für virtuelle Maschine angegeben"
#, python-format
msgid "Invalid storage pool URI %(value)s specified for virtual machine"
msgstr "Ungültiger Speicherpool-URI %(value)s für virtuelle Maschine angegeben"
msgid "Supported virtual machine graphics are Spice or VNC"
msgstr "Unterstützte Grafiken für virtuelle Maschine sind Spice oder VNC"
msgid "Graphics address to listen on must be IPv4 or IPv6"
msgstr "Zu überwachende Grafikadresse muss IPv4 oder IPv6 sein"
msgid "Specify a template to create a virtual machine from"
msgstr "Vorlage angeben, aus der eine virtuelle Maschine erstellt werden soll"
#, python-format
msgid "Unable to start virtual machine %(name)s. Details: %(err)s"
msgstr ""
"Virtuelle Maschine %(name)s konnte nicht gestartet werden. Details: %(err)s"
#, python-format
msgid "Unable to power off virtual machine %(name)s. Details: %(err)s"
msgstr ""
"Virtuelle Maschine %(name)s konnte nicht ausgeschaltet werden. Details: "
"%(err)s"
#, python-format
msgid "Unable to delete virtual machine %(name)s. Details: %(err)s"
msgstr ""
"Virtuelle Maschine %(name)s konnte nicht gelöscht werden. Details: %(err)s"
#, python-format
msgid "Unable to reset virtual machine %(name)s. Details: %(err)s"
msgstr ""
"Virtuelle Maschine %(name)s konnte nicht zurückgesetzt werden. Details: "
"%(err)s"
msgid "User name list must be an array"
msgstr "Benutzernamensliste muss ein Array sein"
msgid "User name must be a string"
msgstr "Benutzername muss eine Zeichenfolge sein"
msgid "Group name list must be an array"
msgstr "Gruppennamensliste muss ein Array sein"
msgid "Group name must be a string"
msgstr "Gruppenname muss eine Zeichenfolge sein"
#, python-format
msgid "User(s) '%(users)s' do not exist"
msgstr "Benutzer '%(users)s' nicht vorhanden"
#, python-format
msgid "Group(s) '%(groups)s' do not exist"
msgstr "Gruppe(n) '%(groups)s' nicht vorhanden"
#, python-format
msgid "Unable to shutdown virtual machine %(name)s. Details: %(err)s"
msgstr ""
"Virtuelle Maschine %(name)s konnte nicht heruntergefahren werden. Details: "
"%(err)s"
msgid "The guest console password must be a string."
msgstr "Das Konsolenkennwort des Gastes muss eine Zeichenfolge sein."
msgid "The life time for the guest console password must be a number."
msgstr ""
"Die Lebensdauer für das Konsolenkennwort des Gastes muss eine Zahl sein."
#, python-format
msgid "Virtual machine '%(name)s' must be stopped before cloning it."
msgstr "Die virtuelle Maschine '%(name)s' muss vor dem Klonen gestoppt werden."
#, python-format
msgid "Insufficient disk space to clone virtual machine '%(name)s'"
msgstr ""
"Nicht genügend Plattenspeicherplatz zum Klonen der virtuellen Maschine "
"'%(name)s' vorhanden"
#, python-format
msgid "Unable to clone VM '%(name)s'. Details: %(err)s"
msgstr ""
"Virtuelle Maschine '%(name)s' konnte nicht geklont werden. Details: %(err)s"
#, python-format
msgid "Invalid operation for non-persistent virtual machine %(name)s"
msgstr "Ungültige Operation für nicht permanente virtuelle Maschine %(name)s"
#, python-format
msgid "Cannot suspend VM '%(name)s' because it is not running."
msgstr ""
"Die virtuelle Maschine '%(name)s' kann nicht ausgesetzt werden, weil sie "
"momentan nicht aktiv ist."
#, python-format
msgid "Unable to suspend VM '%(name)s'. Details: %(err)s"
msgstr ""
"Virtuelle Maschine '%(name)s' konnte nicht ausgesetzt werden. Details: "
"%(err)s"
#, python-format
msgid "Cannot resume VM '%(name)s' because it is not paused."
msgstr ""
"Die virtuelle Maschine '%(name)s' kann nicht fortgesetzt werden, weil sie "
"nicht angehalten wurde."
#, python-format
msgid "Unable to resume VM '%(name)s'. Details: %(err)s"
msgstr ""
"Virtuelle Maschine '%(name)s' konnte nicht fortgesetzt werden. Details: "
"%(err)s"
#, python-format
msgid ""
"Memory assigned is higher then the maximum allowed in the host: "
"%(maxmem)sMib."
msgstr ""
#, python-format
msgid ""
"Guest '%(name)s' does not support live memory update. Please, with the guest "
"offline, set Maximum Memory with a value greater then Memory to enable this "
"feature."
msgstr ""
msgid "Only increase memory is allowed in active VMs"
msgstr ""
"Die Speichervergrößerung ist nur in aktiven virtuellen Maschinen zulässig"
msgid "There are not enough free slots to add a new memory device."
msgstr ""
msgid ""
"Host's libvirt or qemu version does not support memory devices and memory "
"hotplug. Libvirt must be >= 1.2.14 and QEMU must be >= 2.1."
msgstr ""
#, python-format
msgid "Error attaching memory device. Details: %(error)s"
msgstr "Fehler beim Anschließen der Speichereinheit. Details: %(error)s"
#, python-format
msgid "Cannot start %(name)s. Virtual machine is already running."
msgstr ""
"%(name)s kann nicht gestartet werden. Virtuelle Maschine wird bereits "
"ausgeführt."
#, python-format
msgid "Cannot power off %(name)s. Virtual machine is shut off."
msgstr ""
"%(name)s kann nicht ausgeschaltet werden. Virtuelle Maschine ist "
"ausgeschaltet."
#, python-format
msgid "Cannot shutdown %(name)s. Virtual machine is shut off."
msgstr ""
"%(name)s kann nicht heruntergefahren werden. Virtuelle Maschine ist "
"ausgeschaltet."
#, python-format
msgid "Cannot reset %(name)s. Virtual machine is already shut off."
msgstr ""
"%(name)s kann nicht zurückgesetzt werden. Virtuelle Maschine ist bereits "
"ausgeschaltet."
msgid "Boot order must be a list. Devices accepted: hd, cdrom, fd or network."
msgstr ""
msgid "Bootmenu must be boolean. Values accepted: true of false."
msgstr ""
msgid "Graphic type not valid. Values accepted: vnc or spice."
msgstr ""
#, python-format
msgid "Migrate to localhost %(host)s is not allowed."
msgstr ""
#, python-format
msgid ""
"To migrate a virtual machine to the remote host %(host)s the user %(user)s "
"must have password-less login to the remote host."
msgstr ""
#, python-format
msgid "Can not migrate virtual machine %(name)s when its in %(state)s state."
msgstr ""
#, python-format
msgid "Failed to migrate virtual machine %(name)s due error: %(err)s"
msgstr ""
msgid "User name of the remote server must be a string."
msgstr ""
msgid "Destination host of the migration must be a string."
msgstr ""
#, python-format
msgid "Unable to create file %(path)s at %(host)s using user %(user)s."
msgstr ""
#, python-format
msgid "Unable to read disk size of %(path)s, error: %(error)s"
msgstr ""
#, python-format
msgid ""
"Unable to create disk image %(path)s at %(host)s using user %(user)s. Error: "
"%(error)s"
msgstr ""
#, python-format
msgid ""
"Unable to migrate virtual machine to remote host %(host)s with arch "
"%(destarch)s using localhost with arch %(srcarch)s."
msgstr ""
#, python-format
msgid ""
"Unable to migrate virtual machine to remote host %(host)s with hypervisor "
"%(desthyp)s because localhost uses hypervisor %(srchyp)s."
msgstr ""
#, python-format
msgid ""
"Unable to determine remote host hypervisor and architecture. Error: %(error)s"
msgstr ""
#, python-format
msgid ""
"Unable to migrate virtual machine: subcores per core setting from "
"localhostand remote host %(host)s differs."
msgstr ""
#, python-format
msgid ""
"Unable to setup password-less login at remote host %(host)s using user "
"%(user)s. Error: %(error)s"
msgstr ""
msgid "Password field must be a string."
msgstr ""
msgid "Error creating local host ssh rsa key of user 'root'."
msgstr ""
#, python-format
msgid "%(param)s value (%(mem)sMiB) must be aligned to %(alignment)sMiB."
msgstr ""
#, python-format
msgid ""
"Unable to update the following parameters while the VM is offline: %(params)s"
msgstr ""
#, python-format
msgid ""
"Unable to update the following parameters while the VM is online: %(params)s"
msgstr ""
#, python-format
msgid ""
"VM %(name)s must have serial and console defined to open a web serial console"
msgstr ""
#, python-format
msgid "Impossible to get the serial console of %(name)s"
msgstr ""
#, python-format
msgid ""
"Memory or Maximum Memory value is higher than amount supported by the host: "
"%(memHost)sMiB."
msgstr ""
#, python-format
msgid ""
"Memory or Maximum Memory value is higher than maximum amount recommended: "
"%(value)sTiB"
msgstr ""
msgid "Cannot update Maximum Memory when guest is running."
msgstr ""
#, python-format
msgid "Impossible to create %(dir)s directory."
msgstr ""
#, python-format
msgid ""
"Either the guest %(name)s did not start to listen to the serial or it is not "
"configured to use the serial console."
msgstr ""
#, python-format
msgid ""
"Unable to retrieve Virt Viewer file for stopped virtual machine %(name)s"
msgstr ""
#, python-format
msgid ""
"Error occured while retrieving the Virt Viewer file for virtual machine "
"%(name)s : %(err)s"
msgstr ""
msgid "Virtual machine title must be a string"
msgstr ""
msgid "Virtual machine description must be a string"
msgstr ""
msgid "console parameter is only supported for s390x/s390 architecture."
msgstr ""
msgid "invalid console type, supported types are sclp/virtio."
msgstr ""
#, python-format
msgid ""
"Unable to setup password-less login at remote host %(host)s using user "
"%(user)s: remote directory %(sshdir)s does not exist."
msgstr ""
#, python-format
msgid ""
"Unable to create a password-less libvirt connection to the remote libvirt "
"daemon at host %(host)s with the user %(user)s. Please verify the remote "
"server libvirt configuration. More information: http://libvirt.org/auth."
"html ."
msgstr ""
msgid "'enable_rdma' must be of type boolean (true or false)."
msgstr ""
#, python-format
msgid ""
"VM %(vmid)s does not contain directly assigned host device %(dev_name)s."
msgstr ""
"VM %(vmid)s enthält die direkt zugewiesene Hosteinheit %(dev_name)s nicht."
#, python-format
msgid "The host device %(dev_name)s is not allowed to directly assign to VM."
msgstr ""
"Die Hosteinheit %(dev_name)s darf nicht direkt einer VM zugewiesen werden."
msgid ""
"No IOMMU groups found. Host PCI pass through needs IOMMU group to function "
"correctly. Please enable Intel VT-d or AMD IOMMU in your BIOS, then verify "
"the Kernel is compiled with IOMMU support. For Intel CPU, add "
"'intel_iommu=on' to GRUB_CMDLINE_LINUX parameter in /etc/default/grub file. "
"For AMD CPU, add 'iommu=pt iommu=1'."
msgstr ""
msgid "\"name\" should be a device name string"
msgstr "Für \"name\" muss eine Einheitennamenszeichenfolge angegeben werden"
#, python-format
msgid ""
"The device %(name)s is probably in use by the host. Unable to attach it to "
"the guest."
msgstr ""
"Die Einheit %(name)s wird vermutlich vom Host benutzt. Es kann keine "
"Verbindung der Einheit zum Gast hergestellt werden."
#, python-format
msgid "Hot-(un)plug of device %(name)s is not supported."
msgstr ""
#, python-format
msgid "Failed to attach %(device)s to %(vm)s"
msgstr ""
#, python-format
msgid "VM %(vmid)s does not have a USB controller to accept PCI hotplug."
msgstr ""
#, python-format
msgid "Interface %(iface)s does not exist in virtual machine %(name)s"
msgstr ""
"Schnittstelle %(iface)s ist in virtueller Maschine %(name)s nicht vorhanden"
#, python-format
msgid ""
"Network %(network)s specified for virtual machine %(name)s does not exist"
msgstr ""
"Das Netz %(network)s, das für die virtuelle Maschine %(name)s angegeben "
"wurde, ist nicht vorhanden"
msgid ""
"Supported virtual machine interfaces type are network, ovs and macvtap.Type "
"ovs and macvtap are only supported for s390x/s390 architecture."
msgstr ""
msgid "Network name for virtual machine interface must be a string"
msgstr ""
"Netzname für Schnittstelle einer virtuellen Maschine muss eine Zeichenfolge "
"sein"
msgid "Invalid network model card specified for virtual machine interface"
msgstr ""
"Ungültige Netzmodellkarte für Schnittstelle einer virtuellen Maschine "
"angegeben"
msgid "Specify type and network to add a new virtual machine interface"
msgstr ""
"Geben Sie Typ und Netz an, um eine neue Schnittstelle für eine virtuelle "
"Maschine hinzuzufügen"
msgid "MAC Address must respect this format FF:FF:FF:FF:FF:FF"
msgstr "MAC-Adresse muss folgendes Format verwenden: FF:FF:FF:FF:FF:FF"
#, python-format
msgid "MAC Address %(mac)s already exists in virtual machine %(name)s"
msgstr ""
"MAC-Adresse %(mac)s ist in virtueller Maschine %(name)s bereits vorhanden"
msgid "Invalid MAC Address"
msgstr "Ungültige MAC-Adresse"
msgid "Cannot change MAC address of a running virtual machine"
msgstr ""
"MAC-Adresse einer aktiven virtuellen Maschine kann nicht geändert werden"
msgid "Type macvtap and ovs are only supported on s390x/s390 architecture."
msgstr ""
msgid "Source attribute is only supported on s390x/s390 architecture."
msgstr ""
msgid "If source is provided, only type supported are macvtap and ovs."
msgstr ""
msgid "For type macvtap and ovs, source has to be provided"
msgstr ""
msgid "Source name for virtual machine interface must be string"
msgstr ""
msgid "Invalid source mode. Valid options are: bridge or vepa."
msgstr ""
#, python-format
msgid "Template %(name)s already exists"
msgstr "Vorlage %(name)s ist bereits vorhanden"
#, python-format
msgid "Source media %(path)s not found"
msgstr ""
#, python-format
msgid ""
"Network '%(network)s' specified for template %(template)s does not exist"
msgstr ""
"Netz '%(network)s', das für Vorlage %(template)s angegeben wurde, ist nicht "
"vorhanden"
#, python-format
msgid ""
"Storage pool %(pool)s specified for template %(template)s does not exist"
msgstr ""
"Speicherpool %(pool)s, der für Vorlage %(template)s angegeben wurde, ist "
"nicht vorhanden"
#, python-format
msgid "Invalid parameter '%(param)s' specified for CDROM."
msgstr "Ungültiger Parameter '%(param)s' für CD-ROM angegeben."
#, python-format
msgid "Network %(network)s specified for template %(template)s is not active"
msgstr ""
"Netz %(network)s, das für Vorlage %(template)s angegeben wurde, ist nicht "
"aktiv"
msgid "Template name must be a string"
msgstr "Vorlagenname muss eine Zeichenfolge sein"
msgid "Template icon must be a path to the image"
msgstr "Vorlagensymbol muss ein Pfad zum Image sein"
msgid "Template distribution must be a string"
msgstr "Vorlagenverteilung muss eine Zeichenfolge sein"
msgid "Template distribution version must be a string"
msgstr "Vorlagenverteilungsversion muss eine Zeichenfolge sein"
msgid "The number of CPUs must be an integer greater than 0"
msgstr "Die Anzahl der CPUs muss eine Ganzzahl größer als 0 sein"
msgid ""
"Amount of memory and maximum memory (MB) must be an integer greater than 512"
msgstr ""
msgid "Template CDROM must be a local or remote ISO file"
msgstr "Vorlagen-CD-ROM muss eine lokale oder ferne ISO-Datei sein"
#, python-format
msgid "Invalid storage pool URI %(value)s specified for template"
msgstr "Ungültiger Speicherpool-URI %(value)s für Vorlage angegeben"
msgid ""
"Specify a path to source media (ISO, disk or remote ISO) to create a template"
msgstr ""
msgid "All networks for the template must be specified in a list."
msgstr "Alle Netze für die Vorlage müssen in einer Liste angegeben werden."
msgid "Specify a volume to a template when storage pool is iSCSI or SCSI"
msgstr ""
"Geben Sie einen Datenträger für eine Vorlage an, wenn der Speicherpool iSCSI "
"oder SCSI ist"
#, python-format
msgid "The volume %(volume)s is not in storage pool %(pool)s"
msgstr ""
"Der Datenträger %(volume)s ist nicht im Speicherpool %(pool)s vorhanden"
#, python-format
msgid "Unable to create template due error: %(err)s"
msgstr ""
"Vorlage kann aufgrund des folgenden Fehlers nicht erstellt werden: %(err)s"
#, python-format
msgid "Unable to delete template due error: %(err)s"
msgstr ""
"Vorlage kann aufgrund des folgenden Fehlers nicht gelöscht werden: %(err)s"
msgid "Disk size must be an integer greater than 1GB."
msgstr "Plattengröße muss eine Ganzzahl größer als 1 GB sein."
#, python-format
msgid "Cannot identify base image %(path)s format"
msgstr "Format für %(path)s des Basisimage kann nicht ermittelt werden"
msgid ""
"When specifying CPU topology, each element must be an integer greater than "
"zero."
msgstr ""
"Bei Angabe der CPU-Topologie muss jedes Element eine Ganzzahl größer als "
"null sein."
msgid ""
"Invalid disk image format. Valid formats: qcow, qcow2, qed, raw, vmdk, vpc."
msgstr ""
msgid ""
"When setting template disks, following parameters are required: 'index', "
"'pool name', 'format', 'size' or 'volume' (for scsi/iscsi pools)"
msgstr ""
msgid "Disk format must be 'raw', for logical, iscsi, and scsi pools."
msgstr ""
msgid ""
"Memory expects an object with one or both parameters: 'current' and "
"'maxmemory'"
msgstr ""
#, python-format
msgid ""
"Memory value (%(mem)sMiB) must be equal or lesser than maximum memory value "
"(%(maxmem)sMiB)"
msgstr ""
#, python-format
msgid "Unable to update template due error: %(err)s"
msgstr ""
msgid "Parameter 'disks' requires at least one disk object"
msgstr ""
msgid ""
"Invalid interface type. Type should be 'macvtap' for host network interface "
"(Ethernet, Bond, VLAN) to be connected as direct MacVTap or 'ovs' for "
"openvswitch host network interface to be connected as virtual switch to a VM."
msgstr ""
msgid "Interface name should be string."
msgstr ""
msgid "Invalid interface mode. Valid options are: bridge or vepa."
msgstr ""
msgid ""
"Interfaces should be list of interfaces. Each interface should have name, "
"type and mode(optional, only applicable for interfcae type 'macvtap'."
msgstr ""
msgid ""
"Interface expects an object with parameters: 'name', 'type' and 'mode'. Name "
"should be name of host network interface (Ethernet, Bond, VLAN) for type "
"'macvtap' or the name of host openvswitch bridge interface for type 'ovs'. "
"Mode (optional) is only applicable for interface type 'macvtap' to indicates "
"whether packets will be delivered directly to target device (bridge) or to "
"the external bridge (vepa-capable bridge)."
msgstr ""
msgid "Interfaces parameter only supported on s390x or s390 architecture."
msgstr ""
msgid "Storage without libvirt pool is not supported on this architecture"
msgstr ""
#, python-format
msgid "Error while creating the virtual disk for the guest. Details: %(err)s"
msgstr ""
msgid ""
"When setting template disks without libvirt, following parameters are "
"required: 'index', 'format', 'path', 'size'"
msgstr ""
#, python-format
msgid "Storage pool %(name)s already exists"
msgstr "Speicherpool %(name)s ist bereits vorhanden"
#, python-format
msgid "Storage pool %(name)s does not exist"
msgstr "Speicherpool %(name)s ist nicht vorhanden"
#, python-format
msgid "Specify %(item)s in order to create the storage pool %(name)s"
msgstr "Geben Sie %(item)s an, um den Speicherpool %(name)s zu erstellen"
#, python-format
msgid "Unable to delete active storage pool %(name)s"
msgstr "Aktiver Speicherpool %(name)s konnte nicht gelöscht werden"
#, python-format
msgid "Unable to list storage pools. Details: %(err)s"
msgstr "Speicherpools konnten nicht aufgelistet werden. Details: %(err)s"
#, python-format
msgid "Unable to create storage pool %(name)s. Details: %(err)s"
msgstr "Speicherpool %(name)s konnte nicht erstellt werden. Details: %(err)s"
#, python-format
msgid "Unable to activate storage pool %(name)s. Details: %(err)s"
msgstr "Speicherpool %(name)s konnte nicht aktiviert werden. Details: %(err)s"
#, python-format
msgid "Unable to deactivate storage pool %(name)s. Details: %(err)s"
msgstr ""
"Speicherpool %(name)s konnte nicht inaktiviert werden. Details: %(err)s"
#, python-format
msgid "Unable to delete storage pool %(name)s. Details: %(err)s"
msgstr "Speicherpool %(name)s konnte nicht gelöscht werden. Details: %(err)s"
#, python-format
msgid ""
"Unable to create NFS Pool as export path %(path)s may block during mount"
msgstr ""
"NFS-Pool konnte nicht erstellt werden, weil Exportpfad %(path)s beim Mounten "
"blockieren kann"
#, python-format
msgid "Unable to create NFS Pool as export path %(path)s mount failed"
msgstr ""
"NFS-Pool konnte nicht erstellt werden, weil das Mounten des Exportpfads "
"%(path)s fehlgeschlagen ist"
#, python-format
msgid "Unsupported storage pool type: %(type)s"
msgstr "Nicht unterstützter Speicherpooltyp: %(type)s"
#, python-format
msgid "Error while retrieving storage pool XML to %(pool)s"
msgstr "Fehler beim Abrufen der XML für Speicherpool in %(pool)s"
msgid "Storage pool name must be a string without slashes (/)"
msgstr ""
"Name des Speicherpools muss eine Zeichenfolge ohne Schrägstriche (/) sein"
msgid ""
"Supported storage pool types are dir, netfs, logical, iscsi, isci and kimchi-"
"iso"
msgstr ""
"Unterstützte Speicherpooltypen sind dir, netfs, logical, iscsi, isci und "
"kimchi-iso"
msgid "Storage pool path must be a string"
msgstr "Speicherpoolpfad muss eine Zeichenfolge sein"
msgid "Storage pool host must be a IP or hostname"
msgstr "Speicherpoolhost muss eine IP oder ein Hostname sein"
msgid "Storage pool device must be the absolute path to the block device"
msgstr "Speicherpooleinheit muss den absoluten Pfad zur Blockeinheit angeben"
msgid "Storage pool devices parameter must be a list"
msgstr "Einheitenparameter des Speicherpools muss eine Liste sein"
msgid "Target IQN of an iSCSI pool must be a string"
msgstr "Ziel-IQN eines iSCSI-Pools muss eine Zeichenfolge sein"
msgid "Port of a remote storage server must be an integer between 1 and 65535"
msgstr ""
"Port eines fernen Speicherservers muss eine Ganzzahl zwischen 1 und 65535 "
"sein"
msgid "iSCSI target username must be a string"
msgstr "Benutzername des iSCSI-Ziels muss eine Zeichenfolge sein"
msgid "iSCSI target password must be a string"
msgstr "Kennwort des iSCSI-Ziels muss eine Zeichenfolge sein"
msgid "Specify name and type to create a storage pool"
msgstr "Geben Sie Name und Typ an, um einen Speicherpool zu erstellen"
#, python-format
msgid ""
"%(disk)s is not a valid disk/partition. Could not add it to the pool "
"%(pool)s."
msgstr ""
"%(disk)s ist keine gültige Platte/Partition. Sie konnte nicht hinzugefügt "
"werden zum Pool %(pool)s."
#, python-format
msgid "Unable to extend logical pool %(pool)s. Details: %(err)s"
msgstr ""
"Logischer Pool %(pool)s konnte nicht erweitert werden. Details: %(err)s"
msgid "The parameter disks only can be updated for logical storage pool."
msgstr ""
"Die Parameterplatten können nur für den logischen Speicherpool aktualisiert "
"werden."
msgid "The SCSI host adapter name must be a string."
msgstr "Der Name des SCSI-Hostadapters muss eine Zeichenfolge sein."
msgid "The storage pool kimchi_isos is reserved for internal use"
msgstr "Der Speicherpool kimchi_isos ist für die interne Verwendung reserviert"
#, python-format
msgid ""
"Unable to activate NFS storage pool %(name)s. NFS server %(server)s is "
"unreachable."
msgstr ""
"NFS-Speicherpool %(name)s konnte nicht aktiviert werden. NFS-Server "
"%(server)s ist nicht erreichbar."
#, python-format
msgid ""
"Unable to deactivate NFS storage pool %(name)s. NFS server %(server)s is "
"unreachable."
msgstr ""
"NFS-Speicherpool %(name)s konnte nicht inaktiviert werden. NFS-Server "
"%(server)s ist nicht erreichbar."
#, python-format
msgid ""
"Unable to deactivate pool %(name)s as it is associated with some templates"
msgstr ""
"Pool %(name)s konnte nicht inaktiviert werden, weil er einigen Vorlagen "
"zugeordnet ist"
#, python-format
msgid "Unable to delete pool %(name)s as it is associated with some templates"
msgstr ""
"Pool %(name)s konnte nicht gelöscht werden, weil er einigen Vorlagen "
"zugeordnet ist"
#, python-format
msgid ""
"A volume group named '%(name)s' already exists. Please, choose another name "
"to create the logical pool."
msgstr ""
"Eine Datenträgergruppe mit dem Namen '%(name)s' ist bereits vorhanden. "
"Wählen Sie einen anderen Namen aus, um den logischen Pool zu erstellen."
#, python-format
msgid "Unable to update database with deep scan information due error: %(err)s"
msgstr ""
"Datenbank mit Tiefenscaninformationen kann aufgrund des folgenden Fehlers "
"nicht aktualisiert werden: %(err)s"
#, python-format
msgid ""
"No volume group '%(name)s' found. Please, specify an existing volume group "
"to create the logical pool from."
msgstr ""
#, python-format
msgid "Unable to delete pool %(name)s as it is associated with guests: %(vms)s"
msgstr ""
#, python-format
msgid "Storage volume %(name)s already exists"
msgstr "Speicherdatenträger %(name)s ist bereits vorhanden"
#, python-format
msgid "Storage volume %(name)s does not exist in storage pool %(pool)s"
msgstr ""
"Speicherdatenträger %(name)s ist nicht im Speicherpool %(pool)s vorhanden"
#, python-format
msgid ""
"Unable to create storage volume %(volume)s because storage pool %(pool)s is "
"not active"
msgstr ""
"Speicherdatenträger %(volume)s konnte nicht erstellt werden, weil "
"Speicherpool %(pool)s nicht aktiv ist"
#, python-format
msgid "Specify %(item)s in order to create storage volume %(volume)s"
msgstr ""
"Geben Sie %(item)s an, um den Speicherdatenträger %(volume)s zu erstellen"
#, python-format
msgid ""
"Unable to list storage volumes because storage pool %(pool)s is not active"
msgstr ""
"Speicherdatenträger konnten nicht aufgelistet werden, weil Speicherpool "
"%(pool)s nicht aktiv ist"
#, python-format
msgid ""
"Unable to create storage volume %(name)s in storage pool %(pool)s. Details: "
"%(err)s"
msgstr ""
"Speicherdatenträger %(name)s konnte im Speicherpool %(pool)s nicht erstellt "
"werden. Details: %(err)s"
#, python-format
msgid "Unable to wipe storage volumes %(name)s. Details: %(err)s"
msgstr ""
"Speicherdatenträger %(name)s konnten nicht bereinigt werden. Details: %(err)s"
#, python-format
msgid "Unable to delete storage volume %(name)s. Details: %(err)s"
msgstr ""
"Speicherdatenträger %(name)s konnte nicht gelöscht werden. Details: %(err)s"
#, python-format
msgid "Unable to resize storage volume %(name)s. Details: %(err)s"
msgstr ""
"Größe des Speicherdatenträgers %(name)s konnte nicht geändert werden. "
"Details: %(err)s"
#, python-format
msgid "Storage type %(type)s does not support volume create and delete"
msgstr ""
"Speichertyp %(type)s unterstützt nicht das Erstellen und Löschen von "
"Datenträgern"
msgid "Storage volume name must be a string"
msgstr "Name des Speicherdatenträgers muss eine Zeichenfolge sein"
msgid "Storage volume allocation must be an integer number"
msgstr "Zuordnung des Speicherdatenträgers muss eine Ganzzahl sein"
msgid ""
"Storage volume format not supported. Valid formats: qcow, qcow2, qed, raw, "
"vmdk, vpc."
msgstr ""
msgid "Storage volume requires a volume name"
msgstr "Speicherdatenträger erfordert einen Datenträgernamen"
#, python-format
msgid ""
"Unable to update database with storage volume information due error: %(err)s"
msgstr ""
"Datenbank mit Datenträgerinformationen kann aufgrund des folgenden Fehlers "
"nicht aktualisiert werden: %(err)s"
#, python-format
msgid "Only one of parameter %(param)s can be specified"
msgstr "Der Parameter %(param)s kann nur einmal angegeben werden"
#, python-format
msgid "Create volume from %(param)s is not supported"
msgstr "Erstellung des Datenträgers aus %(param)s wird nicht unterstützt"
msgid "Storage volume capacity must be an integer number."
msgstr "Kapazität des Speicherdatenträgers muss eine Ganzzahl sein."
msgid "Storage volume URL must be http://, https://, ftp:// or ftps://."
msgstr ""
"Speicherdatenträger-URL muss eine http://-, https://-, ftp://- oder ftps://-"
"URL sein."
#, python-format
msgid "Unable to access file %(url)s. Please, check it."
msgstr ""
"Zugriff auf Datei %(url)s konnte nicht ausgeführt werden. Überprüfen Sie die "
"Datei."
#, python-format
msgid ""
"Unable to clone storage volume '%(name)s' in pool '%(pool)s'. Details: "
"%(err)s"
msgstr ""
"Speicherdatenträger '%(name)s' im Pool '%(pool)s' konnte nicht geklont "
"werden. Details: %(err)s"
msgid "Specify chunk data and its size to upload a file."
msgstr "Geben Sie Chunkdaten und deren Größe an, um eine Datei hochzuladen."
msgid "In order to upload a storage volume, specify the 'upload' parameter."
msgstr ""
"Um einen Speicherdatenträger hochzuladen, müssen Sie den Parameter 'upload' "
"angeben."
msgid ""
"Unable to upload chunk data as it does not match with requested chunk size."
msgstr ""
"Chunkdaten konnten nicht hochgeladen werden, da sie nicht mit der "
"angeforderten Chunkgröße übereinstimmen."
#, python-format
msgid "The storage volume %(vol)s is not under an upload process."
msgstr ""
"Der Speicherdatenträger %(vol)s befindet sich nicht in einem Uploadprozess."
msgid "The upload chunk data will exceed the storage volume size."
msgstr ""
"Die Chunkdaten für den Upload überschreiten die Größe des "
"Speicherdatenträgers."
#, python-format
msgid "Unable to upload chunk data to storage volume. Details: %(err)s."
msgstr ""
"Chunkdaten konnten nicht auf Speicherdatenträger hochgeladen werden. "
"Details: %(err)s."
#, python-format
msgid "Interface %(name)s does not exist"
msgstr "Schnittstelle %(name)s ist nicht vorhanden"
#, python-format
msgid ""
"Failed to list interfaces. Invalid _inuse parameter. Supported options for "
"_inuse are: %(supported_inuse)s"
msgstr ""
#, python-format
msgid "Network %(name)s already exists"
msgstr "Netz %(name)s ist bereits vorhanden"
#, python-format
msgid "Network %(name)s does not exist"
msgstr "Netz %(name)s ist nicht vorhanden"
#, python-format
msgid "Subnet %(subnet)s specified for network %(network)s is not valid."
msgstr ""
msgid "Specify a network interface to create bridged or macvtap networks."
msgstr ""
#, python-format
msgid "Unable to delete or update active network %(name)s"
msgstr ""
#, python-format
msgid "Interface %(iface)s specified for network %(network)s is already in use"
msgstr ""
"Die Schnittstelle %(iface)s, die für das Netz %(network)s angegeben wurde, "
"ist bereits belegt"
msgid "Interface should be bare NIC, bonding or bridge device."
msgstr "Schnittstelle sollte bloßes NIC, Bonding oder Brückeneinheit sein."
#, python-format
msgid "Unable to create or update network %(name)s. Details: %(err)s"
msgstr ""
#, python-format
msgid "Unable to find a free IP address for network '%(name)s'"
msgstr "Es konnte keine freie IP-Adresse für Netz '%(name)s' gefunden werden"
#, python-format
msgid "The interface %(iface)s already exists."
msgstr "Schnittstelle %(iface)s ist bereits vorhanden."
msgid "Network name must be a string without slashes (/) or quotes (\")"
msgstr ""
"Netzname muss eine Zeichenfolge ohne Schrägstriche (/) oder "
"Anführungszeichen (\") sein"
msgid ""
"Supported network types are isolated, NAT, macvtap, bridge, vepa and "
"passthrough."
msgstr ""
msgid "Network subnet must be a string with IP address and prefix or netmask"
msgstr ""
"Teilnetz des Netzes muss eine Zeichenfolge mit IP-Adresse und Präfix oder "
"Netzmaske sein"
msgid "Network interfaces must be an array."
msgstr ""
msgid "Network VLAN ID must be an integer between 1 and 4094"
msgstr "Netz-VLAN-ID muss eine Ganzzahl zwischen 1 und 4094 sein"
msgid "Specify name and type to create a Network"
msgstr "Geben Sie Name und Typ an, um ein Netz zu erstellen"
#, python-format
msgid ""
"Unable to delete or update network %(name)s as it is linked to some virtual "
"machines (%(vms)s) and/or templates (%(tmpls)s)."
msgstr ""
#, python-format
msgid ""
"Unable to deactivate network %(name)s as it is linked to are some virtual "
"machines (%(vms)s) and/or templates (%(tmpls)s)."
msgstr ""
#, python-format
msgid "Bridge device %(name)s can not be the trunk device of a VLAN."
msgstr "Brückeneinheit %(name)s kann nicht die Trunkeinheit eines VLAN sein."
#, python-format
msgid "Failed to activate interface %(iface)s: %(err)s."
msgstr "Schnittstelle %(iface)s konnte nicht aktiviert werden: %(err)s."
#, python-format
msgid ""
"Failed to activate interface %(iface)s. Please check the physical link "
"status."
msgstr ""
"Schnittstelle %(iface)s konnte nicht aktiviert werden. Überprüfen Sie den "
"Status der physischen Verbindung."
#, python-format
msgid "Failed to start network %(name)s. Details: %(err)s"
msgstr "Netz %(name)s konnte nicht gestartet werden. Details: %(err)s"
#, python-format
msgid "Unable to redefine interface %(name)s. Details: %(err)s"
msgstr ""
#, python-format
msgid "Unable to create bridge %(name)s. Details: %(err)s"
msgstr ""
msgid ""
"Unable to create bridge with NetworkManager enabled. Disable it and try "
"again."
msgstr ""
msgid "Interface should be bare NIC or bonding."
msgstr ""
msgid "Network interfaces parameter must contain at least one interface."
msgstr ""
msgid "Only one interface is allowed for 'bridge' and 'macvtap' networks."
msgstr ""
msgid "Subnet is not a valid parameter for this type of virtual network."
msgstr ""
msgid ""
"VLAN ID and interfaces are not valid parameters for this type of virtual "
"network."
msgstr ""
#, python-format
msgid "Storage server %(server)s was not used by Kimchi"
msgstr "Speicherserver %(server)s wurde nicht von Kimchi verwendet"
#, python-format
msgid "Distro '%(name)s' does not exist"
msgstr "Distro '%(name)s' ist nicht vorhanden"
#, python-format
msgid "Node device '%(name)s' not found"
msgstr "Knoteneinheit '%(name)s' nicht gefunden"
msgid "Conflicting flag filters specified."
msgstr "In Konflikt stehende Flagfilter angegeben."
msgid "Unable to choose a virtual machine name"
msgstr "Name der virtuellen Maschine konnte nicht ausgewählt werden"
msgid "Cannot upgrade objectstore data."
msgstr ""
msgid "Invalid storage type. Types supported: 'cdrom', 'disk'"
msgstr "Ungültiger Speichertyp. Unterstützte Typen: 'cdrom', 'disk'"
#, python-format
msgid "The path '%(value)s' is not a valid local/remote path for the device"
msgstr ""
"Der Pfad '%(value)s' ist kein gültiger lokaler/ferner Pfad für die Einheit"
msgid "Only CDROM path can be update."
msgstr "Nur der CD-ROM-Pfad kann aktualisiert werden."
#, python-format
msgid ""
"The storage device %(dev_name)s does not exist in the virtual machine "
"%(vm_name)s"
msgstr ""
"Die Speichereinheit %(dev_name)s ist in der virtuellen Maschine %(vm_name)s"
#, python-format
msgid "Error while creating new storage device: %(error)s"
msgstr "Fehler beim Erstellen einer neuen Speichereinheit: %(error)s"
#, python-format
msgid "Error while updating storage device: %(error)s"
msgstr "Fehler beim Aktualisieren einer Speichereinheit: %(error)s"
#, python-format
msgid "Error while removing storage device: %(error)s"
msgstr "Fehler beim Entfernen einer Speichereinheit: %(error)s"
msgid "Do not support IDE device hot plug"
msgstr "Hot Plug für IDE-Einheit nicht unterstützen"
msgid ""
"Specify type and path or type and pool/volume to add a new virtual machine "
"disk"
msgstr ""
"Geben Sie Typ und Pfad oder Typ und Pool/Datenträger an, um eine neue Platte "
"für eine virtuelle Maschine hinzuzufügen"
msgid "Specify path to update virtual machine disk"
msgstr ""
"Geben Sie einen Pfad an, um die Platte der virtuellen Maschine zu "
"aktualisieren"
#, python-format
msgid "Controller type %(type)s limitation of %(limit)s devices reached"
msgstr "Begrenzung von %(limit)s Einheiten bei Controllertyp %(type)s erreicht"
#, python-format
msgid "Cannot retrieve disk path information for given pool/volume: %(error)s"
msgstr ""
"Plattenpfadinformationen für angegebenen Pool/Datenträger können nicht "
"abgerufen werden: %(error)s"
msgid "Volume already in use by other virtual machine."
msgstr ""
"Datenträger wird bereits von einer anderen virtuellen Maschine verwendet."
msgid ""
"Only one of path or pool/volume can be specified to add a new virtual "
"machine disk"
msgstr ""
"Es kann nur ein Pfad oder ein Pool/Datenträger angegeben werden, um eine "
"neue Platte für die virtuelle Maschine hinzuzufügen"
#, python-format
msgid ""
"Volume chosen with format %(format)s does not fit in the storage type "
"%(type)s"
msgstr ""
"Ausgewählter Datenträger mit Format %(format)s passt nicht in Speichertyp "
"%(type)s"
msgid "On s390x arch one of pool, path of dir_path must be specified"
msgstr ""
msgid ""
"On s390x arch 'format' must be specified while attaching disk to virtual "
"machine"
msgstr ""
#, python-format
msgid "Virtual disk already exists on the system: %(disk_path)s"
msgstr ""
#, python-format
msgid ""
"Unable to create snapshot '%(name)s' on virtual machine '%(vm)s'. Details: "
"%(err)s"
msgstr ""
"Snapshot '%(name)s' kann auf virtueller Maschine '%(vm)s' nicht erstellt "
"werden. Details: %(err)s"
#, python-format
msgid "Snapshot '%(name)s' does not exist on virtual machine '%(vm)s'."
msgstr ""
"Snapshot '%(name)s' ist auf virtueller Maschine '%(vm)s' nicht vorhanden."
#, python-format
msgid ""
"Unable to retrieve snapshot '%(name)s' on virtual machine '%(vm)s'. Details: "
"%(err)s"
msgstr ""
"Snapshot '%(name)s' kann auf virtueller Maschine '%(vm)s' nicht abgerufen "
"werden. Details: %(err)s"
#, python-format
msgid "Unable to list snapshots on virtual machine '%(vm)s'. Details: %(err)s"
msgstr ""
"Snapshots können auf virtueller Maschine '%(vm)s' nicht aufgelistet werden. "
"Details: %(err)s"
#, python-format
msgid ""
"Unable to delete snapshot '%(name)s' on virtual machine '%(vm)s'. Details: "
"%(err)s"
msgstr ""
"Snapshot '%(name)s' kann auf virtueller Maschine '%(vm)s' nicht gelöscht "
"werden. Details: %(err)s"
#, python-format
msgid ""
"Unable to retrieve current snapshot of virtual machine '%(vm)s'. Details: "
"%(err)s"
msgstr ""
"Aktueller Snapshot der virtuellen Maschine '%(vm)s' kann nicht abgerufen "
"werden. Details: %(err)s"
#, python-format
msgid ""
"Unable to revert virtual machine '%(vm)s' to snapshot '%(name)s'. Details: "
"%(err)s"
msgstr ""
"Virtuelle Maschine '%(vm)s' kann nicht auf Snapshot '%(name)s' zurückgesetzt "
"werden. Details: %(err)s"
#, python-format
msgid ""
"Unable to create snapshot of virtual machine '%(vm)s' because it contains a "
"disk with format '%(format)s'; only 'qcow2' is supported."
msgstr ""
"Snapshot der virtuellen Maschine '%(vm)s' kann nicht erstellt werden, weil "
"er eine Platte im Format '%(format)s' enthält. Nur 'qcow2' wird unterstützt."
msgid ""
"The number of vCPUs must be less than or equal the maximum number of vCPUs "
"specified."
msgstr ""
msgid ""
"When CPU topology is defined, maximum number of vCPUs must be a product of "
"sockets, cores, and threads."
msgstr ""
msgid "This host (or current configuration) does not allow CPU topology."
msgstr ""
"Dieser Host (oder die aktuelle Konfiguration) erlaubt keine CPU-Topologie."
msgid "The maximum number of vCPUs is too large for this system."
msgstr ""
msgid ""
"When CPU topology is defined, CPUs must be a multiple of the 'threads' "
"number defined."
msgstr ""
msgid ""
"When CPU topology is specified, sockets, cores and threads are required "
"paramaters."
msgstr ""
msgid ""
"Parameter 'cpu_info' expects an object with fields among: 'vcpus', "
"'maxvcpus', 'topology'."
msgstr ""
msgid ""
"Parameter 'topology' expects an object with fields among: 'sockets', "
"'cores', 'threads'."
msgstr ""
msgid "Unable to update Max CPU or CPU topology when guest is running."
msgstr ""
#, python-format
msgid "Unable to hot plug/unplug CPUs. Details: %(err)s"
msgstr ""
#, python-format
msgid "Invalid volume group name parameter: %(name)s."
msgstr ""
msgid ""
"Unable to establish connection with libvirt. Please check your libvirt URI "
"which is often defined in /etc/libvirt/libvirt.conf"
msgstr ""
msgid ""
"Libvirt service is not active. Please start the libvirt service in your host "
"system."
msgstr ""
msgid "Failed to register the default event implementation."
msgstr ""
msgid "Failed to register timeout event."
msgstr ""
msgid "Failed to Run the default event implementation."
msgstr ""
#, python-format
msgid ""
"I/O error on guest '%(vm)s': storage pool out of space for %(devAlias)s "
"(%(srcPath)s)."
msgstr ""
#, python-format
msgid "Create virtual network '%(name)s' type '%(connection)s'"
msgstr ""
#, python-format
msgid "Remove virtual network '%(ident)s'"
msgstr ""
#, python-format
msgid "Update virtual network '%(ident)s'"
msgstr ""
#, python-format
msgid "Activate virtual network '%(ident)s'"
msgstr ""
#, python-format
msgid "Deactivate virtual network '%(ident)s'"
msgstr ""
#, python-format
msgid "Create storage pool '%(name)s' type '%(type)s'"
msgstr ""
#, python-format
msgid "Remove storage pool '%(ident)s'"
msgstr ""
#, python-format
msgid "Update storage pool '%(ident)s'"
msgstr ""
#, python-format
msgid "Activate storage pool '%(ident)s'"
msgstr ""
#, python-format
msgid "Deactivate storage pool '%(ident)s'"
msgstr ""
#, python-format
msgid "Create snapshot '%(name)s' at guest '%(vm)s'"
msgstr ""
#, python-format
msgid "Remove snapshot '%(ident)s' from guest '%(vm)s'"
msgstr ""
#, python-format
msgid "Revert guest '%(vm)s' to snapshot '%(ident)s'"
msgstr ""
#, python-format
msgid "Create template '%(name)s'"
msgstr ""
#, python-format
msgid "Remove template '%(ident)s'"
msgstr ""
#, python-format
msgid "Update template '%(ident)s'"
msgstr ""
#, python-format
msgid "Clone template '%(ident)s'"
msgstr ""
#, python-format
msgid "Create guest '%(name)s' from template '%(template)s'"
msgstr ""
#, python-format
msgid "Remove guest '%(ident)s'"
msgstr ""
#, python-format
msgid "Edit guest '%(ident)s'"
msgstr ""
#, python-format
msgid "Start guest '%(ident)s'"
msgstr ""
#, python-format
msgid "Power off guest '%(ident)s'"
msgstr ""
#, python-format
msgid "Shutdown guest '%(ident)s'"
msgstr ""
#, python-format
msgid "Restart guest '%(ident)s'"
msgstr ""
#, python-format
msgid "Connect to guest '%(ident)s' through novnc/spice"
msgstr ""
#, python-format
msgid "Clone guest '%(ident)s'"
msgstr ""
#, python-format
msgid "Migrate guest '%(ident)s' to '%(remote_host)s'"
msgstr ""
#, python-format
msgid "Suspend guest '%(ident)s'"
msgstr ""
#, python-format
msgid "Resume guest '%(ident)s'"
msgstr ""
#, python-format
msgid "Connect to guest '%(ident)s' through serial"
msgstr ""
#, python-format
msgid "Attach host device '%(name)s' to guest '%(vmid)s'"
msgstr ""
#, python-format
msgid "Detach host device '%(ident)s' from guest '%(vmid)s'"
msgstr ""
#, python-format
msgid "Attach network interface '%(network)s' to guest '%(vm)s'"
msgstr ""
#, python-format
msgid "Detach network interface '%(ident)s' from guest '%(vm)s'"
msgstr ""
#, python-format
msgid "Update network interface '%(ident)s' at guest '%(vm)s'"
msgstr ""
#, python-format
msgid "Attach %(type)s storage '%(path)s' to guest '%(vm)s'"
msgstr ""
#, python-format
msgid "Remove storage '%(ident)s' from guest '%(vm)s'"
msgstr ""
#, python-format
msgid "Update storage '%(ident)s' at guest '%(vm)s'"
msgstr ""
#, python-format
msgid "Create storage volume '%(name)s' at pool '%(pool)s'"
msgstr ""
#, python-format
msgid "Remove storage volume '%(ident)s' from pool '%(pool)s'"
msgstr ""
#, python-format
msgid "Update storage volume '%(ident)s' at pool '%(pool)s'"
msgstr ""
#, python-format
msgid "Wipe storage volume '%(ident)s' off pool '%(pool)s'"
msgstr ""
#, python-format
msgid "Resize storage volume '%(ident)s' at pool '%(pool)s' with size %(size)s"
msgstr ""
#, python-format
msgid "Clone storage volume '%(ident)s' at pool '%(pool)s'"
msgstr ""
msgid "Create a New Virtual Machine"
msgstr "Neue virtuelle Maschine erstellen"
msgid "Virtual Machine Name"
msgstr "Name der virtuellen Maschine"
msgid ""
"The name used to identify the virtual machine. If omitted, a name will be "
"chosen based on the template used."
msgstr ""
"Der für die Kennzeichnung der virtuellen Maschine verwendete Name. Falls er "
"ausgelassen wird, wird ein Name anhand der verwendeten Vorlage ausgewählt."
msgid "Please create a template first."
msgstr "Erstellen Sie zunächst eine Vorlage."
msgid "Create a Template"
msgstr "Vorlage erstellen"
msgid "Please choose a template."
msgstr "Wählen Sie eine Vorlage aus."
msgid "This template has invalid parameters."
msgstr ""
msgid "This template has invalid parameters"
msgstr ""
msgid "OS"
msgstr "BS"
msgid "Version"
msgstr "Version"
msgid "Current CPUs"
msgstr ""
msgid "Memory"
msgstr "Speicher"
msgid "Create"
msgstr "Erstellen"
msgid "Creating..."
msgstr "Wird erstellt..."
msgid "Cancel"
msgstr "Abbrechen"
msgid "Clone a Guest"
msgstr ""
msgid ""
"When the target guest has SCSI or iSCSI volumes, they will be cloned on the "
"default storage pool. The same will happen when the target pool does not "
"have enough space to clone the volumes. Do you want to continue?"
msgstr ""
msgid "Number of times to clone"
msgstr ""
msgid "Continue"
msgstr ""
msgid "Edit Guest"
msgstr "Gast bearbeiten"
msgid "General"
msgstr "Allgemein"
msgid "Storage"
msgstr "Speicher"
msgid "Interface"
msgstr "Schnittstelle"
msgid "Permission"
msgstr ""
msgid "Pci"
msgstr ""
msgid "Snapshot"
msgstr ""
msgid "Processor"
msgstr "Prozessor"
msgid "Name"
msgstr "Name"
msgid "Memory (MB)"
msgstr "Speicher (MB)"
msgid "More"
msgstr ""
msgid "Max Memory (MB)"
msgstr ""
msgid "Host does not support memory hotplug"
msgstr ""
msgid "Icon"
msgstr "Symbol"
msgid "Console"
msgstr ""
msgid "Nothing selected"
msgstr ""
msgid "sclp"
msgstr ""
msgid "virtio"
msgstr ""
msgid ""
"Select which items for boot order and grad them when needed to order them. "
"At least one option must be selected."
msgstr ""
msgid "Add"
msgstr "Hinzufügen"
msgid "Device"
msgstr "Einheit"
msgid "Path"
msgstr "Pfad"
msgid "Actions"
msgstr "Aktionen"
msgid "Network"
msgstr "Netz"
msgid "Type"
msgstr "Typ"
msgid "MAC Address"
msgstr "MAC-Adresse"
msgid "IP Address"
msgstr ""
msgid "Network/Interface"
msgstr ""
msgid "Mode"
msgstr ""
msgid "Available system users and groups"
msgstr "Verfügbare Systembenutzer und -gruppen"
msgid "Users"
msgstr "Benutzer"
msgid "Groups"
msgstr "Gruppen"
msgid "Selected system users and groups"
msgstr "Ausgewählte Systembenutzer und -gruppen"
msgid "User"
msgstr "Benutzer"
msgid "All"
msgstr "Alle"
msgid "To Add"
msgstr "Hinzuzufügen"
msgid "Added"
msgstr "Hinzugefügt"
msgid "Filter"
msgstr ""
msgid "Status"
msgstr ""
msgid "Product"
msgstr "Produkt"
msgid "Vendor"
msgstr "Anbieter"
msgid "Loading"
msgstr ""
msgid "Created"
msgstr "Erstellt"
msgid "Current CPU Number"
msgstr ""
msgid ""
"Current CPU must be equal or lower than the Maximum CPU value. If a topology "
"is set, it must be also be a multiple of the 'threads' value."
msgstr ""
msgid "Max CPU"
msgstr ""
msgid ""
"Unable to edit maximum CPU or CPU topology when editing a running or paused "
"virtual machine."
msgstr ""
msgid ""
"If a topology is set, this value will be the product of sockets * times * "
"cores."
msgstr ""
msgid "Manually set CPU topology"
msgstr "CPU-Topologie manuell festlegen"
msgid "Sockets"
msgstr ""
msgid "Cores"
msgstr "Kerne"
msgid "Threads"
msgstr "Threads"
msgid "Save"
msgstr "Speichern"
msgid "Replace"
msgstr "Ersetzen"
msgid "Detach"
msgstr "Abhängen"
msgid "Remove"
msgstr "Entfernen"
msgid "Edit"
msgstr "Bearbeiten"
msgid "LDAP User ID,e.g.foo@foo.com"
msgstr "LDAP-Benutzer-ID, z. B. foo@foo.com"
msgid "Revert"
msgstr ""
msgid "Running"
msgstr ""
msgid "Disconnected"
msgstr ""
msgid "Starting"
msgstr ""
msgid "Crashed"
msgstr ""
msgid "Unknown"
msgstr ""
msgid "Paused"
msgstr ""
msgid "Suspended"
msgstr ""
msgid "Resetting"
msgstr ""
msgid "View Console"
msgstr ""
msgid "View Serial"
msgstr ""
msgid "Clone"
msgstr "Klonen"
msgid "Migrate"
msgstr ""
msgid "Reset"
msgstr "Zurücksetzen"
msgid "Pause"
msgstr "Anhalten"
msgid "Resume"
msgstr "Fortsetzen"
msgid "Shut Down"
msgstr "Herunterfahren"
msgid "Start"
msgstr "Starten"
msgid "Power Off"
msgstr "Ausschalten"
msgid "Delete"
msgstr "Löschen"
msgid "No Data Available"
msgstr ""
msgid "Processors Utilization"
msgstr ""
msgid "Memory Utilization"
msgstr ""
msgid "Storage I/O"
msgstr ""
msgid "Network I/O"
msgstr "Netz-E/A"
msgid "Migrate a Guest"
msgstr ""
msgid ""
"Disclaimer: This process cannot be stopped after started, can take a long "
"time to complete and will turn off the VM on this Hypervisor when it is "
"successfully migrated to the remote destination."
msgstr ""
msgid "Remote Server"
msgstr ""
msgid "IP Address or Hostname"
msgstr ""
msgid ""
"The following fields are optional. Fill them if you want Kimchi to setup a "
"password-less ssh session between the localhost and the remote host. The "
"setup process will only be successful if the user has 'SUDO ALL' permission "
"in the remote machine."
msgstr ""
msgid "Username of the remote host"
msgstr ""
msgid "Password"
msgstr "Kennwort"
msgid "Password of the user in the remote host"
msgstr ""
msgid "Use RDMA transport"
msgstr ""
msgid ""
"Check this option only if RDMA is properly configured in both source and "
"destination hosts, otherwise migration will fail."
msgstr ""
msgid "Delete this VM when the migration is completed"
msgstr ""
msgid "Add a Storage Device to VM"
msgstr "Speichereinheit zur virtuellen Maschine hinzufügen"
msgid "Device Type"
msgstr "Einheitentyp"
msgid ""
"The device type. Currently, \"cdrom\" and \"disk\" are supported. If the "
"guest is running, only \"disk\" is supported."
msgstr ""
msgid "Create a new disk"
msgstr ""
msgid "Select an existing disk"
msgstr ""
msgid "Source"
msgstr ""
msgid "Storage based on Libvirt pool or direct block device"
msgstr ""
msgid "Storage Pool"
msgstr "Speicherpool"
msgid "Storage pool to create the volume in"
msgstr ""
msgid "Disk Size (GB)"
msgstr ""
msgid "New disk size to be created"
msgstr ""
msgid "Format"
msgstr ""
msgid "Format of the new disk to be created"
msgstr ""
msgid "Directory Path"
msgstr ""
msgid "Provide a directory path"
msgstr ""
msgid "Storage pool in which the volume is located in"
msgstr ""
msgid "Storage Volume"
msgstr "Speicherdatenträger"
msgid "Storage volume to be attached"
msgstr "Anzuhängender Speicherdatenträger"
msgid "Disk Path"
msgstr ""
msgid "Provide a block device"
msgstr ""
msgid "File Path"
msgstr "Dateipfad"
msgid "The ISO file path in the server for CDROM."
msgstr "Der ISO-Dateipfad auf dem Server für die CD-ROM."
msgid "Attach"
msgstr "Anhängen"
msgid "Host"
msgstr "Host"
msgid "Guests"
msgstr "Gäste"
msgid "Templates"
msgstr "Vorlagen"
msgid "This is not a valid Linux path"
msgstr "Dies ist kein gültiger Linux-Pfad"
msgid "Unable to read file."
msgstr "Datei konnte nicht gelesen werden."
msgid "Error while uploading file."
msgstr "Fehler beim Hochladen der Datei."
msgid "Delete Confirmation"
msgstr "Löschbestätigung"
msgid "OK"
msgstr "OK"
msgid "Confirm"
msgstr "Bestätigen"
msgid "Warning"
msgstr "Warnung"
msgid "Cloning..."
msgstr "Wird geklont..."
msgid "Saving..."
msgstr ""
msgid "Migrating..."
msgstr ""
msgid "No ISO found"
msgstr "Keine ISO-Datei gefunden"
msgid "Add Template"
msgstr "Vorlage hinzufügen"
msgid "This may take a long time. Do you want to continue?"
msgstr "Dieser Vorgang kann lange dauern. Möchten Sie fortfahren?"
msgid ""
"This will permanently delete the %1 template. Would you like to continue?"
msgstr ""
msgid "View Table"
msgstr ""
msgid "View Gallery"
msgstr ""
msgid "Not Available"
msgstr ""
msgid "Please check the invalid Storage Pools"
msgstr ""
msgid "Please check the invalid Storage Pools or Paths"
msgstr ""
msgid "macvtap"
msgstr ""
msgid "ovs"
msgstr ""
msgid "network"
msgstr ""
msgid ""
"This will delete the %1 virtual machine and its virtual disks. This "
"operation cannot be undone. Would you like to continue?"
msgstr ""
msgid "Power off Confirmation"
msgstr "Ausschalten bestätigen"
msgid ""
"This action may produce undesirable results, for example unflushed disk "
"cache in the %1 guest. Would you like to continue?"
msgstr ""
msgid "Reset Confirmation"
msgstr "Zurücksetzung bestätigen"
msgid ""
"There is a risk of data loss caused by reset without the %1 guest OS "
"shutdown. Would you like to continue?"
msgstr ""
msgid "Shut Down Confirmation"
msgstr "Herunterfahren bestätigen"
msgid ""
"Note the %1 guest OS may ignore this request. Would you like to continue?"
msgstr ""
msgid "Virtual Machine delete Confirmation"
msgstr "Löschbestätigung für virtuelle Maschine"
msgid ""
"The %1 virtual machine is not persistent. Power Off will delete it. Continue?"
msgstr ""
msgid "Add Guest"
msgstr ""
msgid "Input is not a number"
msgstr ""
msgid "Memory value cannot be higher than Max Memory value"
msgstr ""
msgid ""
"For better performance it is recommended a threads per core value not "
"greater than %1."
msgstr ""
msgid ""
"This CDROM will be detached permanently and you can re-attach it. Continue "
"to detach it?"
msgstr ""
"Diese CD-ROM wird dauerhaft abgehängt und Sie können sie neu anhängen. "
"Möchten Sie mit dem Abhängen fortfahren?"
msgid "Attaching..."
msgstr "Wird angehängt..."
msgid ""
"This disk will be detached permanently and you can re-attach it. Continue to "
"detach it?"
msgstr ""
"Diese Platte wird dauerhaft abgehängt und Sie können sie neu anhängen. "
"Möchten Sie mit dem Abhängen fortfahren?"
msgid "interface:"
msgstr "Schnittstelle:"
msgid "address:"
msgstr "Adresse:"
msgid "link_type:"
msgstr "Linktyp:"
msgid "block:"
msgstr "Block:"
msgid "drive_type:"
msgstr "Laufwerkstyp:"
msgid "model:"
msgstr "Modell:"
msgid "Affected devices:"
msgstr "Betroffene Einheiten:"
msgid "Less"
msgstr ""
msgid "Successfully attached device to VM"
msgstr ""
msgid "Successfully detached device from VM"
msgstr ""
msgid "Following devices will be affected, confirm?"
msgstr ""
msgid "Bridge"
msgstr ""
msgid "Vepa"
msgstr ""
msgid "None"
msgstr ""
msgid "unavailable"
msgstr "nicht verfügbar"
msgid ""
"This action will interrupt network connectivity for any virtual machine that "
"depend on the %1 network."
msgstr ""
msgid "Add Network"
msgstr ""
msgid ""
"The %1 network is not persistent. Instead of stop, this action will "
"permanently delete it. Would you like to continue?"
msgstr ""
msgid ""
"The bridged VLAN tag may not work well with NetworkManager enabled. You "
"should consider disabling it."
msgstr ""
"Der überbrückte VLAN-Tag arbeitet möglicherweise nicht korrekt, wenn der "
"Netzmanager aktiviert ist. Sie sollten ihn eventuell inaktivieren."
msgid ""
"This will permanently delete the %1 storage pool. Would you like to continue?"
msgstr ""
msgid "This storage pool is empty."
msgstr "Dieser Speicherpool ist leer."
msgid ""
"It will format your disk and you will loose any data in there, are you sure "
"to continue? "
msgstr ""
"Hiermit wird Ihre Platte formatiert und Sie verlieren sämtliche Daten "
"darauf. Sind Sie sicher, dass Sie fortfahren möchten? "
msgid "SCSI Fibre Channel"
msgstr "SCSI-Fibre Channel"
msgid "No SCSI adapters found."
msgstr "Keine SCSI-Adapter gefunden."
msgid "Loading iSCSI targets..."
msgstr "iSCSI-Ziele werden geladen..."
msgid "No iSCSI found. Please input one."
msgstr "iSCSI wurde nicht gefunden. Nehmen Sie die iSCSI-Eingabe vor."
msgid "Failed to load iSCSI targets."
msgstr "iSCSI-Ziele konnten nicht geladen werden."
msgid "Would you like to continue?"
msgstr ""
msgid "This will permanently delete the following storage volumes: %1"
msgstr ""
msgid "No available partitions found."
msgstr "Keine gültigen Partitionen gefunden."
msgid ""
"The %1 storage pool is not persistent. Instead of deactivate, this action "
"will permanently delete it. Would you like to continue?"
msgstr ""
msgid "Unable to retrieve partitions information."
msgstr "Partitionsinformationen konnten nicht abgerufen werden."
msgid "In progress..."
msgstr "In Bearbeitung..."
msgid "Failed!"
msgstr "Fehlgeschlagen!"
msgid "No LVM found in the system."
msgstr ""
msgid "This will permanently wipe the following storage volumes: %1"
msgstr ""
msgid "Wipe Confirmation"
msgstr ""
msgid "Select one or more partitions to be added to the logical pool %1:"
msgstr ""
msgid "Add Storage"
msgstr ""
msgid "DIR"
msgstr ""
msgid "NFS"
msgstr ""
msgid "iSCSI"
msgstr ""
msgid "LOGICAL"
msgstr ""
msgid "device"
msgstr ""
msgid "path"
msgstr ""
msgid "size (GiB)"
msgstr ""
msgid "free size (GiB)"
msgstr ""
msgid "Invalid NFS mount path."
msgstr "Ungültiger NFS-Mountpfad."
msgid "No logical device selected."
msgstr "Keine logische Einheit ausgewählt."
msgid "This is not a valid Server Name or IP. Please, modify it."
msgstr ""
"Dies ist kein gültiger Servername oder keine gültige IP. Ändern Sie den "
"Servernamen oder die IP."
msgid "CDROM path needs to be a valid local/remote path and cannot be blank."
msgstr ""
"Der CD-ROM-Pfad muss ein gültiger lokaler/ferner Pfad sein. Er darf nicht "
"leer sein."
msgid "Disk pool or volume cannot be blank."
msgstr "Der Plattenpool oder Datenträger darf nicht leer sein."
msgid ""
"Disk size or Format or Directory path cannot be blank and Directory path "
"needs to be a valid local/remote path."
msgstr ""
msgid "Disk path needs to be a valid local/remote path and cannot be blank."
msgstr ""
msgid "Storage pool or Disk size or Format cannot be blank."
msgstr ""
msgid "cdrom"
msgstr ""
msgid "disk"
msgstr ""
msgid "Pool"
msgstr ""
msgid "qcow"
msgstr ""
msgid "qcow2"
msgstr ""
msgid "qed"
msgstr ""
msgid "raw"
msgstr ""
msgid "vmdk"
msgstr ""
msgid "vpc"
msgstr ""
msgid "Create a network"
msgstr "Netz erstellen"
msgid "Network Name"
msgstr "Netzname"
msgid "Name should not contain '/' and '\"'."
msgstr "Der Name darf weder '/' noch '\"' enthalten."
msgid "Network Type"
msgstr "Netztyp"
msgid "Isolated: no external network connection"
msgstr "Isoliert: keine externe Netzverbindung"
msgid "NAT: outbound physical network connection only"
msgstr "NAT: nur ausgehende physische Netzverbindung"
msgid "Macvtap: Virtual machines are connected to physical network directly"
msgstr ""
msgid ""
"Passthrough: Virtual machines are connected using a macvtap connection in "
"passthrough mode."
msgstr ""
msgid ""
"VEPA: special mode where virtual machines are connected to a VEPA-enabled "
"switch"
msgstr ""
msgid "Bridged: Virtual machines are connected through a network bridge"
msgstr ""
msgid "Destination"
msgstr "Zieladresse"
msgid "Select an Interface"
msgstr ""
msgid "Enable VLAN"
msgstr "VLAN aktivieren"
msgid "VLAN ID"
msgstr "VLAN-ID"
msgid "Edit Network"
msgstr ""
msgid "Address Space"
msgstr ""
msgid "Define a New Storage Pool"
msgstr "Neuen Speicherpool definieren"
msgid "Storage Pool Name"
msgstr "Speicherpoolname"
msgid ""
"The name used to identify the storage pools, and it should not be empty."
msgstr ""
"Der Name, mit dem die Speicherpools gekennzeichnet werden. Er darf nicht "
"leer sein."
msgid "Storage Pool Type"
msgstr "Speicherpooltyp"
msgid "Storage Path"
msgstr "Speicherpfad"
msgid ""
"The path of the Storage Pool. Each Storage Pool must have a unique path."
msgstr ""
"Der Pfad des Speicherpools. Jeder Speicherpool muss einen eindeutigen Pfad "
"haben."
msgid ""
"Kimchi will try to create the directory when it does not already exist in "
"your system."
msgstr ""
"Kimchi versucht, das Verzeichnis zu erstellen, wenn es noch nicht in Ihrem "
"System vorhanden ist."
msgid "NFS Server IP"
msgstr "NFS-Server-IP"
msgid "NFS server IP or hostname. It can be input or chosen from history."
msgstr ""
"IP oder Hostname des NFS-Servers. Diese(r) kann eingegeben oder aus dem "
"Verlauf ausgewählt werden."
msgid "NFS Path"
msgstr "NFS-Pfad"
msgid "The NFS exported path on NFS server."
msgstr "Der NFS-Exportpfad auf dem NFS-Server."
msgid "Create from existing LVM"
msgstr ""
msgid "Create from raw disk"
msgstr ""
msgid "Looking for existing lvms ..."
msgstr ""
msgid "Looking for available partitions ..."
msgstr "Es wird nach verfügbaren Partitionen gesucht..."
msgid "iSCSI Server"
msgstr "iSCSI-Server"
msgid "Server"
msgstr "Server"
msgid "Port"
msgstr "Port"
msgid "iSCSI server IP or hostname. It should not be empty."
msgstr "IP oder Hostname des iSCSI-Servers. Diese(r) darf nicht leer sein."
msgid "Target"
msgstr "Ziel"
msgid "The iSCSI target on iSCSI server"
msgstr "Das iSCSI-Ziel auf dem iSCSI-Server"
msgid "Add iSCSI Authentication"
msgstr "iSCSI-Authentifizierung hinzufügen"
msgid "User Name"
msgstr "Benutzername"
msgid "SCSI Adapter"
msgstr "SCSI-Adapter"
msgid "Please, wait..."
msgstr "Bitte warten..."
msgid "Add a Volume to Storage Pool"
msgstr "Datenträger zu Speicherpool hinzufügen"
msgid "Fetch from remote URL"
msgstr "Über Remote URL abrufen"
msgid "Enter the remote URL here."
msgstr "Remote URL hier eingeben."
msgid "Upload a file"
msgstr "Datei hochladen"
msgid "Choose the file you want to upload."
msgstr "Wählen Sie die hochzuladende Datei aus."
msgid "Resize Volume"
msgstr ""
msgid "Size"
msgstr ""
msgid "The total space which can be used to store data. The unit is megabytes."
msgstr ""
msgid "Ok"
msgstr ""
msgid "Template Name"
msgstr ""
msgid ""
"The name used to identify the template. If omitted, a name will be "
"automatically chosen."
msgstr ""
msgid ""
"When selecting more than one Image Template, a name will be automatically "
"chosen for each Image Template selected."
msgstr ""
msgid "Where is the source media for this template? "
msgstr ""
msgid "Image Template"
msgstr ""
msgid "Netboot Template"
msgstr ""
msgid "File Path:"
msgstr "Dateipfad:"
msgid "Search ISOs"
msgstr "ISOs suchen"
msgid "The following ISOs are available:"
msgstr "Die folgenden ISOs sind verfügbar:"
msgid "QEMU does not have enough permission to work with this file"
msgstr ""
msgid "Search more ISOs"
msgstr "Weitere ISOs suchen"
msgid "Loading..."
msgstr ""
msgid "Edit Template"
msgstr "Vorlage bearbeiten"
msgid "CDROM"
msgstr "CD-ROM"
msgid "Image File"
msgstr "Imagedatei"
msgid "Graphics"
msgstr "Grafik"
msgid "Disk(GB)"
msgstr "Festplatte (GB)"
msgid "Disk Format"
msgstr "Plattenformat"
msgid "Add Interface"
msgstr ""
msgid "pool"
msgstr ""
msgid "bridge"
msgstr ""
msgid "vepa"
msgstr ""
msgid "State"
msgstr ""
msgid "Guest Name ID"
msgstr ""
msgid "OS Type"
msgstr ""
msgid "VNC"
msgstr ""
msgid "No guests found."
msgstr ""
msgid "Stop"
msgstr ""
msgid "Location"
msgstr ""
msgid "%Used"
msgstr ""
msgid "Allocated"
msgstr ""
msgid "Capacity"
msgstr ""
msgid "Disks"
msgstr ""
msgid "Extending logical pool"
msgstr ""
msgid "%"
msgstr ""
msgid "Deactivate"
msgstr ""
msgid "Activate"
msgstr ""
msgid "Extend"
msgstr ""
msgid "Undefine"
msgstr ""
msgid "Add Volume"
msgstr ""
msgid "Resize"
msgstr ""
msgid "Wipe"
msgstr ""
msgid "Filter:"
msgstr ""
msgid "Used By"
msgstr ""
msgid "Used"
msgstr ""
msgid "Progress"
msgstr ""
msgid "Used by the following VMs:"
msgstr ""
msgid "Allocation"
msgstr ""
msgid "Template Name (ID)"
msgstr ""
msgid "No templates found."
msgstr ""
msgid "M"
msgstr ""
================================================
FILE: po/en_US.po
================================================
# English translations for kimchi package.
# Copyright IBM Corp, 2013-2017
# Adam Litke , 2013.
#
msgid ""
msgstr ""
"Project-Id-Version: kimchi 0.1\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2017-06-30 10:27-0300\n"
"PO-Revision-Date: 2013-07-11 17:32-0400\n"
"Last-Translator: Crístian Viana \n"
"Language-Team: English\n"
"Language: en_US\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: pygettext.py 1.5\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#, python-format
msgid "Unknown parameter %(value)s"
msgstr ""
#, python-format
msgid "User %(user_id)s not found with given LDAP settings."
msgstr ""
#, python-format
msgid "Partition %(name)s does not exist in the host"
msgstr ""
#, python-format
msgid "Error while accessing dev mapper device, %(err)s"
msgstr ""
msgid "Block device not found."
msgstr ""
#, python-format
msgid "Block device %(device)s not found."
msgstr ""
#, python-format
msgid "Unable to retrieve LVM information. Details: %(err)s"
msgstr ""
msgid "Unknown \"_cap\" specified"
msgstr ""
msgid "\"_passthrough\" should be \"true\" or \"false\""
msgstr ""
msgid "\"_passthrough_affected_by\" should be a device name string"
msgstr ""
msgid "\"_available_only\" should be \"true\" or \"false\""
msgstr ""
#, python-format
msgid "Unable to find distro file: %(filename)s"
msgstr ""
#, python-format
msgid ""
"Unable to parse distro file: %(filename)s. Make sure, it is a JSON file."
msgstr ""
#, python-format
msgid "Unable to login to iSCSI host target %(portal)s. Details: %(err)s"
msgstr ""
#, python-format
msgid "Unable to login to iSCSI host %(host)s target %(target)s"
msgstr ""
#, python-format
msgid "Unable to find ISO file %(filename)s"
msgstr ""
#, python-format
msgid "The ISO file %(filename)s is not bootable"
msgstr ""
#, python-format
msgid "The ISO file %(filename)s does not have a valid El Torito boot record"
msgstr ""
#, python-format
msgid "Invalid El Torito validation entry in ISO %(filename)s"
msgstr ""
#, python-format
msgid "Invalid El Torito boot indicator in ISO %(filename)s"
msgstr ""
#, python-format
msgid "Unexpected volume type for primary volume in ISO %(filename)s"
msgstr ""
#, python-format
msgid "Bad format while reading volume descriptor in ISO %(filename)s"
msgstr ""
#, python-format
msgid ""
"The hypervisor doesn't have permission to use this ISO %(filename)s. "
"Consider moving it under /var/lib/libvirt, or set the search permission to "
"file access control lists for '%(user)s' user if possible, or add the "
"'%(user)s' to the ISO path group, or (not recommended) 'chmod -R o+x "
"'path_to_iso'.Details: %(err)s"
msgstr ""
#, python-format
msgid "Unable to access remote ISO. Details: %(err)s"
msgstr ""
#, python-format
msgid "Error probing image OS information: %(err)s"
msgstr ""
#, python-format
msgid "Unable to read image file %(filename)s"
msgstr ""
#, python-format
msgid ""
"Image file must be an existing file on system. %(filename)s is not a valid "
"input."
msgstr ""
#, python-format
msgid "Virtual machine %(name)s already exists"
msgstr ""
#, python-format
msgid "Virtual machine %(name)s does not exist"
msgstr ""
#, python-format
msgid "Unable to retrieve screenshot for stopped virtual machine %(name)s"
msgstr ""
msgid "Remote ISO image is not supported by this server."
msgstr ""
#, python-format
msgid "Screenshot is not supported on virtual machine %(name)s"
msgstr ""
#, python-format
msgid "Unable to create virtual machine %(name)s. Details: %(err)s"
msgstr ""
#, python-format
msgid "Unable to update virtual machine %(name)s. Details: %(err)s"
msgstr ""
#, python-format
msgid "Unable to retrieve virtual machine %(name)s. Details: %(err)s"
msgstr ""
#, python-format
msgid "Unable to connect to powered off virtual machine %(name)s."
msgstr ""
msgid "Virtual machine name must be a string without slashes (/)"
msgstr ""
#, python-format
msgid "Invalid template URI %(value)s specified for virtual machine"
msgstr ""
#, python-format
msgid "Invalid storage pool URI %(value)s specified for virtual machine"
msgstr ""
msgid "Supported virtual machine graphics are Spice or VNC"
msgstr ""
msgid "Graphics address to listen on must be IPv4 or IPv6"
msgstr ""
msgid "Specify a template to create a virtual machine from"
msgstr ""
#, python-format
msgid "Unable to start virtual machine %(name)s. Details: %(err)s"
msgstr ""
#, python-format
msgid "Unable to power off virtual machine %(name)s. Details: %(err)s"
msgstr ""
#, python-format
msgid "Unable to delete virtual machine %(name)s. Details: %(err)s"
msgstr ""
#, python-format
msgid "Unable to reset virtual machine %(name)s. Details: %(err)s"
msgstr ""
msgid "User name list must be an array"
msgstr ""
msgid "User name must be a string"
msgstr ""
msgid "Group name list must be an array"
msgstr ""
msgid "Group name must be a string"
msgstr ""
#, python-format
msgid "User(s) '%(users)s' do not exist"
msgstr ""
#, python-format
msgid "Group(s) '%(groups)s' do not exist"
msgstr ""
#, python-format
msgid "Unable to shutdown virtual machine %(name)s. Details: %(err)s"
msgstr ""
msgid "The guest console password must be a string."
msgstr ""
msgid "The life time for the guest console password must be a number."
msgstr ""
#, python-format
msgid "Virtual machine '%(name)s' must be stopped before cloning it."
msgstr ""
#, python-format
msgid "Insufficient disk space to clone virtual machine '%(name)s'"
msgstr ""
#, python-format
msgid "Unable to clone VM '%(name)s'. Details: %(err)s"
msgstr ""
#, python-format
msgid "Invalid operation for non-persistent virtual machine %(name)s"
msgstr ""
#, python-format
msgid "Cannot suspend VM '%(name)s' because it is not running."
msgstr ""
#, python-format
msgid "Unable to suspend VM '%(name)s'. Details: %(err)s"
msgstr ""
#, python-format
msgid "Cannot resume VM '%(name)s' because it is not paused."
msgstr ""
#, python-format
msgid "Unable to resume VM '%(name)s'. Details: %(err)s"
msgstr ""
#, python-format
msgid ""
"Memory assigned is higher then the maximum allowed in the host: "
"%(maxmem)sMib."
msgstr ""
#, python-format
msgid ""
"Guest '%(name)s' does not support live memory update. Please, with the guest "
"offline, set Maximum Memory with a value greater then Memory to enable this "
"feature."
msgstr ""
msgid "Only increase memory is allowed in active VMs"
msgstr ""
msgid "There are not enough free slots to add a new memory device."
msgstr ""
msgid ""
"Host's libvirt or qemu version does not support memory devices and memory "
"hotplug. Libvirt must be >= 1.2.14 and QEMU must be >= 2.1."
msgstr ""
#, python-format
msgid "Error attaching memory device. Details: %(error)s"
msgstr ""
#, python-format
msgid "Cannot start %(name)s. Virtual machine is already running."
msgstr ""
#, python-format
msgid "Cannot power off %(name)s. Virtual machine is shut off."
msgstr ""
#, python-format
msgid "Cannot shutdown %(name)s. Virtual machine is shut off."
msgstr ""
#, python-format
msgid "Cannot reset %(name)s. Virtual machine is already shut off."
msgstr ""
msgid "Boot order must be a list. Devices accepted: hd, cdrom, fd or network."
msgstr ""
msgid "Bootmenu must be boolean. Values accepted: true of false."
msgstr ""
msgid "Graphic type not valid. Values accepted: vnc or spice."
msgstr ""
#, python-format
msgid "Migrate to localhost %(host)s is not allowed."
msgstr ""
#, python-format
msgid ""
"To migrate a virtual machine to the remote host %(host)s the user %(user)s "
"must have password-less login to the remote host."
msgstr ""
#, python-format
msgid "Can not migrate virtual machine %(name)s when its in %(state)s state."
msgstr ""
#, python-format
msgid "Failed to migrate virtual machine %(name)s due error: %(err)s"
msgstr ""
msgid "User name of the remote server must be a string."
msgstr ""
msgid "Destination host of the migration must be a string."
msgstr ""
#, python-format
msgid "Unable to create file %(path)s at %(host)s using user %(user)s."
msgstr ""
#, python-format
msgid "Unable to read disk size of %(path)s, error: %(error)s"
msgstr ""
#, python-format
msgid ""
"Unable to create disk image %(path)s at %(host)s using user %(user)s. Error: "
"%(error)s"
msgstr ""
#, python-format
msgid ""
"Unable to migrate virtual machine to remote host %(host)s with arch "
"%(destarch)s using localhost with arch %(srcarch)s."
msgstr ""
#, python-format
msgid ""
"Unable to migrate virtual machine to remote host %(host)s with hypervisor "
"%(desthyp)s because localhost uses hypervisor %(srchyp)s."
msgstr ""
#, python-format
msgid ""
"Unable to determine remote host hypervisor and architecture. Error: %(error)s"
msgstr ""
#, python-format
msgid ""
"Unable to migrate virtual machine: subcores per core setting from "
"localhostand remote host %(host)s differs."
msgstr ""
#, python-format
msgid ""
"Unable to setup password-less login at remote host %(host)s using user "
"%(user)s. Error: %(error)s"
msgstr ""
msgid "Password field must be a string."
msgstr ""
msgid "Error creating local host ssh rsa key of user 'root'."
msgstr ""
#, python-format
msgid "%(param)s value (%(mem)sMiB) must be aligned to %(alignment)sMiB."
msgstr ""
#, python-format
msgid ""
"Unable to update the following parameters while the VM is offline: %(params)s"
msgstr ""
#, python-format
msgid ""
"Unable to update the following parameters while the VM is online: %(params)s"
msgstr ""
#, python-format
msgid ""
"VM %(name)s must have serial and console defined to open a web serial console"
msgstr ""
#, python-format
msgid "Impossible to get the serial console of %(name)s"
msgstr ""
#, python-format
msgid ""
"Memory or Maximum Memory value is higher than amount supported by the host: "
"%(memHost)sMiB."
msgstr ""
#, python-format
msgid ""
"Memory or Maximum Memory value is higher than maximum amount recommended: "
"%(value)sTiB"
msgstr ""
msgid "Cannot update Maximum Memory when guest is running."
msgstr ""
#, python-format
msgid "Impossible to create %(dir)s directory."
msgstr ""
#, python-format
msgid ""
"Either the guest %(name)s did not start to listen to the serial or it is not "
"configured to use the serial console."
msgstr ""
#, python-format
msgid ""
"Unable to retrieve Virt Viewer file for stopped virtual machine %(name)s"
msgstr ""
#, python-format
msgid ""
"Error occured while retrieving the Virt Viewer file for virtual machine "
"%(name)s : %(err)s"
msgstr ""
msgid "Virtual machine title must be a string"
msgstr ""
msgid "Virtual machine description must be a string"
msgstr ""
msgid "console parameter is only supported for s390x/s390 architecture."
msgstr ""
msgid "invalid console type, supported types are sclp/virtio."
msgstr ""
#, python-format
msgid ""
"Unable to setup password-less login at remote host %(host)s using user "
"%(user)s: remote directory %(sshdir)s does not exist."
msgstr ""
#, python-format
msgid ""
"Unable to create a password-less libvirt connection to the remote libvirt "
"daemon at host %(host)s with the user %(user)s. Please verify the remote "
"server libvirt configuration. More information: http://libvirt.org/auth."
"html ."
msgstr ""
msgid "'enable_rdma' must be of type boolean (true or false)."
msgstr ""
#, python-format
msgid ""
"VM %(vmid)s does not contain directly assigned host device %(dev_name)s."
msgstr ""
#, python-format
msgid "The host device %(dev_name)s is not allowed to directly assign to VM."
msgstr ""
msgid ""
"No IOMMU groups found. Host PCI pass through needs IOMMU group to function "
"correctly. Please enable Intel VT-d or AMD IOMMU in your BIOS, then verify "
"the Kernel is compiled with IOMMU support. For Intel CPU, add "
"'intel_iommu=on' to GRUB_CMDLINE_LINUX parameter in /etc/default/grub file. "
"For AMD CPU, add 'iommu=pt iommu=1'."
msgstr ""
msgid "\"name\" should be a device name string"
msgstr ""
#, python-format
msgid ""
"The device %(name)s is probably in use by the host. Unable to attach it to "
"the guest."
msgstr ""
#, python-format
msgid "Hot-(un)plug of device %(name)s is not supported."
msgstr ""
#, python-format
msgid "Failed to attach %(device)s to %(vm)s"
msgstr ""
#, python-format
msgid "VM %(vmid)s does not have a USB controller to accept PCI hotplug."
msgstr ""
#, python-format
msgid "Interface %(iface)s does not exist in virtual machine %(name)s"
msgstr ""
#, python-format
msgid ""
"Network %(network)s specified for virtual machine %(name)s does not exist"
msgstr ""
msgid ""
"Supported virtual machine interfaces type are network, ovs and macvtap.Type "
"ovs and macvtap are only supported for s390x/s390 architecture."
msgstr ""
msgid "Network name for virtual machine interface must be a string"
msgstr ""
msgid "Invalid network model card specified for virtual machine interface"
msgstr ""
msgid "Specify type and network to add a new virtual machine interface"
msgstr ""
msgid "MAC Address must respect this format FF:FF:FF:FF:FF:FF"
msgstr ""
#, python-format
msgid "MAC Address %(mac)s already exists in virtual machine %(name)s"
msgstr ""
msgid "Invalid MAC Address"
msgstr ""
msgid "Cannot change MAC address of a running virtual machine"
msgstr ""
msgid "Type macvtap and ovs are only supported on s390x/s390 architecture."
msgstr ""
msgid "Source attribute is only supported on s390x/s390 architecture."
msgstr ""
msgid "If source is provided, only type supported are macvtap and ovs."
msgstr ""
msgid "For type macvtap and ovs, source has to be provided"
msgstr ""
msgid "Source name for virtual machine interface must be string"
msgstr ""
msgid "Invalid source mode. Valid options are: bridge or vepa."
msgstr ""
#, python-format
msgid "Template %(name)s already exists"
msgstr ""
#, python-format
msgid "Source media %(path)s not found"
msgstr ""
#, python-format
msgid ""
"Network '%(network)s' specified for template %(template)s does not exist"
msgstr ""
#, python-format
msgid ""
"Storage pool %(pool)s specified for template %(template)s does not exist"
msgstr ""
#, python-format
msgid "Invalid parameter '%(param)s' specified for CDROM."
msgstr ""
#, python-format
msgid "Network %(network)s specified for template %(template)s is not active"
msgstr ""
msgid "Template name must be a string"
msgstr ""
msgid "Template icon must be a path to the image"
msgstr ""
msgid "Template distribution must be a string"
msgstr ""
msgid "Template distribution version must be a string"
msgstr ""
msgid "The number of CPUs must be an integer greater than 0"
msgstr ""
msgid ""
"Amount of memory and maximum memory (MB) must be an integer greater than 512"
msgstr ""
msgid "Template CDROM must be a local or remote ISO file"
msgstr ""
#, python-format
msgid "Invalid storage pool URI %(value)s specified for template"
msgstr ""
msgid ""
"Specify a path to source media (ISO, disk or remote ISO) to create a template"
msgstr ""
msgid "All networks for the template must be specified in a list."
msgstr ""
msgid "Specify a volume to a template when storage pool is iSCSI or SCSI"
msgstr ""
#, python-format
msgid "The volume %(volume)s is not in storage pool %(pool)s"
msgstr ""
#, python-format
msgid "Unable to create template due error: %(err)s"
msgstr ""
#, python-format
msgid "Unable to delete template due error: %(err)s"
msgstr ""
msgid "Disk size must be an integer greater than 1GB."
msgstr ""
#, python-format
msgid "Cannot identify base image %(path)s format"
msgstr ""
msgid ""
"When specifying CPU topology, each element must be an integer greater than "
"zero."
msgstr ""
msgid ""
"Invalid disk image format. Valid formats: qcow, qcow2, qed, raw, vmdk, vpc."
msgstr ""
msgid ""
"When setting template disks, following parameters are required: 'index', "
"'pool name', 'format', 'size' or 'volume' (for scsi/iscsi pools)"
msgstr ""
msgid "Disk format must be 'raw', for logical, iscsi, and scsi pools."
msgstr ""
msgid ""
"Memory expects an object with one or both parameters: 'current' and "
"'maxmemory'"
msgstr ""
#, python-format
msgid ""
"Memory value (%(mem)sMiB) must be equal or lesser than maximum memory value "
"(%(maxmem)sMiB)"
msgstr ""
#, python-format
msgid "Unable to update template due error: %(err)s"
msgstr ""
msgid "Parameter 'disks' requires at least one disk object"
msgstr ""
msgid ""
"Invalid interface type. Type should be 'macvtap' for host network interface "
"(Ethernet, Bond, VLAN) to be connected as direct MacVTap or 'ovs' for "
"openvswitch host network interface to be connected as virtual switch to a VM."
msgstr ""
msgid "Interface name should be string."
msgstr ""
msgid "Invalid interface mode. Valid options are: bridge or vepa."
msgstr ""
msgid ""
"Interfaces should be list of interfaces. Each interface should have name, "
"type and mode(optional, only applicable for interfcae type 'macvtap'."
msgstr ""
msgid ""
"Interface expects an object with parameters: 'name', 'type' and 'mode'. Name "
"should be name of host network interface (Ethernet, Bond, VLAN) for type "
"'macvtap' or the name of host openvswitch bridge interface for type 'ovs'. "
"Mode (optional) is only applicable for interface type 'macvtap' to indicates "
"whether packets will be delivered directly to target device (bridge) or to "
"the external bridge (vepa-capable bridge)."
msgstr ""
msgid "Interfaces parameter only supported on s390x or s390 architecture."
msgstr ""
msgid "Storage without libvirt pool is not supported on this architecture"
msgstr ""
#, python-format
msgid "Error while creating the virtual disk for the guest. Details: %(err)s"
msgstr ""
msgid ""
"When setting template disks without libvirt, following parameters are "
"required: 'index', 'format', 'path', 'size'"
msgstr ""
#, python-format
msgid "Storage pool %(name)s already exists"
msgstr ""
#, python-format
msgid "Storage pool %(name)s does not exist"
msgstr ""
#, python-format
msgid "Specify %(item)s in order to create the storage pool %(name)s"
msgstr ""
#, python-format
msgid "Unable to delete active storage pool %(name)s"
msgstr ""
#, python-format
msgid "Unable to list storage pools. Details: %(err)s"
msgstr ""
#, python-format
msgid "Unable to create storage pool %(name)s. Details: %(err)s"
msgstr ""
#, python-format
msgid "Unable to activate storage pool %(name)s. Details: %(err)s"
msgstr ""
#, python-format
msgid "Unable to deactivate storage pool %(name)s. Details: %(err)s"
msgstr ""
#, python-format
msgid "Unable to delete storage pool %(name)s. Details: %(err)s"
msgstr ""
#, python-format
msgid ""
"Unable to create NFS Pool as export path %(path)s may block during mount"
msgstr ""
#, python-format
msgid "Unable to create NFS Pool as export path %(path)s mount failed"
msgstr ""
#, python-format
msgid "Unsupported storage pool type: %(type)s"
msgstr ""
#, python-format
msgid "Error while retrieving storage pool XML to %(pool)s"
msgstr ""
msgid "Storage pool name must be a string without slashes (/)"
msgstr ""
msgid ""
"Supported storage pool types are dir, netfs, logical, iscsi, isci and kimchi-"
"iso"
msgstr ""
msgid "Storage pool path must be a string"
msgstr ""
msgid "Storage pool host must be a IP or hostname"
msgstr ""
msgid "Storage pool device must be the absolute path to the block device"
msgstr ""
msgid "Storage pool devices parameter must be a list"
msgstr ""
msgid "Target IQN of an iSCSI pool must be a string"
msgstr ""
msgid "Port of a remote storage server must be an integer between 1 and 65535"
msgstr ""
msgid "iSCSI target username must be a string"
msgstr ""
msgid "iSCSI target password must be a string"
msgstr ""
msgid "Specify name and type to create a storage pool"
msgstr ""
#, python-format
msgid ""
"%(disk)s is not a valid disk/partition. Could not add it to the pool "
"%(pool)s."
msgstr ""
#, python-format
msgid "Unable to extend logical pool %(pool)s. Details: %(err)s"
msgstr ""
msgid "The parameter disks only can be updated for logical storage pool."
msgstr ""
msgid "The SCSI host adapter name must be a string."
msgstr ""
msgid "The storage pool kimchi_isos is reserved for internal use"
msgstr ""
#, python-format
msgid ""
"Unable to activate NFS storage pool %(name)s. NFS server %(server)s is "
"unreachable."
msgstr ""
#, python-format
msgid ""
"Unable to deactivate NFS storage pool %(name)s. NFS server %(server)s is "
"unreachable."
msgstr ""
#, python-format
msgid ""
"Unable to deactivate pool %(name)s as it is associated with some templates"
msgstr ""
#, python-format
msgid "Unable to delete pool %(name)s as it is associated with some templates"
msgstr ""
#, python-format
msgid ""
"A volume group named '%(name)s' already exists. Please, choose another name "
"to create the logical pool."
msgstr ""
#, python-format
msgid "Unable to update database with deep scan information due error: %(err)s"
msgstr ""
#, python-format
msgid ""
"No volume group '%(name)s' found. Please, specify an existing volume group "
"to create the logical pool from."
msgstr ""
#, python-format
msgid "Unable to delete pool %(name)s as it is associated with guests: %(vms)s"
msgstr ""
#, python-format
msgid "Storage volume %(name)s already exists"
msgstr ""
#, python-format
msgid "Storage volume %(name)s does not exist in storage pool %(pool)s"
msgstr ""
#, python-format
msgid ""
"Unable to create storage volume %(volume)s because storage pool %(pool)s is "
"not active"
msgstr ""
#, python-format
msgid "Specify %(item)s in order to create storage volume %(volume)s"
msgstr ""
#, python-format
msgid ""
"Unable to list storage volumes because storage pool %(pool)s is not active"
msgstr ""
#, python-format
msgid ""
"Unable to create storage volume %(name)s in storage pool %(pool)s. Details: "
"%(err)s"
msgstr ""
#, python-format
msgid "Unable to wipe storage volumes %(name)s. Details: %(err)s"
msgstr ""
#, python-format
msgid "Unable to delete storage volume %(name)s. Details: %(err)s"
msgstr ""
#, python-format
msgid "Unable to resize storage volume %(name)s. Details: %(err)s"
msgstr ""
#, python-format
msgid "Storage type %(type)s does not support volume create and delete"
msgstr ""
msgid "Storage volume name must be a string"
msgstr ""
msgid "Storage volume allocation must be an integer number"
msgstr ""
msgid ""
"Storage volume format not supported. Valid formats: qcow, qcow2, qed, raw, "
"vmdk, vpc."
msgstr ""
msgid "Storage volume requires a volume name"
msgstr ""
#, python-format
msgid ""
"Unable to update database with storage volume information due error: %(err)s"
msgstr ""
#, python-format
msgid "Only one of parameter %(param)s can be specified"
msgstr ""
#, python-format
msgid "Create volume from %(param)s is not supported"
msgstr ""
msgid "Storage volume capacity must be an integer number."
msgstr ""
msgid "Storage volume URL must be http://, https://, ftp:// or ftps://."
msgstr ""
#, python-format
msgid "Unable to access file %(url)s. Please, check it."
msgstr ""
#, python-format
msgid ""
"Unable to clone storage volume '%(name)s' in pool '%(pool)s'. Details: "
"%(err)s"
msgstr ""
msgid "Specify chunk data and its size to upload a file."
msgstr ""
msgid "In order to upload a storage volume, specify the 'upload' parameter."
msgstr ""
msgid ""
"Unable to upload chunk data as it does not match with requested chunk size."
msgstr ""
#, python-format
msgid "The storage volume %(vol)s is not under an upload process."
msgstr ""
msgid "The upload chunk data will exceed the storage volume size."
msgstr ""
#, python-format
msgid "Unable to upload chunk data to storage volume. Details: %(err)s."
msgstr ""
#, python-format
msgid "Interface %(name)s does not exist"
msgstr ""
#, python-format
msgid ""
"Failed to list interfaces. Invalid _inuse parameter. Supported options for "
"_inuse are: %(supported_inuse)s"
msgstr ""
#, python-format
msgid "Network %(name)s already exists"
msgstr ""
#, python-format
msgid "Network %(name)s does not exist"
msgstr ""
#, python-format
msgid "Subnet %(subnet)s specified for network %(network)s is not valid."
msgstr ""
msgid "Specify a network interface to create bridged or macvtap networks."
msgstr ""
#, python-format
msgid "Unable to delete or update active network %(name)s"
msgstr ""
#, python-format
msgid "Interface %(iface)s specified for network %(network)s is already in use"
msgstr ""
msgid "Interface should be bare NIC, bonding or bridge device."
msgstr ""
#, python-format
msgid "Unable to create or update network %(name)s. Details: %(err)s"
msgstr ""
#, python-format
msgid "Unable to find a free IP address for network '%(name)s'"
msgstr ""
#, python-format
msgid "The interface %(iface)s already exists."
msgstr ""
msgid "Network name must be a string without slashes (/) or quotes (\")"
msgstr ""
msgid ""
"Supported network types are isolated, NAT, macvtap, bridge, vepa and "
"passthrough."
msgstr ""
msgid "Network subnet must be a string with IP address and prefix or netmask"
msgstr ""
msgid "Network interfaces must be an array."
msgstr ""
msgid "Network VLAN ID must be an integer between 1 and 4094"
msgstr ""
msgid "Specify name and type to create a Network"
msgstr ""
#, python-format
msgid ""
"Unable to delete or update network %(name)s as it is linked to some virtual "
"machines (%(vms)s) and/or templates (%(tmpls)s)."
msgstr ""
#, python-format
msgid ""
"Unable to deactivate network %(name)s as it is linked to are some virtual "
"machines (%(vms)s) and/or templates (%(tmpls)s)."
msgstr ""
#, python-format
msgid "Bridge device %(name)s can not be the trunk device of a VLAN."
msgstr ""
#, python-format
msgid "Failed to activate interface %(iface)s: %(err)s."
msgstr ""
#, python-format
msgid ""
"Failed to activate interface %(iface)s. Please check the physical link "
"status."
msgstr ""
#, python-format
msgid "Failed to start network %(name)s. Details: %(err)s"
msgstr ""
#, python-format
msgid "Unable to redefine interface %(name)s. Details: %(err)s"
msgstr ""
#, python-format
msgid "Unable to create bridge %(name)s. Details: %(err)s"
msgstr ""
msgid ""
"Unable to create bridge with NetworkManager enabled. Disable it and try "
"again."
msgstr ""
msgid "Interface should be bare NIC or bonding."
msgstr ""
msgid "Network interfaces parameter must contain at least one interface."
msgstr ""
msgid "Only one interface is allowed for 'bridge' and 'macvtap' networks."
msgstr ""
msgid "Subnet is not a valid parameter for this type of virtual network."
msgstr ""
msgid ""
"VLAN ID and interfaces are not valid parameters for this type of virtual "
"network."
msgstr ""
#, python-format
msgid "Storage server %(server)s was not used by Kimchi"
msgstr ""
#, python-format
msgid "Distro '%(name)s' does not exist"
msgstr ""
#, python-format
msgid "Node device '%(name)s' not found"
msgstr ""
msgid "Conflicting flag filters specified."
msgstr ""
msgid "Unable to choose a virtual machine name"
msgstr ""
msgid "Cannot upgrade objectstore data."
msgstr ""
msgid "Invalid storage type. Types supported: 'cdrom', 'disk'"
msgstr ""
#, python-format
msgid "The path '%(value)s' is not a valid local/remote path for the device"
msgstr ""
msgid "Only CDROM path can be update."
msgstr ""
#, python-format
msgid ""
"The storage device %(dev_name)s does not exist in the virtual machine "
"%(vm_name)s"
msgstr ""
#, python-format
msgid "Error while creating new storage device: %(error)s"
msgstr ""
#, python-format
msgid "Error while updating storage device: %(error)s"
msgstr ""
#, python-format
msgid "Error while removing storage device: %(error)s"
msgstr ""
msgid "Do not support IDE device hot plug"
msgstr ""
msgid ""
"Specify type and path or type and pool/volume to add a new virtual machine "
"disk"
msgstr ""
msgid "Specify path to update virtual machine disk"
msgstr ""
#, python-format
msgid "Controller type %(type)s limitation of %(limit)s devices reached"
msgstr ""
#, python-format
msgid "Cannot retrieve disk path information for given pool/volume: %(error)s"
msgstr ""
msgid "Volume already in use by other virtual machine."
msgstr ""
msgid ""
"Only one of path or pool/volume can be specified to add a new virtual "
"machine disk"
msgstr ""
#, python-format
msgid ""
"Volume chosen with format %(format)s does not fit in the storage type "
"%(type)s"
msgstr ""
msgid "On s390x arch one of pool, path of dir_path must be specified"
msgstr ""
msgid ""
"On s390x arch 'format' must be specified while attaching disk to virtual "
"machine"
msgstr ""
#, python-format
msgid "Virtual disk already exists on the system: %(disk_path)s"
msgstr ""
#, python-format
msgid ""
"Unable to create snapshot '%(name)s' on virtual machine '%(vm)s'. Details: "
"%(err)s"
msgstr ""
#, python-format
msgid "Snapshot '%(name)s' does not exist on virtual machine '%(vm)s'."
msgstr ""
#, python-format
msgid ""
"Unable to retrieve snapshot '%(name)s' on virtual machine '%(vm)s'. Details: "
"%(err)s"
msgstr ""
#, python-format
msgid "Unable to list snapshots on virtual machine '%(vm)s'. Details: %(err)s"
msgstr ""
#, python-format
msgid ""
"Unable to delete snapshot '%(name)s' on virtual machine '%(vm)s'. Details: "
"%(err)s"
msgstr ""
#, python-format
msgid ""
"Unable to retrieve current snapshot of virtual machine '%(vm)s'. Details: "
"%(err)s"
msgstr ""
#, python-format
msgid ""
"Unable to revert virtual machine '%(vm)s' to snapshot '%(name)s'. Details: "
"%(err)s"
msgstr ""
#, python-format
msgid ""
"Unable to create snapshot of virtual machine '%(vm)s' because it contains a "
"disk with format '%(format)s'; only 'qcow2' is supported."
msgstr ""
msgid ""
"The number of vCPUs must be less than or equal the maximum number of vCPUs "
"specified."
msgstr ""
msgid ""
"When CPU topology is defined, maximum number of vCPUs must be a product of "
"sockets, cores, and threads."
msgstr ""
msgid "This host (or current configuration) does not allow CPU topology."
msgstr ""
msgid "The maximum number of vCPUs is too large for this system."
msgstr ""
msgid ""
"When CPU topology is defined, CPUs must be a multiple of the 'threads' "
"number defined."
msgstr ""
msgid ""
"When CPU topology is specified, sockets, cores and threads are required "
"paramaters."
msgstr ""
msgid ""
"Parameter 'cpu_info' expects an object with fields among: 'vcpus', "
"'maxvcpus', 'topology'."
msgstr ""
msgid ""
"Parameter 'topology' expects an object with fields among: 'sockets', "
"'cores', 'threads'."
msgstr ""
msgid "Unable to update Max CPU or CPU topology when guest is running."
msgstr ""
#, python-format
msgid "Unable to hot plug/unplug CPUs. Details: %(err)s"
msgstr ""
#, python-format
msgid "Invalid volume group name parameter: %(name)s."
msgstr ""
msgid ""
"Unable to establish connection with libvirt. Please check your libvirt URI "
"which is often defined in /etc/libvirt/libvirt.conf"
msgstr ""
msgid ""
"Libvirt service is not active. Please start the libvirt service in your host "
"system."
msgstr ""
msgid "Failed to register the default event implementation."
msgstr ""
msgid "Failed to register timeout event."
msgstr ""
msgid "Failed to Run the default event implementation."
msgstr ""
#, python-format
msgid ""
"I/O error on guest '%(vm)s': storage pool out of space for %(devAlias)s "
"(%(srcPath)s)."
msgstr ""
#, python-format
msgid "Create virtual network '%(name)s' type '%(connection)s'"
msgstr ""
#, python-format
msgid "Remove virtual network '%(ident)s'"
msgstr ""
#, python-format
msgid "Update virtual network '%(ident)s'"
msgstr ""
#, python-format
msgid "Activate virtual network '%(ident)s'"
msgstr ""
#, python-format
msgid "Deactivate virtual network '%(ident)s'"
msgstr ""
#, python-format
msgid "Create storage pool '%(name)s' type '%(type)s'"
msgstr ""
#, python-format
msgid "Remove storage pool '%(ident)s'"
msgstr ""
#, python-format
msgid "Update storage pool '%(ident)s'"
msgstr ""
#, python-format
msgid "Activate storage pool '%(ident)s'"
msgstr ""
#, python-format
msgid "Deactivate storage pool '%(ident)s'"
msgstr ""
#, python-format
msgid "Create snapshot '%(name)s' at guest '%(vm)s'"
msgstr ""
#, python-format
msgid "Remove snapshot '%(ident)s' from guest '%(vm)s'"
msgstr ""
#, python-format
msgid "Revert guest '%(vm)s' to snapshot '%(ident)s'"
msgstr ""
#, python-format
msgid "Create template '%(name)s'"
msgstr ""
#, python-format
msgid "Remove template '%(ident)s'"
msgstr ""
#, python-format
msgid "Update template '%(ident)s'"
msgstr ""
#, python-format
msgid "Clone template '%(ident)s'"
msgstr ""
#, python-format
msgid "Create guest '%(name)s' from template '%(template)s'"
msgstr ""
#, python-format
msgid "Remove guest '%(ident)s'"
msgstr ""
#, python-format
msgid "Edit guest '%(ident)s'"
msgstr ""
#, python-format
msgid "Start guest '%(ident)s'"
msgstr ""
#, python-format
msgid "Power off guest '%(ident)s'"
msgstr ""
#, python-format
msgid "Shutdown guest '%(ident)s'"
msgstr ""
#, python-format
msgid "Restart guest '%(ident)s'"
msgstr ""
#, python-format
msgid "Connect to guest '%(ident)s' through novnc/spice"
msgstr ""
#, python-format
msgid "Clone guest '%(ident)s'"
msgstr ""
#, python-format
msgid "Migrate guest '%(ident)s' to '%(remote_host)s'"
msgstr ""
#, python-format
msgid "Suspend guest '%(ident)s'"
msgstr ""
#, python-format
msgid "Resume guest '%(ident)s'"
msgstr ""
#, python-format
msgid "Connect to guest '%(ident)s' through serial"
msgstr ""
#, python-format
msgid "Attach host device '%(name)s' to guest '%(vmid)s'"
msgstr ""
#, python-format
msgid "Detach host device '%(ident)s' from guest '%(vmid)s'"
msgstr ""
#, python-format
msgid "Attach network interface '%(network)s' to guest '%(vm)s'"
msgstr ""
#, python-format
msgid "Detach network interface '%(ident)s' from guest '%(vm)s'"
msgstr ""
#, python-format
msgid "Update network interface '%(ident)s' at guest '%(vm)s'"
msgstr ""
#, python-format
msgid "Attach %(type)s storage '%(path)s' to guest '%(vm)s'"
msgstr ""
#, python-format
msgid "Remove storage '%(ident)s' from guest '%(vm)s'"
msgstr ""
#, python-format
msgid "Update storage '%(ident)s' at guest '%(vm)s'"
msgstr ""
#, python-format
msgid "Create storage volume '%(name)s' at pool '%(pool)s'"
msgstr ""
#, python-format
msgid "Remove storage volume '%(ident)s' from pool '%(pool)s'"
msgstr ""
#, python-format
msgid "Update storage volume '%(ident)s' at pool '%(pool)s'"
msgstr ""
#, python-format
msgid "Wipe storage volume '%(ident)s' off pool '%(pool)s'"
msgstr ""
#, python-format
msgid "Resize storage volume '%(ident)s' at pool '%(pool)s' with size %(size)s"
msgstr ""
#, python-format
msgid "Clone storage volume '%(ident)s' at pool '%(pool)s'"
msgstr ""
msgid "Create a New Virtual Machine"
msgstr ""
msgid "Virtual Machine Name"
msgstr ""
msgid ""
"The name used to identify the virtual machine. If omitted, a name will be "
"chosen based on the template used."
msgstr ""
msgid "Please create a template first."
msgstr ""
msgid "Create a Template"
msgstr ""
msgid "Please choose a template."
msgstr ""
msgid "This template has invalid parameters."
msgstr ""
msgid "This template has invalid parameters"
msgstr ""
msgid "OS"
msgstr ""
msgid "Version"
msgstr ""
msgid "Current CPUs"
msgstr ""
msgid "Memory"
msgstr ""
msgid "Create"
msgstr ""
msgid "Creating..."
msgstr ""
msgid "Cancel"
msgstr ""
msgid "Clone a Guest"
msgstr ""
msgid ""
"When the target guest has SCSI or iSCSI volumes, they will be cloned on the "
"default storage pool. The same will happen when the target pool does not "
"have enough space to clone the volumes. Do you want to continue?"
msgstr ""
msgid "Number of times to clone"
msgstr ""
msgid "Continue"
msgstr ""
msgid "Edit Guest"
msgstr ""
msgid "General"
msgstr ""
msgid "Storage"
msgstr ""
msgid "Interface"
msgstr ""
msgid "Permission"
msgstr ""
msgid "Pci"
msgstr ""
msgid "Snapshot"
msgstr ""
msgid "Processor"
msgstr ""
msgid "Name"
msgstr ""
msgid "Memory (MB)"
msgstr ""
msgid "More"
msgstr ""
msgid "Max Memory (MB)"
msgstr ""
msgid "Host does not support memory hotplug"
msgstr ""
msgid "Icon"
msgstr ""
msgid "Console"
msgstr ""
msgid "Nothing selected"
msgstr ""
msgid "sclp"
msgstr ""
msgid "virtio"
msgstr ""
msgid ""
"Select which items for boot order and grad them when needed to order them. "
"At least one option must be selected."
msgstr ""
msgid "Add"
msgstr ""
msgid "Device"
msgstr ""
msgid "Path"
msgstr ""
msgid "Actions"
msgstr ""
msgid "Network"
msgstr ""
msgid "Type"
msgstr ""
msgid "MAC Address"
msgstr ""
msgid "IP Address"
msgstr ""
msgid "Network/Interface"
msgstr ""
msgid "Mode"
msgstr ""
msgid "Available system users and groups"
msgstr ""
msgid "Users"
msgstr ""
msgid "Groups"
msgstr ""
msgid "Selected system users and groups"
msgstr ""
msgid "User"
msgstr ""
msgid "All"
msgstr ""
msgid "To Add"
msgstr ""
msgid "Added"
msgstr ""
msgid "Filter"
msgstr ""
msgid "Status"
msgstr ""
msgid "Product"
msgstr ""
msgid "Vendor"
msgstr ""
msgid "Loading"
msgstr ""
msgid "Created"
msgstr ""
msgid "Current CPU Number"
msgstr ""
msgid ""
"Current CPU must be equal or lower than the Maximum CPU value. If a topology "
"is set, it must be also be a multiple of the 'threads' value."
msgstr ""
msgid "Max CPU"
msgstr ""
msgid ""
"Unable to edit maximum CPU or CPU topology when editing a running or paused "
"virtual machine."
msgstr ""
msgid ""
"If a topology is set, this value will be the product of sockets * times * "
"cores."
msgstr ""
msgid "Manually set CPU topology"
msgstr ""
msgid "Sockets"
msgstr ""
msgid "Cores"
msgstr ""
msgid "Threads"
msgstr ""
msgid "Save"
msgstr ""
msgid "Replace"
msgstr ""
msgid "Detach"
msgstr ""
msgid "Remove"
msgstr ""
msgid "Edit"
msgstr ""
msgid "LDAP User ID,e.g.foo@foo.com"
msgstr ""
msgid "Revert"
msgstr ""
msgid "Running"
msgstr ""
msgid "Disconnected"
msgstr ""
msgid "Starting"
msgstr ""
msgid "Crashed"
msgstr ""
msgid "Unknown"
msgstr ""
msgid "Paused"
msgstr ""
msgid "Suspended"
msgstr ""
msgid "Resetting"
msgstr ""
msgid "View Console"
msgstr ""
msgid "View Serial"
msgstr ""
msgid "Clone"
msgstr ""
msgid "Migrate"
msgstr ""
msgid "Reset"
msgstr ""
msgid "Pause"
msgstr ""
msgid "Resume"
msgstr ""
msgid "Shut Down"
msgstr ""
msgid "Start"
msgstr ""
msgid "Power Off"
msgstr ""
msgid "Delete"
msgstr ""
msgid "No Data Available"
msgstr ""
msgid "Processors Utilization"
msgstr ""
msgid "Memory Utilization"
msgstr ""
msgid "Storage I/O"
msgstr ""
msgid "Network I/O"
msgstr ""
msgid "Migrate a Guest"
msgstr ""
msgid ""
"Disclaimer: This process cannot be stopped after started, can take a long "
"time to complete and will turn off the VM on this Hypervisor when it is "
"successfully migrated to the remote destination."
msgstr ""
msgid "Remote Server"
msgstr ""
msgid "IP Address or Hostname"
msgstr ""
msgid ""
"The following fields are optional. Fill them if you want Kimchi to setup a "
"password-less ssh session between the localhost and the remote host. The "
"setup process will only be successful if the user has 'SUDO ALL' permission "
"in the remote machine."
msgstr ""
msgid "Username of the remote host"
msgstr ""
msgid "Password"
msgstr ""
msgid "Password of the user in the remote host"
msgstr ""
msgid "Use RDMA transport"
msgstr ""
msgid ""
"Check this option only if RDMA is properly configured in both source and "
"destination hosts, otherwise migration will fail."
msgstr ""
msgid "Delete this VM when the migration is completed"
msgstr ""
msgid "Add a Storage Device to VM"
msgstr ""
msgid "Device Type"
msgstr ""
msgid ""
"The device type. Currently, \"cdrom\" and \"disk\" are supported. If the "
"guest is running, only \"disk\" is supported."
msgstr ""
msgid "Create a new disk"
msgstr ""
msgid "Select an existing disk"
msgstr ""
msgid "Source"
msgstr ""
msgid "Storage based on Libvirt pool or direct block device"
msgstr ""
msgid "Storage Pool"
msgstr ""
msgid "Storage pool to create the volume in"
msgstr ""
msgid "Disk Size (GB)"
msgstr ""
msgid "New disk size to be created"
msgstr ""
msgid "Format"
msgstr ""
msgid "Format of the new disk to be created"
msgstr ""
msgid "Directory Path"
msgstr ""
msgid "Provide a directory path"
msgstr ""
msgid "Storage pool in which the volume is located in"
msgstr ""
msgid "Storage Volume"
msgstr ""
msgid "Storage volume to be attached"
msgstr ""
msgid "Disk Path"
msgstr ""
msgid "Provide a block device"
msgstr ""
msgid "File Path"
msgstr ""
msgid "The ISO file path in the server for CDROM."
msgstr ""
msgid "Attach"
msgstr ""
msgid "Host"
msgstr ""
msgid "Guests"
msgstr ""
msgid "Templates"
msgstr ""
msgid "This is not a valid Linux path"
msgstr ""
msgid "Unable to read file."
msgstr ""
msgid "Error while uploading file."
msgstr ""
msgid "Delete Confirmation"
msgstr ""
msgid "OK"
msgstr ""
msgid "Confirm"
msgstr ""
msgid "Warning"
msgstr ""
msgid "Cloning..."
msgstr ""
msgid "Saving..."
msgstr ""
msgid "Migrating..."
msgstr ""
msgid "No ISO found"
msgstr ""
msgid "Add Template"
msgstr ""
msgid "This may take a long time. Do you want to continue?"
msgstr ""
msgid ""
"This will permanently delete the %1 template. Would you like to continue?"
msgstr ""
msgid "View Table"
msgstr ""
msgid "View Gallery"
msgstr ""
msgid "Not Available"
msgstr ""
msgid "Please check the invalid Storage Pools"
msgstr ""
msgid "Please check the invalid Storage Pools or Paths"
msgstr ""
msgid "macvtap"
msgstr ""
msgid "ovs"
msgstr ""
msgid "network"
msgstr ""
msgid ""
"This will delete the %1 virtual machine and its virtual disks. This "
"operation cannot be undone. Would you like to continue?"
msgstr ""
msgid "Power off Confirmation"
msgstr ""
msgid ""
"This action may produce undesirable results, for example unflushed disk "
"cache in the %1 guest. Would you like to continue?"
msgstr ""
msgid "Reset Confirmation"
msgstr ""
msgid ""
"There is a risk of data loss caused by reset without the %1 guest OS "
"shutdown. Would you like to continue?"
msgstr ""
msgid "Shut Down Confirmation"
msgstr ""
msgid ""
"Note the %1 guest OS may ignore this request. Would you like to continue?"
msgstr ""
msgid "Virtual Machine delete Confirmation"
msgstr ""
msgid ""
"The %1 virtual machine is not persistent. Power Off will delete it. Continue?"
msgstr ""
msgid "Add Guest"
msgstr ""
msgid "Input is not a number"
msgstr ""
msgid "Memory value cannot be higher than Max Memory value"
msgstr ""
msgid ""
"For better performance it is recommended a threads per core value not "
"greater than %1."
msgstr ""
msgid ""
"This CDROM will be detached permanently and you can re-attach it. Continue "
"to detach it?"
msgstr ""
msgid "Attaching..."
msgstr ""
msgid ""
"This disk will be detached permanently and you can re-attach it. Continue to "
"detach it?"
msgstr ""
msgid "interface:"
msgstr ""
msgid "address:"
msgstr ""
msgid "link_type:"
msgstr ""
msgid "block:"
msgstr ""
msgid "drive_type:"
msgstr ""
msgid "model:"
msgstr ""
msgid "Affected devices:"
msgstr ""
msgid "Less"
msgstr ""
msgid "Successfully attached device to VM"
msgstr ""
msgid "Successfully detached device from VM"
msgstr ""
msgid "Following devices will be affected, confirm?"
msgstr ""
msgid "Bridge"
msgstr ""
msgid "Vepa"
msgstr ""
msgid "None"
msgstr ""
msgid "unavailable"
msgstr ""
msgid ""
"This action will interrupt network connectivity for any virtual machine that "
"depend on the %1 network."
msgstr ""
msgid "Add Network"
msgstr ""
msgid ""
"The %1 network is not persistent. Instead of stop, this action will "
"permanently delete it. Would you like to continue?"
msgstr ""
msgid ""
"The bridged VLAN tag may not work well with NetworkManager enabled. You "
"should consider disabling it."
msgstr ""
msgid ""
"This will permanently delete the %1 storage pool. Would you like to continue?"
msgstr ""
msgid "This storage pool is empty."
msgstr ""
msgid ""
"It will format your disk and you will loose any data in there, are you sure "
"to continue? "
msgstr ""
msgid "SCSI Fibre Channel"
msgstr ""
msgid "No SCSI adapters found."
msgstr ""
msgid "Loading iSCSI targets..."
msgstr ""
msgid "No iSCSI found. Please input one."
msgstr ""
msgid "Failed to load iSCSI targets."
msgstr ""
msgid "Would you like to continue?"
msgstr ""
msgid "This will permanently delete the following storage volumes: %1"
msgstr ""
msgid "No available partitions found."
msgstr ""
msgid ""
"The %1 storage pool is not persistent. Instead of deactivate, this action "
"will permanently delete it. Would you like to continue?"
msgstr ""
msgid "Unable to retrieve partitions information."
msgstr ""
msgid "In progress..."
msgstr ""
msgid "Failed!"
msgstr ""
msgid "No LVM found in the system."
msgstr ""
msgid "This will permanently wipe the following storage volumes: %1"
msgstr ""
msgid "Wipe Confirmation"
msgstr ""
msgid "Select one or more partitions to be added to the logical pool %1:"
msgstr ""
msgid "Add Storage"
msgstr ""
msgid "DIR"
msgstr ""
msgid "NFS"
msgstr ""
msgid "iSCSI"
msgstr ""
msgid "LOGICAL"
msgstr ""
msgid "device"
msgstr ""
msgid "path"
msgstr ""
msgid "size (GiB)"
msgstr ""
msgid "free size (GiB)"
msgstr ""
msgid "Invalid NFS mount path."
msgstr ""
msgid "No logical device selected."
msgstr ""
msgid "This is not a valid Server Name or IP. Please, modify it."
msgstr ""
msgid "CDROM path needs to be a valid local/remote path and cannot be blank."
msgstr ""
msgid "Disk pool or volume cannot be blank."
msgstr ""
msgid ""
"Disk size or Format or Directory path cannot be blank and Directory path "
"needs to be a valid local/remote path."
msgstr ""
msgid "Disk path needs to be a valid local/remote path and cannot be blank."
msgstr ""
msgid "Storage pool or Disk size or Format cannot be blank."
msgstr ""
msgid "cdrom"
msgstr ""
msgid "disk"
msgstr ""
msgid "Pool"
msgstr ""
msgid "qcow"
msgstr ""
msgid "qcow2"
msgstr ""
msgid "qed"
msgstr ""
msgid "raw"
msgstr ""
msgid "vmdk"
msgstr ""
msgid "vpc"
msgstr ""
msgid "Create a network"
msgstr ""
msgid "Network Name"
msgstr ""
msgid "Name should not contain '/' and '\"'."
msgstr ""
msgid "Network Type"
msgstr ""
msgid "Isolated: no external network connection"
msgstr ""
msgid "NAT: outbound physical network connection only"
msgstr ""
msgid "Macvtap: Virtual machines are connected to physical network directly"
msgstr ""
msgid ""
"Passthrough: Virtual machines are connected using a macvtap connection in "
"passthrough mode."
msgstr ""
msgid ""
"VEPA: special mode where virtual machines are connected to a VEPA-enabled "
"switch"
msgstr ""
msgid "Bridged: Virtual machines are connected through a network bridge"
msgstr ""
msgid "Destination"
msgstr ""
msgid "Select an Interface"
msgstr ""
msgid "Enable VLAN"
msgstr ""
msgid "VLAN ID"
msgstr ""
msgid "Edit Network"
msgstr ""
msgid "Address Space"
msgstr ""
msgid "Define a New Storage Pool"
msgstr ""
msgid "Storage Pool Name"
msgstr ""
msgid ""
"The name used to identify the storage pools, and it should not be empty."
msgstr ""
msgid "Storage Pool Type"
msgstr ""
msgid "Storage Path"
msgstr ""
msgid ""
"The path of the Storage Pool. Each Storage Pool must have a unique path."
msgstr ""
msgid ""
"Kimchi will try to create the directory when it does not already exist in "
"your system."
msgstr ""
msgid "NFS Server IP"
msgstr ""
msgid "NFS server IP or hostname. It can be input or chosen from history."
msgstr ""
msgid "NFS Path"
msgstr ""
msgid "The NFS exported path on NFS server."
msgstr ""
msgid "Create from existing LVM"
msgstr ""
msgid "Create from raw disk"
msgstr ""
msgid "Looking for existing lvms ..."
msgstr ""
msgid "Looking for available partitions ..."
msgstr ""
msgid "iSCSI Server"
msgstr ""
msgid "Server"
msgstr ""
msgid "Port"
msgstr ""
msgid "iSCSI server IP or hostname. It should not be empty."
msgstr ""
msgid "Target"
msgstr ""
msgid "The iSCSI target on iSCSI server"
msgstr ""
msgid "Add iSCSI Authentication"
msgstr ""
msgid "User Name"
msgstr ""
msgid "SCSI Adapter"
msgstr ""
msgid "Please, wait..."
msgstr ""
msgid "Add a Volume to Storage Pool"
msgstr ""
msgid "Fetch from remote URL"
msgstr ""
msgid "Enter the remote URL here."
msgstr ""
msgid "Upload a file"
msgstr ""
msgid "Choose the file you want to upload."
msgstr ""
msgid "Resize Volume"
msgstr ""
msgid "Size"
msgstr ""
msgid "The total space which can be used to store data. The unit is megabytes."
msgstr ""
msgid "Ok"
msgstr ""
msgid "Template Name"
msgstr ""
msgid ""
"The name used to identify the template. If omitted, a name will be "
"automatically chosen."
msgstr ""
msgid ""
"When selecting more than one Image Template, a name will be automatically "
"chosen for each Image Template selected."
msgstr ""
msgid "Where is the source media for this template? "
msgstr ""
msgid "Image Template"
msgstr ""
msgid "Netboot Template"
msgstr ""
msgid "File Path:"
msgstr ""
msgid "Search ISOs"
msgstr ""
msgid "The following ISOs are available:"
msgstr ""
msgid "QEMU does not have enough permission to work with this file"
msgstr ""
msgid "Search more ISOs"
msgstr ""
msgid "Loading..."
msgstr ""
msgid "Edit Template"
msgstr ""
msgid "CDROM"
msgstr ""
msgid "Image File"
msgstr ""
msgid "Graphics"
msgstr ""
msgid "Disk(GB)"
msgstr ""
msgid "Disk Format"
msgstr ""
msgid "Add Interface"
msgstr ""
msgid "pool"
msgstr ""
msgid "bridge"
msgstr ""
msgid "vepa"
msgstr ""
msgid "State"
msgstr ""
msgid "Guest Name ID"
msgstr ""
msgid "OS Type"
msgstr ""
msgid "VNC"
msgstr ""
msgid "No guests found."
msgstr ""
msgid "Stop"
msgstr ""
msgid "Location"
msgstr ""
msgid "%Used"
msgstr ""
msgid "Allocated"
msgstr ""
msgid "Capacity"
msgstr ""
msgid "Disks"
msgstr ""
msgid "Extending logical pool"
msgstr ""
msgid "%"
msgstr ""
msgid "Deactivate"
msgstr ""
msgid "Activate"
msgstr ""
msgid "Extend"
msgstr ""
msgid "Undefine"
msgstr ""
msgid "Add Volume"
msgstr ""
msgid "Resize"
msgstr ""
msgid "Wipe"
msgstr ""
msgid "Filter:"
msgstr ""
msgid "Used By"
msgstr ""
msgid "Used"
msgstr ""
msgid "Progress"
msgstr ""
msgid "Used by the following VMs:"
msgstr ""
msgid "Allocation"
msgstr ""
msgid "Template Name (ID)"
msgstr ""
msgid "No templates found."
msgstr ""
msgid "M"
msgstr ""
================================================
FILE: po/es_ES.po
================================================
# Spanish translations for kimchi package.
# Copyright IBM Corp, 2014-2017
# Adam Litke , 2013.
#
msgid ""
msgstr ""
"Project-Id-Version: kimchi 0.1\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2017-06-30 10:27-0300\n"
"PO-Revision-Date: 2013-07-11 17:32-0400\n"
"Last-Translator: Crístian Viana \n"
"Language-Team: English\n"
"Language: es_ES\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: pygettext.py 1.5\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
#, python-format
msgid "Unknown parameter %(value)s"
msgstr "Parámetro %(value)s desconocido"
#, python-format
msgid "User %(user_id)s not found with given LDAP settings."
msgstr ""
"No se ha encontrado el usuario %(user_id)s con los valores LDAP indicados."
#, python-format
msgid "Partition %(name)s does not exist in the host"
msgstr "La partición %(name)s no existe en el host"
#, python-format
msgid "Error while accessing dev mapper device, %(err)s"
msgstr ""
msgid "Block device not found."
msgstr ""
#, python-format
msgid "Block device %(device)s not found."
msgstr ""
#, python-format
msgid "Unable to retrieve LVM information. Details: %(err)s"
msgstr ""
msgid "Unknown \"_cap\" specified"
msgstr "Se ha especificado un valor \"_cap\" desconocido"
msgid "\"_passthrough\" should be \"true\" or \"false\""
msgstr "\"_passthrough\" debería ser \"true\" o \"false\""
msgid "\"_passthrough_affected_by\" should be a device name string"
msgstr ""
"\"_passthrough_affected_by\" debería ser una cadena de nombre de dispositivo"
msgid "\"_available_only\" should be \"true\" or \"false\""
msgstr "\"_available_only\" debería ser \"true\" o \"false\""
#, python-format
msgid "Unable to find distro file: %(filename)s"
msgstr "No se ha podido encontrar el archivo distro: %(filename)s"
#, python-format
msgid ""
"Unable to parse distro file: %(filename)s. Make sure, it is a JSON file."
msgstr ""
"No se ha podido analizar el archivo distro: %(filename)s. Asegúrese de que "
"se trate de un archivo JSON. "
#, python-format
msgid "Unable to login to iSCSI host target %(portal)s. Details: %(err)s"
msgstr ""
"No se puede iniciar sesión en el %(portal)s de destino de host iSCSI. "
"Detalles: %(err)s"
#, python-format
msgid "Unable to login to iSCSI host %(host)s target %(target)s"
msgstr ""
"No se puede iniciar sesión en el host iSCSI %(host)s de destino %(target)s"
#, python-format
msgid "Unable to find ISO file %(filename)s"
msgstr "No se puede encontrar el archivo ISO %(filename)s"
#, python-format
msgid "The ISO file %(filename)s is not bootable"
msgstr "El archivo ISO %(filename)s no se puede arrancar"
#, python-format
msgid "The ISO file %(filename)s does not have a valid El Torito boot record"
msgstr ""
"El archivo ISO %(filename)s no tiene un registro de arranque El Torito válido"
#, python-format
msgid "Invalid El Torito validation entry in ISO %(filename)s"
msgstr "La entrada de validación de El Torito no es válida en ISO %(filename)s"
#, python-format
msgid "Invalid El Torito boot indicator in ISO %(filename)s"
msgstr "El indicador de arranque de El Torito no es válido en ISO %(filename)s"
#, python-format
msgid "Unexpected volume type for primary volume in ISO %(filename)s"
msgstr ""
"Tipo de volumen inesperado para el volumen primario en ISO %(filename)s"
#, python-format
msgid "Bad format while reading volume descriptor in ISO %(filename)s"
msgstr "Formato erróneo al leer el descriptor de volúmenes en ISO %(filename)s"
#, python-format
msgid ""
"The hypervisor doesn't have permission to use this ISO %(filename)s. "
"Consider moving it under /var/lib/libvirt, or set the search permission to "
"file access control lists for '%(user)s' user if possible, or add the "
"'%(user)s' to the ISO path group, or (not recommended) 'chmod -R o+x "
"'path_to_iso'.Details: %(err)s"
msgstr ""
"El hipervisor no tiene permiso para utilizar este ISO %(filename)s. "
"Considere moverlo a /var/lib/libvirt, o establezca el permiso de búsqueda en "
"las listas de control de acceso de archivos para el usuario '%(user)s', si "
"es posible, o añada el '%(user)s' al grupo de vías de acceso ISO o (no "
"recomendado) 'chmod -R o+x 'path_to_iso'. Detalles: %(err)s"
#, python-format
msgid "Unable to access remote ISO. Details: %(err)s"
msgstr ""
#, python-format
msgid "Error probing image OS information: %(err)s"
msgstr ""
#, python-format
msgid "Unable to read image file %(filename)s"
msgstr "No se puede leer el archivo de imágenes %(filename)s"
#, python-format
msgid ""
"Image file must be an existing file on system. %(filename)s is not a valid "
"input."
msgstr ""
"El archivo de imágenes debe ser un archivo existente en el sistema. "
"%(filename)s no es una entrada válida. "
#, python-format
msgid "Virtual machine %(name)s already exists"
msgstr "Ya existe la máquina virtual %(name)s"
#, python-format
msgid "Virtual machine %(name)s does not exist"
msgstr "No existe la máquina virtual %(name)s"
#, python-format
msgid "Unable to retrieve screenshot for stopped virtual machine %(name)s"
msgstr ""
"No se puede recuperar la captura de pantalla para la máquina virtual "
"detenida %(name)s"
msgid "Remote ISO image is not supported by this server."
msgstr "La imagen ISO remota no está soportada por este servidor."
#, python-format
msgid "Screenshot is not supported on virtual machine %(name)s"
msgstr "No se acepta la captura de pantalla en la máquina virtual %(name)s"
#, python-format
msgid "Unable to create virtual machine %(name)s. Details: %(err)s"
msgstr "No se puede crear la máquina virtual %(name)s. Detalles: %(err)s"
#, python-format
msgid "Unable to update virtual machine %(name)s. Details: %(err)s"
msgstr "No se puede actualizar la máquina virtual %(name)s. Detalles: %(err)s"
#, python-format
msgid "Unable to retrieve virtual machine %(name)s. Details: %(err)s"
msgstr "No se puede recuperar la máquina virtual %(name)s. Detalles: %(err)s"
#, python-format
msgid "Unable to connect to powered off virtual machine %(name)s."
msgstr "No se puede conectar a la máquina virtual %(name)s apagada. "
msgid "Virtual machine name must be a string without slashes (/)"
msgstr ""
"El nombre de la máquina virtual debe ser una serie sin barras inclinadas (/)"
#, python-format
msgid "Invalid template URI %(value)s specified for virtual machine"
msgstr ""
"Se ha especificado un URI de plantilla %(value)s no válido para la máquina "
"virtual"
#, python-format
msgid "Invalid storage pool URI %(value)s specified for virtual machine"
msgstr ""
"Se ha especificado un URI de agrupación de almacenamiento %(value)s no "
"válido para la máquina virtual"
msgid "Supported virtual machine graphics are Spice or VNC"
msgstr "Los gráficos de la máquina virtual soportados son Spice o VNC"
msgid "Graphics address to listen on must be IPv4 or IPv6"
msgstr ""
"La dirección de gráficos en que hay que estar a la escucha debe ser IPv4 o "
"IPv6"
msgid "Specify a template to create a virtual machine from"
msgstr ""
"Especifique una plantilla a partir de la que se creará una máquina virtual"
#, python-format
msgid "Unable to start virtual machine %(name)s. Details: %(err)s"
msgstr "No se puede iniciar la máquina virtual %(name)s. Detalles: %(err)s"
#, python-format
msgid "Unable to power off virtual machine %(name)s. Details: %(err)s"
msgstr "No se puede apagar la máquina virtual %(name)s. Detalles: %(err)s"
#, python-format
msgid "Unable to delete virtual machine %(name)s. Details: %(err)s"
msgstr "No se puede suprimir la máquina virtual %(name)s. Detalles: %(err)s"
#, python-format
msgid "Unable to reset virtual machine %(name)s. Details: %(err)s"
msgstr "No se puede restablecer la máquina virtual %(name)s. Detalles: %(err)s"
msgid "User name list must be an array"
msgstr "La lista de nombres de usuarios debe ser una matriz"
msgid "User name must be a string"
msgstr "El nombre de usuario debe ser una serie"
msgid "Group name list must be an array"
msgstr "La lista de nombres de grupos debe ser una matriz"
msgid "Group name must be a string"
msgstr "El nombre de grupo debe ser una serie"
#, python-format
msgid "User(s) '%(users)s' do not exist"
msgstr "No existe el usuario (o usuarios) '%(users)s'"
#, python-format
msgid "Group(s) '%(groups)s' do not exist"
msgstr "No existe el grupo (o grupos) '%(groups)s'"
#, python-format
msgid "Unable to shutdown virtual machine %(name)s. Details: %(err)s"
msgstr "No se puede apagar la máquina virtual %(name)s. Detalles: %(err)s"
msgid "The guest console password must be a string."
msgstr "La contraseña de la consola del invitado debe ser una serie. "
msgid "The life time for the guest console password must be a number."
msgstr ""
"El tiempo de vida para la contraseña de la consola del invitado debe ser un "
"número. "
#, python-format
msgid "Virtual machine '%(name)s' must be stopped before cloning it."
msgstr "La máquina virtual '%(name)s' se debe detener antes de clonarla."
#, python-format
msgid "Insufficient disk space to clone virtual machine '%(name)s'"
msgstr ""
"No hay espacio de disco suficiente para clonar la máquina virtual '%(name)s'"
#, python-format
msgid "Unable to clone VM '%(name)s'. Details: %(err)s"
msgstr "No se puede clonar la máquina virtual '%(name)s'. Detalles: %(err)s"
#, python-format
msgid "Invalid operation for non-persistent virtual machine %(name)s"
msgstr "Operación no válida para la máquina virtual no persistente %(name)s"
#, python-format
msgid "Cannot suspend VM '%(name)s' because it is not running."
msgstr ""
"No se puede suspender la máquina virtual '%(name)s' porque no se está "
"ejecutando."
#, python-format
msgid "Unable to suspend VM '%(name)s'. Details: %(err)s"
msgstr "No se puede suspender la máquina virtual '%(name)s'. Detalles: %(err)s"
#, python-format
msgid "Cannot resume VM '%(name)s' because it is not paused."
msgstr ""
"No se puede reanudar la máquina virtual '%(name)s' porque no se ha puesto en "
"pausa. "
#, python-format
msgid "Unable to resume VM '%(name)s'. Details: %(err)s"
msgstr "No se puede reanudar la máquina virtual '%(name)s'. Detalles: %(err)s"
#, python-format
msgid ""
"Memory assigned is higher then the maximum allowed in the host: "
"%(maxmem)sMib."
msgstr ""
#, python-format
msgid ""
"Guest '%(name)s' does not support live memory update. Please, with the guest "
"offline, set Maximum Memory with a value greater then Memory to enable this "
"feature."
msgstr ""
msgid "Only increase memory is allowed in active VMs"
msgstr ""
"Solamente se permite aumentar la memoria en las máquinas virtuales activas"
msgid "There are not enough free slots to add a new memory device."
msgstr ""
msgid ""
"Host's libvirt or qemu version does not support memory devices and memory "
"hotplug. Libvirt must be >= 1.2.14 and QEMU must be >= 2.1."
msgstr ""
#, python-format
msgid "Error attaching memory device. Details: %(error)s"
msgstr "Error al conectar el dispositivo de memoria. Detalles: %(error)s"
#, python-format
msgid "Cannot start %(name)s. Virtual machine is already running."
msgstr "No se puede iniciar %(name)s. La máquina virtual ya está en ejecución."
#, python-format
msgid "Cannot power off %(name)s. Virtual machine is shut off."
msgstr "No se puede apagar %(name)s. La máquina virtual está apagada."
#, python-format
msgid "Cannot shutdown %(name)s. Virtual machine is shut off."
msgstr "No se puede apagar %(name)s. La máquina virtual está apagada."
#, python-format
msgid "Cannot reset %(name)s. Virtual machine is already shut off."
msgstr "No se puede restablecer %(name)s. La máquina virtual ya está apagada."
msgid "Boot order must be a list. Devices accepted: hd, cdrom, fd or network."
msgstr ""
msgid "Bootmenu must be boolean. Values accepted: true of false."
msgstr ""
msgid "Graphic type not valid. Values accepted: vnc or spice."
msgstr ""
#, python-format
msgid "Migrate to localhost %(host)s is not allowed."
msgstr ""
#, python-format
msgid ""
"To migrate a virtual machine to the remote host %(host)s the user %(user)s "
"must have password-less login to the remote host."
msgstr ""
#, python-format
msgid "Can not migrate virtual machine %(name)s when its in %(state)s state."
msgstr ""
#, python-format
msgid "Failed to migrate virtual machine %(name)s due error: %(err)s"
msgstr ""
msgid "User name of the remote server must be a string."
msgstr ""
msgid "Destination host of the migration must be a string."
msgstr ""
#, python-format
msgid "Unable to create file %(path)s at %(host)s using user %(user)s."
msgstr ""
#, python-format
msgid "Unable to read disk size of %(path)s, error: %(error)s"
msgstr ""
#, python-format
msgid ""
"Unable to create disk image %(path)s at %(host)s using user %(user)s. Error: "
"%(error)s"
msgstr ""
#, python-format
msgid ""
"Unable to migrate virtual machine to remote host %(host)s with arch "
"%(destarch)s using localhost with arch %(srcarch)s."
msgstr ""
#, python-format
msgid ""
"Unable to migrate virtual machine to remote host %(host)s with hypervisor "
"%(desthyp)s because localhost uses hypervisor %(srchyp)s."
msgstr ""
#, python-format
msgid ""
"Unable to determine remote host hypervisor and architecture. Error: %(error)s"
msgstr ""
#, python-format
msgid ""
"Unable to migrate virtual machine: subcores per core setting from "
"localhostand remote host %(host)s differs."
msgstr ""
#, python-format
msgid ""
"Unable to setup password-less login at remote host %(host)s using user "
"%(user)s. Error: %(error)s"
msgstr ""
msgid "Password field must be a string."
msgstr ""
msgid "Error creating local host ssh rsa key of user 'root'."
msgstr ""
#, python-format
msgid "%(param)s value (%(mem)sMiB) must be aligned to %(alignment)sMiB."
msgstr ""
#, python-format
msgid ""
"Unable to update the following parameters while the VM is offline: %(params)s"
msgstr ""
#, python-format
msgid ""
"Unable to update the following parameters while the VM is online: %(params)s"
msgstr ""
#, python-format
msgid ""
"VM %(name)s must have serial and console defined to open a web serial console"
msgstr ""
#, python-format
msgid "Impossible to get the serial console of %(name)s"
msgstr ""
#, python-format
msgid ""
"Memory or Maximum Memory value is higher than amount supported by the host: "
"%(memHost)sMiB."
msgstr ""
#, python-format
msgid ""
"Memory or Maximum Memory value is higher than maximum amount recommended: "
"%(value)sTiB"
msgstr ""
msgid "Cannot update Maximum Memory when guest is running."
msgstr ""
#, python-format
msgid "Impossible to create %(dir)s directory."
msgstr ""
#, python-format
msgid ""
"Either the guest %(name)s did not start to listen to the serial or it is not "
"configured to use the serial console."
msgstr ""
#, python-format
msgid ""
"Unable to retrieve Virt Viewer file for stopped virtual machine %(name)s"
msgstr ""
#, python-format
msgid ""
"Error occured while retrieving the Virt Viewer file for virtual machine "
"%(name)s : %(err)s"
msgstr ""
msgid "Virtual machine title must be a string"
msgstr ""
msgid "Virtual machine description must be a string"
msgstr ""
msgid "console parameter is only supported for s390x/s390 architecture."
msgstr ""
msgid "invalid console type, supported types are sclp/virtio."
msgstr ""
#, python-format
msgid ""
"Unable to setup password-less login at remote host %(host)s using user "
"%(user)s: remote directory %(sshdir)s does not exist."
msgstr ""
#, python-format
msgid ""
"Unable to create a password-less libvirt connection to the remote libvirt "
"daemon at host %(host)s with the user %(user)s. Please verify the remote "
"server libvirt configuration. More information: http://libvirt.org/auth."
"html ."
msgstr ""
msgid "'enable_rdma' must be of type boolean (true or false)."
msgstr ""
#, python-format
msgid ""
"VM %(vmid)s does not contain directly assigned host device %(dev_name)s."
msgstr ""
"La máquina virtual %(vmid)s no contiene el dispositivo de host asignado "
"directamente %(dev_name)s."
#, python-format
msgid "The host device %(dev_name)s is not allowed to directly assign to VM."
msgstr ""
"El dispositivo de host %(dev_name)s no se permite para asignarlo "
"directamente a la máquina virtual. "
msgid ""
"No IOMMU groups found. Host PCI pass through needs IOMMU group to function "
"correctly. Please enable Intel VT-d or AMD IOMMU in your BIOS, then verify "
"the Kernel is compiled with IOMMU support. For Intel CPU, add "
"'intel_iommu=on' to GRUB_CMDLINE_LINUX parameter in /etc/default/grub file. "
"For AMD CPU, add 'iommu=pt iommu=1'."
msgstr ""
msgid "\"name\" should be a device name string"
msgstr "\"name\" debe ser una serie de nombre de dispositivo"
#, python-format
msgid ""
"The device %(name)s is probably in use by the host. Unable to attach it to "
"the guest."
msgstr ""
"El dispositivo %(name)s lo está utilizando probablemente el host. No se "
"puede conectar al invitado. "
#, python-format
msgid "Hot-(un)plug of device %(name)s is not supported."
msgstr ""
#, python-format
msgid "Failed to attach %(device)s to %(vm)s"
msgstr ""
#, python-format
msgid "VM %(vmid)s does not have a USB controller to accept PCI hotplug."
msgstr ""
#, python-format
msgid "Interface %(iface)s does not exist in virtual machine %(name)s"
msgstr "La interfaz %(iface)s no existe en la máquina virtual %(name)s"
#, python-format
msgid ""
"Network %(network)s specified for virtual machine %(name)s does not exist"
msgstr ""
"La red %(network)s especificada para la máquina virtual %(name)s no existe"
msgid ""
"Supported virtual machine interfaces type are network, ovs and macvtap.Type "
"ovs and macvtap are only supported for s390x/s390 architecture."
msgstr ""
msgid "Network name for virtual machine interface must be a string"
msgstr ""
"El nombre de red para la interfaz de máquina virtual debe ser una serie"
msgid "Invalid network model card specified for virtual machine interface"
msgstr ""
"Especificada tarjeta de modelo de red no válida para la interfaz de máquina "
"virtual"
msgid "Specify type and network to add a new virtual machine interface"
msgstr ""
"Especifique el tipo y la red para añadir una interfaz de máquina virtual "
"nueva"
msgid "MAC Address must respect this format FF:FF:FF:FF:FF:FF"
msgstr "La dirección MAC debe respetar este formato FF:FF:FF:FF:FF:FF"
#, python-format
msgid "MAC Address %(mac)s already exists in virtual machine %(name)s"
msgstr "La dirección MAC %(mac)s ya existe en la máquina virtual %(name)s"
msgid "Invalid MAC Address"
msgstr "Dirección MAC no válida"
msgid "Cannot change MAC address of a running virtual machine"
msgstr ""
"No se puede cambiar la dirección MAC de una máquina virtual en ejecución"
msgid "Type macvtap and ovs are only supported on s390x/s390 architecture."
msgstr ""
msgid "Source attribute is only supported on s390x/s390 architecture."
msgstr ""
msgid "If source is provided, only type supported are macvtap and ovs."
msgstr ""
msgid "For type macvtap and ovs, source has to be provided"
msgstr ""
msgid "Source name for virtual machine interface must be string"
msgstr ""
msgid "Invalid source mode. Valid options are: bridge or vepa."
msgstr ""
#, python-format
msgid "Template %(name)s already exists"
msgstr "La plantilla %(name)s ya existe"
#, python-format
msgid "Source media %(path)s not found"
msgstr ""
#, python-format
msgid ""
"Network '%(network)s' specified for template %(template)s does not exist"
msgstr ""
"La red '%(network)s' especificada para la plantilla %(template)s no existe"
#, python-format
msgid ""
"Storage pool %(pool)s specified for template %(template)s does not exist"
msgstr ""
"La agrupación de almacenamiento %(pool)s especificada para la plantilla "
"%(template)s no existe"
#, python-format
msgid "Invalid parameter '%(param)s' specified for CDROM."
msgstr "Parámetro no válido '%(param)s' especificado para CDROM."
#, python-format
msgid "Network %(network)s specified for template %(template)s is not active"
msgstr ""
"La red %(network)s que se ha especificado para la plantilla %(template)s no "
"está activa"
msgid "Template name must be a string"
msgstr "El nombre de plantilla debe ser una serie"
msgid "Template icon must be a path to the image"
msgstr "El icono de plantilla debe ser una vía de acceso a la imagen"
msgid "Template distribution must be a string"
msgstr "La distribución de plantilla debe ser una serie"
msgid "Template distribution version must be a string"
msgstr "La versión de distribución de plantilla debe ser una serie"
msgid "The number of CPUs must be an integer greater than 0"
msgstr "El número de CPU debe ser un entero mayor que 0"
msgid ""
"Amount of memory and maximum memory (MB) must be an integer greater than 512"
msgstr ""
msgid "Template CDROM must be a local or remote ISO file"
msgstr "El CDROM de plantilla debe ser un archivo ISO local o remoto"
#, python-format
msgid "Invalid storage pool URI %(value)s specified for template"
msgstr ""
"Se ha especificado un URI de agrupación de almacenamiento %(value)s no "
"válido para la plantilla"
msgid ""
"Specify a path to source media (ISO, disk or remote ISO) to create a template"
msgstr ""
msgid "All networks for the template must be specified in a list."
msgstr "Todas las redes para la plantilla deben especificarse en una lista."
msgid "Specify a volume to a template when storage pool is iSCSI or SCSI"
msgstr ""
"Especifique un volumen para una plantilla cuando la agrupación de "
"almacenamiento sea iSCSI o SCSI"
#, python-format
msgid "The volume %(volume)s is not in storage pool %(pool)s"
msgstr ""
"El volumen %(volume)s no se halla en la agrupación de almacenamiento %(pool)s"
#, python-format
msgid "Unable to create template due error: %(err)s"
msgstr "No se ha podido crear la plantilla debido al error: %(err)s"
#, python-format
msgid "Unable to delete template due error: %(err)s"
msgstr "No se ha podido suprimir la plantilla debido a un error: %(err)s"
msgid "Disk size must be an integer greater than 1GB."
msgstr "El tamaño del disco debe ser un entero mayor que 1 GB."
#, python-format
msgid "Cannot identify base image %(path)s format"
msgstr "No se puede identificar el formato de la imagen base %(path)s"
msgid ""
"When specifying CPU topology, each element must be an integer greater than "
"zero."
msgstr ""
"Cuando se especifica la topología de CPU, cada elemento debe ser un entero "
"mayor que cero."
msgid ""
"Invalid disk image format. Valid formats: qcow, qcow2, qed, raw, vmdk, vpc."
msgstr ""
msgid ""
"When setting template disks, following parameters are required: 'index', "
"'pool name', 'format', 'size' or 'volume' (for scsi/iscsi pools)"
msgstr ""
msgid "Disk format must be 'raw', for logical, iscsi, and scsi pools."
msgstr ""
msgid ""
"Memory expects an object with one or both parameters: 'current' and "
"'maxmemory'"
msgstr ""
#, python-format
msgid ""
"Memory value (%(mem)sMiB) must be equal or lesser than maximum memory value "
"(%(maxmem)sMiB)"
msgstr ""
#, python-format
msgid "Unable to update template due error: %(err)s"
msgstr ""
msgid "Parameter 'disks' requires at least one disk object"
msgstr ""
msgid ""
"Invalid interface type. Type should be 'macvtap' for host network interface "
"(Ethernet, Bond, VLAN) to be connected as direct MacVTap or 'ovs' for "
"openvswitch host network interface to be connected as virtual switch to a VM."
msgstr ""
msgid "Interface name should be string."
msgstr ""
msgid "Invalid interface mode. Valid options are: bridge or vepa."
msgstr ""
msgid ""
"Interfaces should be list of interfaces. Each interface should have name, "
"type and mode(optional, only applicable for interfcae type 'macvtap'."
msgstr ""
msgid ""
"Interface expects an object with parameters: 'name', 'type' and 'mode'. Name "
"should be name of host network interface (Ethernet, Bond, VLAN) for type "
"'macvtap' or the name of host openvswitch bridge interface for type 'ovs'. "
"Mode (optional) is only applicable for interface type 'macvtap' to indicates "
"whether packets will be delivered directly to target device (bridge) or to "
"the external bridge (vepa-capable bridge)."
msgstr ""
msgid "Interfaces parameter only supported on s390x or s390 architecture."
msgstr ""
msgid "Storage without libvirt pool is not supported on this architecture"
msgstr ""
#, python-format
msgid "Error while creating the virtual disk for the guest. Details: %(err)s"
msgstr ""
msgid ""
"When setting template disks without libvirt, following parameters are "
"required: 'index', 'format', 'path', 'size'"
msgstr ""
#, python-format
msgid "Storage pool %(name)s already exists"
msgstr "Ya existe la agrupación de almacenamiento %(name)s"
#, python-format
msgid "Storage pool %(name)s does not exist"
msgstr "No existe la agrupación de almacenamiento %(name)s"
#, python-format
msgid "Specify %(item)s in order to create the storage pool %(name)s"
msgstr ""
"Especifique %(item)s para crear la agrupación de almacenamiento %(name)s"
#, python-format
msgid "Unable to delete active storage pool %(name)s"
msgstr "No se puede suprimir la agrupación de almacenamiento activo %(name)s"
#, python-format
msgid "Unable to list storage pools. Details: %(err)s"
msgstr ""
"No se pueden listar las agrupaciones de almacenamiento. Detalles: %(err)s"
#, python-format
msgid "Unable to create storage pool %(name)s. Details: %(err)s"
msgstr ""
"No se puede crear la agrupación de almacenamiento %(name)s. Detalles: %(err)s"
#, python-format
msgid "Unable to activate storage pool %(name)s. Details: %(err)s"
msgstr ""
"No se puede activar la agrupación de almacenamiento %(name)s. Detalles: "
"%(err)s"
#, python-format
msgid "Unable to deactivate storage pool %(name)s. Details: %(err)s"
msgstr ""
"No se puede desactivar la agrupación de almacenamiento %(name)s. Detalles: "
"%(err)s"
#, python-format
msgid "Unable to delete storage pool %(name)s. Details: %(err)s"
msgstr ""
"No se puede suprimir la agrupación de almacenamiento %(name)s. Detalles: "
"%(err)s"
#, python-format
msgid ""
"Unable to create NFS Pool as export path %(path)s may block during mount"
msgstr ""
"No se puede crear la agrupación de NFS ya que la vía de acceso de "
"exportación %(path)s podría bloquearse durante el montaje"
#, python-format
msgid "Unable to create NFS Pool as export path %(path)s mount failed"
msgstr ""
"No se puede crear la agrupación de NFS ya que ha fallado el montaje de la "
"vía de acceso de exportación %(path)s"
#, python-format
msgid "Unsupported storage pool type: %(type)s"
msgstr "Tipo de agrupación de almacenamiento no admitido: %(type)s"
#, python-format
msgid "Error while retrieving storage pool XML to %(pool)s"
msgstr ""
"Error al recuperar el XML de la agrupación de almacenamiento en %(pool)s"
msgid "Storage pool name must be a string without slashes (/)"
msgstr ""
"El nombre de la agrupación de almacenamiento debe ser una serie sin barras "
"inclinadas (/)"
msgid ""
"Supported storage pool types are dir, netfs, logical, iscsi, isci and kimchi-"
"iso"
msgstr ""
"Los tipos de agrupación de almacenamiento admitidos son dir, netfs, logical, "
"iscsi, isci y kimchi-iso"
msgid "Storage pool path must be a string"
msgstr "La vía de acceso de la agrupación de almacenamiento debe ser una serie"
msgid "Storage pool host must be a IP or hostname"
msgstr ""
"El host de la agrupación de almacenamiento debe ser un IP o nombre de host"
msgid "Storage pool device must be the absolute path to the block device"
msgstr ""
"El dispositivo de la agrupación de almacenamiento debe ser la vía de acceso "
"absoluta al dispositivo de bloque"
msgid "Storage pool devices parameter must be a list"
msgstr ""
"El parámetro de los dispositivos de agrupación de almacenamiento debe ser "
"una lista"
msgid "Target IQN of an iSCSI pool must be a string"
msgstr "El IQN destino de una agrupación de iSCSI debe ser una serie"
msgid "Port of a remote storage server must be an integer between 1 and 65535"
msgstr ""
"El puerto de un servidor de almacenamiento remoto debe ser un entero entre 1 "
"y 65535"
msgid "iSCSI target username must be a string"
msgstr "El nombre de usuario de destino de iSCSI debe ser una serie"
msgid "iSCSI target password must be a string"
msgstr "La contraseña de destino de iSCSI debe ser una serie"
msgid "Specify name and type to create a storage pool"
msgstr ""
"Especifique el nombre y el tipo para crear una agrupación de almacenamiento"
#, python-format
msgid ""
"%(disk)s is not a valid disk/partition. Could not add it to the pool "
"%(pool)s."
msgstr ""
"%(disk)s no es un disco/partición válido. No se ha podido añadir a la "
"agrupación %(pool)s."
#, python-format
msgid "Unable to extend logical pool %(pool)s. Details: %(err)s"
msgstr "No se puede ampliar la agrupación lógica %(pool)s. Detalles: %(err)s"
msgid "The parameter disks only can be updated for logical storage pool."
msgstr ""
"Los discos de parámetro sólo pueden actualizarse para la agrupación de "
"almacenamiento lógico."
msgid "The SCSI host adapter name must be a string."
msgstr "El nombre del adaptador de host SCSI debe ser una serie."
msgid "The storage pool kimchi_isos is reserved for internal use"
msgstr ""
"La agrupación de almacenamiento kimchi_isos está reservada para uso interno"
#, python-format
msgid ""
"Unable to activate NFS storage pool %(name)s. NFS server %(server)s is "
"unreachable."
msgstr ""
"No se puede activar la agrupación de almacenamiento NFS %(name)s. El "
"servidor NFS %(server)s está fuera de alcance."
#, python-format
msgid ""
"Unable to deactivate NFS storage pool %(name)s. NFS server %(server)s is "
"unreachable."
msgstr ""
"No se puede desactivar la agrupación de almacenamiento NFS %(name)s. El "
"servidor NFS %(server)s está fuera de alcance."
#, python-format
msgid ""
"Unable to deactivate pool %(name)s as it is associated with some templates"
msgstr ""
"No se puede desactivar la agrupación %(name)s ya que está asociada con "
"algunas plantillas"
#, python-format
msgid "Unable to delete pool %(name)s as it is associated with some templates"
msgstr ""
"No se puede suprimir la agrupación %(name)s ya que está asociada con algunas "
"plantillas"
#, python-format
msgid ""
"A volume group named '%(name)s' already exists. Please, choose another name "
"to create the logical pool."
msgstr ""
"Ya existe un grupo de volúmenes denominado '%(name)s'. Elija otro nombre "
"para crear la agrupación lógica."
#, python-format
msgid "Unable to update database with deep scan information due error: %(err)s"
msgstr ""
"No se puede actualizar la base de datos con la información de exploración "
"profunda debido a un error: %(err)s"
#, python-format
msgid ""
"No volume group '%(name)s' found. Please, specify an existing volume group "
"to create the logical pool from."
msgstr ""
#, python-format
msgid "Unable to delete pool %(name)s as it is associated with guests: %(vms)s"
msgstr ""
#, python-format
msgid "Storage volume %(name)s already exists"
msgstr "Ya existe el volumen de almacenamiento %(name)s"
#, python-format
msgid "Storage volume %(name)s does not exist in storage pool %(pool)s"
msgstr ""
"No existe el volumen de almacenamiento %(name)s en la agrupación de "
"almacenamiento %(pool)s"
#, python-format
msgid ""
"Unable to create storage volume %(volume)s because storage pool %(pool)s is "
"not active"
msgstr ""
"No se puede crear el volumen de almacenamiento %(volume)s porque la "
"agrupación de almacenamiento %(pool)s no está activa"
#, python-format
msgid "Specify %(item)s in order to create storage volume %(volume)s"
msgstr ""
"Especifique %(item)s para crear el volumen de almacenamiento %(volume)s"
#, python-format
msgid ""
"Unable to list storage volumes because storage pool %(pool)s is not active"
msgstr ""
"No se pueden listar los volúmenes de almacenamiento porque la agrupación de "
"almacenamiento %(pool)s no está activa"
#, python-format
msgid ""
"Unable to create storage volume %(name)s in storage pool %(pool)s. Details: "
"%(err)s"
msgstr ""
"No se puede crear el volumen de almacenamiento %(name)s en la agrupación de "
"almacenamiento %(pool)s. Detalles: %(err)s"
#, python-format
msgid "Unable to wipe storage volumes %(name)s. Details: %(err)s"
msgstr ""
"No se pueden limpiar los volúmenes de almacenamiento %(name)s. Detalles: "
"%(err)s"
#, python-format
msgid "Unable to delete storage volume %(name)s. Details: %(err)s"
msgstr ""
"No se puede suprimir el volumen de almacenamiento %(name)s. Detalles: %(err)s"
#, python-format
msgid "Unable to resize storage volume %(name)s. Details: %(err)s"
msgstr ""
"No se puede redimensionar el volumen de almacenamiento %(name)s. Detalles: "
"%(err)s"
#, python-format
msgid "Storage type %(type)s does not support volume create and delete"
msgstr ""
"El tipo de almacenamiento %(type)s no admite la creación y supresión del "
"volumen"
msgid "Storage volume name must be a string"
msgstr "El nombre de volumen de almacenamiento debe ser una serie"
msgid "Storage volume allocation must be an integer number"
msgstr "La asignación de volumen de almacenamiento debe ser un número entero"
msgid ""
"Storage volume format not supported. Valid formats: qcow, qcow2, qed, raw, "
"vmdk, vpc."
msgstr ""
msgid "Storage volume requires a volume name"
msgstr "El volumen de almacenamiento requiere un nombre de volumen"
#, python-format
msgid ""
"Unable to update database with storage volume information due error: %(err)s"
msgstr ""
"No se puede actualizar la base de datos con la información del volumen de "
"almacenamiento debido a un error: %(err)s"
#, python-format
msgid "Only one of parameter %(param)s can be specified"
msgstr "Sólo se puede especificar uno de los parámetros %(param)s"
#, python-format
msgid "Create volume from %(param)s is not supported"
msgstr "No se admite la creación del volumen de %(param)s"
msgid "Storage volume capacity must be an integer number."
msgstr "La capacidad del volumen de almacenamiento debe ser un número entero. "
msgid "Storage volume URL must be http://, https://, ftp:// or ftps://."
msgstr ""
"El URL del volumen de almacenamiento debe ser http://, https://, ftp:// o "
"ftps://."
#, python-format
msgid "Unable to access file %(url)s. Please, check it."
msgstr "No se puede acceder al archivo %(url)s. Por favor, compruébelo. "
#, python-format
msgid ""
"Unable to clone storage volume '%(name)s' in pool '%(pool)s'. Details: "
"%(err)s"
msgstr ""
"No se puede clonar el volumen de almacenamiento '%(name)s' en la agrupación "
"'%(pool)s'. Detalles: %(err)s"
msgid "Specify chunk data and its size to upload a file."
msgstr "Especifique datos de fragmento y su tamaño para cargar un archivo. "
msgid "In order to upload a storage volume, specify the 'upload' parameter."
msgstr ""
"Para cargar un volumen de almacenamiento, especifique el parámetro 'upload'. "
msgid ""
"Unable to upload chunk data as it does not match with requested chunk size."
msgstr ""
"No se pueden cargar datos de fragmento porque no coinciden con el tamaño de "
"fragmento solicitado. "
#, python-format
msgid "The storage volume %(vol)s is not under an upload process."
msgstr ""
"El volumen de almacenamiento %(vol)s no está bajo un proceso de carga. "
msgid "The upload chunk data will exceed the storage volume size."
msgstr ""
"Los datos de fragmento de carga superarán el tamaño del volumen de "
"almacenamiento. "
#, python-format
msgid "Unable to upload chunk data to storage volume. Details: %(err)s."
msgstr ""
"No se pueden cargar datos de fragmento al volumen de almacenamiento. "
"Detalles: %(err)s."
#, python-format
msgid "Interface %(name)s does not exist"
msgstr "No existe la interfaz %(name)s"
#, python-format
msgid ""
"Failed to list interfaces. Invalid _inuse parameter. Supported options for "
"_inuse are: %(supported_inuse)s"
msgstr ""
#, python-format
msgid "Network %(name)s already exists"
msgstr "Ya existe la red %(name)s"
#, python-format
msgid "Network %(name)s does not exist"
msgstr "No existe la red %(name)s"
#, python-format
msgid "Subnet %(subnet)s specified for network %(network)s is not valid."
msgstr ""
msgid "Specify a network interface to create bridged or macvtap networks."
msgstr ""
#, python-format
msgid "Unable to delete or update active network %(name)s"
msgstr ""
#, python-format
msgid "Interface %(iface)s specified for network %(network)s is already in use"
msgstr ""
"La interfaz %(iface)s especificada para la red %(network)s ya se está "
"utilizando"
msgid "Interface should be bare NIC, bonding or bridge device."
msgstr "La interfaz debe ser dispositivo de puente, enlazado o NIC simple."
#, python-format
msgid "Unable to create or update network %(name)s. Details: %(err)s"
msgstr ""
#, python-format
msgid "Unable to find a free IP address for network '%(name)s'"
msgstr "No se puede encontrar una dirección IP libre para la red '%(name)s'"
#, python-format
msgid "The interface %(iface)s already exists."
msgstr "La interfaz %(iface)s ya existe."
msgid "Network name must be a string without slashes (/) or quotes (\")"
msgstr ""
"El nombre de red debe ser una serie sin barras inclinadas (/) ni comillas "
"(\")"
msgid ""
"Supported network types are isolated, NAT, macvtap, bridge, vepa and "
"passthrough."
msgstr ""
msgid "Network subnet must be a string with IP address and prefix or netmask"
msgstr ""
"La subred de red debe ser una serie con dirección IP y prefijo o máscara de "
"red"
msgid "Network interfaces must be an array."
msgstr ""
msgid "Network VLAN ID must be an integer between 1 and 4094"
msgstr "El ID de VLAN de red debe ser un entero entre 1 y 4094"
msgid "Specify name and type to create a Network"
msgstr "Especifique el nombre y el tipo para crear una red"
#, python-format
msgid ""
"Unable to delete or update network %(name)s as it is linked to some virtual "
"machines (%(vms)s) and/or templates (%(tmpls)s)."
msgstr ""
#, python-format
msgid ""
"Unable to deactivate network %(name)s as it is linked to are some virtual "
"machines (%(vms)s) and/or templates (%(tmpls)s)."
msgstr ""
#, python-format
msgid "Bridge device %(name)s can not be the trunk device of a VLAN."
msgstr ""
"El dispositivo en puente %(name)s no puede ser el dispositivo de conexión "
"troncal de una VLAN."
#, python-format
msgid "Failed to activate interface %(iface)s: %(err)s."
msgstr "No se ha podido activar la interfaz %(iface)s: %(err)s."
#, python-format
msgid ""
"Failed to activate interface %(iface)s. Please check the physical link "
"status."
msgstr ""
"No se ha podido activar la interfaz %(iface)s. Compruebe el estado del "
"enlace físico. "
#, python-format
msgid "Failed to start network %(name)s. Details: %(err)s"
msgstr "No se ha podido iniciar la red %(name)s. Detalles: %(err)s"
#, python-format
msgid "Unable to redefine interface %(name)s. Details: %(err)s"
msgstr ""
#, python-format
msgid "Unable to create bridge %(name)s. Details: %(err)s"
msgstr ""
msgid ""
"Unable to create bridge with NetworkManager enabled. Disable it and try "
"again."
msgstr ""
msgid "Interface should be bare NIC or bonding."
msgstr ""
msgid "Network interfaces parameter must contain at least one interface."
msgstr ""
msgid "Only one interface is allowed for 'bridge' and 'macvtap' networks."
msgstr ""
msgid "Subnet is not a valid parameter for this type of virtual network."
msgstr ""
msgid ""
"VLAN ID and interfaces are not valid parameters for this type of virtual "
"network."
msgstr ""
#, python-format
msgid "Storage server %(server)s was not used by Kimchi"
msgstr "El servidor de almacenamiento %(server)s no lo ha utilizado Kimchi"
#, python-format
msgid "Distro '%(name)s' does not exist"
msgstr "No existe Distro '%(name)s'"
#, python-format
msgid "Node device '%(name)s' not found"
msgstr "No se encuentra el dispositivo de nodos '%(name)s'"
msgid "Conflicting flag filters specified."
msgstr "Se han especificado filtros de distintivos en conflicto."
msgid "Unable to choose a virtual machine name"
msgstr "No se puede elegir un nombre de máquina virtual"
msgid "Cannot upgrade objectstore data."
msgstr ""
msgid "Invalid storage type. Types supported: 'cdrom', 'disk'"
msgstr "Tipo de almacenamiento no válido. Tipos soportados: 'cdrom', 'disk'"
#, python-format
msgid "The path '%(value)s' is not a valid local/remote path for the device"
msgstr ""
"La vía de acceso '%(value)s' no es una vía de acceso local/remota válida "
"para el dispositivo"
msgid "Only CDROM path can be update."
msgstr "Solamente se puede actualizar la vía de acceso de CDROM. "
#, python-format
msgid ""
"The storage device %(dev_name)s does not exist in the virtual machine "
"%(vm_name)s"
msgstr ""
"El dispositivo de almacenamiento %(dev_name)s no existe en la máquina "
"virtual. %(vm_name)s"
#, python-format
msgid "Error while creating new storage device: %(error)s"
msgstr "Error al crear el dispositivo de almacenamiento nuevo: %(error)s"
#, python-format
msgid "Error while updating storage device: %(error)s"
msgstr "Error al actualizar el dispositivo de almacenamiento: %(error)s"
#, python-format
msgid "Error while removing storage device: %(error)s"
msgstr "Error al eliminar el dispositivo de almacenamiento: %(error)s"
msgid "Do not support IDE device hot plug"
msgstr "No se admite la conexión en caliente del IDE"
msgid ""
"Specify type and path or type and pool/volume to add a new virtual machine "
"disk"
msgstr ""
"Especifique el tipo y la vía de acceso y la agrupación/volumen para añadir "
"un nuevo disco de máquina virtual"
msgid "Specify path to update virtual machine disk"
msgstr ""
"Especifique la vía de acceso para actualizar el disco de máquina virtual"
#, python-format
msgid "Controller type %(type)s limitation of %(limit)s devices reached"
msgstr ""
"Se ha alcanzado el límite de tipo de controlador %(type)s de %(limit)s "
"dispositivos"
#, python-format
msgid "Cannot retrieve disk path information for given pool/volume: %(error)s"
msgstr ""
"No se puede recuperar la información de vía de acceso de disco para la "
"agrupación o el volumen que se ha especificado: %(error)s"
msgid "Volume already in use by other virtual machine."
msgstr "El volumen ya lo está utilizando otra máquina virtual. "
msgid ""
"Only one of path or pool/volume can be specified to add a new virtual "
"machine disk"
msgstr ""
"Solo se puede especificar uno de vía de acceso o agrupación/volumen para "
"añadir un nuevo disco de máquina virtual"
#, python-format
msgid ""
"Volume chosen with format %(format)s does not fit in the storage type "
"%(type)s"
msgstr ""
"El volumen elegido con el formato %(format)s no se ajusta al tipo de "
"almacenamiento%(type)s"
msgid "On s390x arch one of pool, path of dir_path must be specified"
msgstr ""
msgid ""
"On s390x arch 'format' must be specified while attaching disk to virtual "
"machine"
msgstr ""
#, python-format
msgid "Virtual disk already exists on the system: %(disk_path)s"
msgstr ""
#, python-format
msgid ""
"Unable to create snapshot '%(name)s' on virtual machine '%(vm)s'. Details: "
"%(err)s"
msgstr ""
"No se puede crear la instantánea '%(name)s' en la máquina virtual '%(vm)s'. "
"Detalles: %(err)s"
#, python-format
msgid "Snapshot '%(name)s' does not exist on virtual machine '%(vm)s'."
msgstr "La instantánea '%(name)s' no existe en la máquina virtual '%(vm)s'."
#, python-format
msgid ""
"Unable to retrieve snapshot '%(name)s' on virtual machine '%(vm)s'. Details: "
"%(err)s"
msgstr ""
"No se puede recuperar la instantánea '%(name)s' en la máquina virtual "
"'%(vm)s'. Detalles: %(err)s"
#, python-format
msgid "Unable to list snapshots on virtual machine '%(vm)s'. Details: %(err)s"
msgstr ""
"No se pueden listar las instantáneas en la máquina virtual '%(vm)s'. "
"Detalles: %(err)s"
#, python-format
msgid ""
"Unable to delete snapshot '%(name)s' on virtual machine '%(vm)s'. Details: "
"%(err)s"
msgstr ""
"No se puede suprimir la instantánea '%(name)s' en la máquina virtual "
"'%(vm)s'. Detalles: %(err)s"
#, python-format
msgid ""
"Unable to retrieve current snapshot of virtual machine '%(vm)s'. Details: "
"%(err)s"
msgstr ""
"No se puede recuperar la instantánea actual de la máquina virtual '%(vm)s'. "
"Detalles: %(err)s"
#, python-format
msgid ""
"Unable to revert virtual machine '%(vm)s' to snapshot '%(name)s'. Details: "
"%(err)s"
msgstr ""
"No se puede revertir la máquina virtual '%(vm)s' en la instantánea "
"'%(name)s'. Detalles: %(err)s"
#, python-format
msgid ""
"Unable to create snapshot of virtual machine '%(vm)s' because it contains a "
"disk with format '%(format)s'; only 'qcow2' is supported."
msgstr ""
"No se puede crear la instantánea de la máquina virtual '%(vm)s' porque "
"contiene un disco con el formato '%(format)s'; sólo se admite 'qcow2'. "
msgid ""
"The number of vCPUs must be less than or equal the maximum number of vCPUs "
"specified."
msgstr ""
msgid ""
"When CPU topology is defined, maximum number of vCPUs must be a product of "
"sockets, cores, and threads."
msgstr ""
msgid "This host (or current configuration) does not allow CPU topology."
msgstr "Este host (o la configuración actual) no permite la topología de CPU. "
msgid "The maximum number of vCPUs is too large for this system."
msgstr ""
msgid ""
"When CPU topology is defined, CPUs must be a multiple of the 'threads' "
"number defined."
msgstr ""
msgid ""
"When CPU topology is specified, sockets, cores and threads are required "
"paramaters."
msgstr ""
msgid ""
"Parameter 'cpu_info' expects an object with fields among: 'vcpus', "
"'maxvcpus', 'topology'."
msgstr ""
msgid ""
"Parameter 'topology' expects an object with fields among: 'sockets', "
"'cores', 'threads'."
msgstr ""
msgid "Unable to update Max CPU or CPU topology when guest is running."
msgstr ""
#, python-format
msgid "Unable to hot plug/unplug CPUs. Details: %(err)s"
msgstr ""
#, python-format
msgid "Invalid volume group name parameter: %(name)s."
msgstr ""
msgid ""
"Unable to establish connection with libvirt. Please check your libvirt URI "
"which is often defined in /etc/libvirt/libvirt.conf"
msgstr ""
msgid ""
"Libvirt service is not active. Please start the libvirt service in your host "
"system."
msgstr ""
msgid "Failed to register the default event implementation."
msgstr ""
msgid "Failed to register timeout event."
msgstr ""
msgid "Failed to Run the default event implementation."
msgstr ""
#, python-format
msgid ""
"I/O error on guest '%(vm)s': storage pool out of space for %(devAlias)s "
"(%(srcPath)s)."
msgstr ""
#, python-format
msgid "Create virtual network '%(name)s' type '%(connection)s'"
msgstr ""
#, python-format
msgid "Remove virtual network '%(ident)s'"
msgstr ""
#, python-format
msgid "Update virtual network '%(ident)s'"
msgstr ""
#, python-format
msgid "Activate virtual network '%(ident)s'"
msgstr ""
#, python-format
msgid "Deactivate virtual network '%(ident)s'"
msgstr ""
#, python-format
msgid "Create storage pool '%(name)s' type '%(type)s'"
msgstr ""
#, python-format
msgid "Remove storage pool '%(ident)s'"
msgstr ""
#, python-format
msgid "Update storage pool '%(ident)s'"
msgstr ""
#, python-format
msgid "Activate storage pool '%(ident)s'"
msgstr ""
#, python-format
msgid "Deactivate storage pool '%(ident)s'"
msgstr ""
#, python-format
msgid "Create snapshot '%(name)s' at guest '%(vm)s'"
msgstr ""
#, python-format
msgid "Remove snapshot '%(ident)s' from guest '%(vm)s'"
msgstr ""
#, python-format
msgid "Revert guest '%(vm)s' to snapshot '%(ident)s'"
msgstr ""
#, python-format
msgid "Create template '%(name)s'"
msgstr ""
#, python-format
msgid "Remove template '%(ident)s'"
msgstr ""
#, python-format
msgid "Update template '%(ident)s'"
msgstr ""
#, python-format
msgid "Clone template '%(ident)s'"
msgstr ""
#, python-format
msgid "Create guest '%(name)s' from template '%(template)s'"
msgstr ""
#, python-format
msgid "Remove guest '%(ident)s'"
msgstr ""
#, python-format
msgid "Edit guest '%(ident)s'"
msgstr ""
#, python-format
msgid "Start guest '%(ident)s'"
msgstr ""
#, python-format
msgid "Power off guest '%(ident)s'"
msgstr ""
#, python-format
msgid "Shutdown guest '%(ident)s'"
msgstr ""
#, python-format
msgid "Restart guest '%(ident)s'"
msgstr ""
#, python-format
msgid "Connect to guest '%(ident)s' through novnc/spice"
msgstr ""
#, python-format
msgid "Clone guest '%(ident)s'"
msgstr ""
#, python-format
msgid "Migrate guest '%(ident)s' to '%(remote_host)s'"
msgstr ""
#, python-format
msgid "Suspend guest '%(ident)s'"
msgstr ""
#, python-format
msgid "Resume guest '%(ident)s'"
msgstr ""
#, python-format
msgid "Connect to guest '%(ident)s' through serial"
msgstr ""
#, python-format
msgid "Attach host device '%(name)s' to guest '%(vmid)s'"
msgstr ""
#, python-format
msgid "Detach host device '%(ident)s' from guest '%(vmid)s'"
msgstr ""
#, python-format
msgid "Attach network interface '%(network)s' to guest '%(vm)s'"
msgstr ""
#, python-format
msgid "Detach network interface '%(ident)s' from guest '%(vm)s'"
msgstr ""
#, python-format
msgid "Update network interface '%(ident)s' at guest '%(vm)s'"
msgstr ""
#, python-format
msgid "Attach %(type)s storage '%(path)s' to guest '%(vm)s'"
msgstr ""
#, python-format
msgid "Remove storage '%(ident)s' from guest '%(vm)s'"
msgstr ""
#, python-format
msgid "Update storage '%(ident)s' at guest '%(vm)s'"
msgstr ""
#, python-format
msgid "Create storage volume '%(name)s' at pool '%(pool)s'"
msgstr ""
#, python-format
msgid "Remove storage volume '%(ident)s' from pool '%(pool)s'"
msgstr ""
#, python-format
msgid "Update storage volume '%(ident)s' at pool '%(pool)s'"
msgstr ""
#, python-format
msgid "Wipe storage volume '%(ident)s' off pool '%(pool)s'"
msgstr ""
#, python-format
msgid "Resize storage volume '%(ident)s' at pool '%(pool)s' with size %(size)s"
msgstr ""
#, python-format
msgid "Clone storage volume '%(ident)s' at pool '%(pool)s'"
msgstr ""
msgid "Create a New Virtual Machine"
msgstr "Crear una nueva máquina virtual"
msgid "Virtual Machine Name"
msgstr "Nombre de máquina virtual"
msgid ""
"The name used to identify the virtual machine. If omitted, a name will be "
"chosen based on the template used."
msgstr ""
"El nombre que se utiliza para identificar la máquina virtual. Si se omite, "
"se elegirá un nombre basándose en la plantilla utilizada."
msgid "Please create a template first."
msgstr "Cree una plantilla primero."
msgid "Create a Template"
msgstr "Crear una plantilla"
msgid "Please choose a template."
msgstr "Elija una plantilla."
msgid "This template has invalid parameters."
msgstr ""
msgid "This template has invalid parameters"
msgstr ""
msgid "OS"
msgstr "SO"
msgid "Version"
msgstr "Versión"
msgid "Current CPUs"
msgstr ""
msgid "Memory"
msgstr "Memoria"
msgid "Create"
msgstr "Crear"
msgid "Creating..."
msgstr "Creando..."
msgid "Cancel"
msgstr "Cancelar"
msgid "Clone a Guest"
msgstr ""
msgid ""
"When the target guest has SCSI or iSCSI volumes, they will be cloned on the "
"default storage pool. The same will happen when the target pool does not "
"have enough space to clone the volumes. Do you want to continue?"
msgstr ""
msgid "Number of times to clone"
msgstr ""
msgid "Continue"
msgstr ""
msgid "Edit Guest"
msgstr "Editar invitado"
msgid "General"
msgstr "General"
msgid "Storage"
msgstr "Almacenamiento"
msgid "Interface"
msgstr "Interfaz"
msgid "Permission"
msgstr ""
msgid "Pci"
msgstr ""
msgid "Snapshot"
msgstr ""
msgid "Processor"
msgstr "Procesador"
msgid "Name"
msgstr "Nombre"
msgid "Memory (MB)"
msgstr "Memoria (MB)"
msgid "More"
msgstr ""
msgid "Max Memory (MB)"
msgstr ""
msgid "Host does not support memory hotplug"
msgstr ""
msgid "Icon"
msgstr "Icono"
msgid "Console"
msgstr ""
msgid "Nothing selected"
msgstr ""
msgid "sclp"
msgstr ""
msgid "virtio"
msgstr ""
msgid ""
"Select which items for boot order and grad them when needed to order them. "
"At least one option must be selected."
msgstr ""
msgid "Add"
msgstr "Añadir"
msgid "Device"
msgstr "Dispositivo"
msgid "Path"
msgstr "Vía de acceso"
msgid "Actions"
msgstr "Acciones"
msgid "Network"
msgstr "Red"
msgid "Type"
msgstr "Tipo"
msgid "MAC Address"
msgstr "Dirección MAC"
msgid "IP Address"
msgstr ""
msgid "Network/Interface"
msgstr ""
msgid "Mode"
msgstr ""
msgid "Available system users and groups"
msgstr "Usuarios y grupos del sistema disponibles"
msgid "Users"
msgstr "Usuarios"
msgid "Groups"
msgstr "Grupos"
msgid "Selected system users and groups"
msgstr "Usuarios y grupos del sistema seleccionados"
msgid "User"
msgstr "Usuario"
msgid "All"
msgstr "Todo"
msgid "To Add"
msgstr "A añadir"
msgid "Added"
msgstr "Añadido"
msgid "Filter"
msgstr ""
msgid "Status"
msgstr ""
msgid "Product"
msgstr "Producto"
msgid "Vendor"
msgstr "Proveedor"
msgid "Loading"
msgstr ""
msgid "Created"
msgstr "Creado"
msgid "Current CPU Number"
msgstr ""
msgid ""
"Current CPU must be equal or lower than the Maximum CPU value. If a topology "
"is set, it must be also be a multiple of the 'threads' value."
msgstr ""
msgid "Max CPU"
msgstr ""
msgid ""
"Unable to edit maximum CPU or CPU topology when editing a running or paused "
"virtual machine."
msgstr ""
msgid ""
"If a topology is set, this value will be the product of sockets * times * "
"cores."
msgstr ""
msgid "Manually set CPU topology"
msgstr "Establezca manualmente la topología de CPU"
msgid "Sockets"
msgstr ""
msgid "Cores"
msgstr "Núcleos"
msgid "Threads"
msgstr "Hebras"
msgid "Save"
msgstr "Guardar"
msgid "Replace"
msgstr "Sustituir"
msgid "Detach"
msgstr "Desconectar"
msgid "Remove"
msgstr "Eliminar"
msgid "Edit"
msgstr "Editar"
msgid "LDAP User ID,e.g.foo@foo.com"
msgstr "ID de usuario LDAP, p.e. foo@foo.com"
msgid "Revert"
msgstr ""
msgid "Running"
msgstr ""
msgid "Disconnected"
msgstr ""
msgid "Starting"
msgstr ""
msgid "Crashed"
msgstr ""
msgid "Unknown"
msgstr ""
msgid "Paused"
msgstr ""
msgid "Suspended"
msgstr ""
msgid "Resetting"
msgstr ""
msgid "View Console"
msgstr ""
msgid "View Serial"
msgstr ""
msgid "Clone"
msgstr "Clonar"
msgid "Migrate"
msgstr ""
msgid "Reset"
msgstr "Restablecer"
msgid "Pause"
msgstr "Poner en pausa"
msgid "Resume"
msgstr "Reanudar"
msgid "Shut Down"
msgstr "Concluir"
msgid "Start"
msgstr "Iniciar"
msgid "Power Off"
msgstr "Apagar"
msgid "Delete"
msgstr "Suprimir"
msgid "No Data Available"
msgstr ""
msgid "Processors Utilization"
msgstr ""
msgid "Memory Utilization"
msgstr ""
msgid "Storage I/O"
msgstr ""
msgid "Network I/O"
msgstr "E/S de red"
msgid "Migrate a Guest"
msgstr ""
msgid ""
"Disclaimer: This process cannot be stopped after started, can take a long "
"time to complete and will turn off the VM on this Hypervisor when it is "
"successfully migrated to the remote destination."
msgstr ""
msgid "Remote Server"
msgstr ""
msgid "IP Address or Hostname"
msgstr ""
msgid ""
"The following fields are optional. Fill them if you want Kimchi to setup a "
"password-less ssh session between the localhost and the remote host. The "
"setup process will only be successful if the user has 'SUDO ALL' permission "
"in the remote machine."
msgstr ""
msgid "Username of the remote host"
msgstr ""
msgid "Password"
msgstr "Contraseña"
msgid "Password of the user in the remote host"
msgstr ""
msgid "Use RDMA transport"
msgstr ""
msgid ""
"Check this option only if RDMA is properly configured in both source and "
"destination hosts, otherwise migration will fail."
msgstr ""
msgid "Delete this VM when the migration is completed"
msgstr ""
msgid "Add a Storage Device to VM"
msgstr "Añadir un dispositivo de almacenamiento a VM"
msgid "Device Type"
msgstr "Tipo de dispositivo"
msgid ""
"The device type. Currently, \"cdrom\" and \"disk\" are supported. If the "
"guest is running, only \"disk\" is supported."
msgstr ""
msgid "Create a new disk"
msgstr ""
msgid "Select an existing disk"
msgstr ""
msgid "Source"
msgstr ""
msgid "Storage based on Libvirt pool or direct block device"
msgstr ""
msgid "Storage Pool"
msgstr "Agrupación de almacenamiento"
msgid "Storage pool to create the volume in"
msgstr ""
msgid "Disk Size (GB)"
msgstr ""
msgid "New disk size to be created"
msgstr ""
msgid "Format"
msgstr ""
msgid "Format of the new disk to be created"
msgstr ""
msgid "Directory Path"
msgstr ""
msgid "Provide a directory path"
msgstr ""
msgid "Storage pool in which the volume is located in"
msgstr ""
msgid "Storage Volume"
msgstr "Volumen de almacenamiento"
msgid "Storage volume to be attached"
msgstr "Volumen de almacenamiento que se va a adjuntar"
msgid "Disk Path"
msgstr ""
msgid "Provide a block device"
msgstr ""
msgid "File Path"
msgstr "Vía de acceso de archivo"
msgid "The ISO file path in the server for CDROM."
msgstr "La vía de acceso del archivo ISO en el servidor para el CDROM."
msgid "Attach"
msgstr "Conectar"
msgid "Host"
msgstr "Host"
msgid "Guests"
msgstr "Invitados"
msgid "Templates"
msgstr "Plantillas"
msgid "This is not a valid Linux path"
msgstr "No es una vía de acceso de Linux válida"
msgid "Unable to read file."
msgstr "No se puede leer el archivo. "
msgid "Error while uploading file."
msgstr "Error al actualizar el archivo. "
msgid "Delete Confirmation"
msgstr "Confirmación de supresión"
msgid "OK"
msgstr "Aceptar"
msgid "Confirm"
msgstr "Confirmar"
msgid "Warning"
msgstr "Aviso"
msgid "Cloning..."
msgstr "Clonación..."
msgid "Saving..."
msgstr ""
msgid "Migrating..."
msgstr ""
msgid "No ISO found"
msgstr "No se ha encontrado ningún ISO"
msgid "Add Template"
msgstr "Añadir plantilla"
msgid "This may take a long time. Do you want to continue?"
msgstr "Esta operación puede necesitar mucho tiempo. ¿Desea continuar?"
msgid ""
"This will permanently delete the %1 template. Would you like to continue?"
msgstr ""
msgid "View Table"
msgstr ""
msgid "View Gallery"
msgstr ""
msgid "Not Available"
msgstr ""
msgid "Please check the invalid Storage Pools"
msgstr ""
msgid "Please check the invalid Storage Pools or Paths"
msgstr ""
msgid "macvtap"
msgstr ""
msgid "ovs"
msgstr ""
msgid "network"
msgstr ""
msgid ""
"This will delete the %1 virtual machine and its virtual disks. This "
"operation cannot be undone. Would you like to continue?"
msgstr ""
msgid "Power off Confirmation"
msgstr "Confirmación de apagado"
msgid ""
"This action may produce undesirable results, for example unflushed disk "
"cache in the %1 guest. Would you like to continue?"
msgstr ""
msgid "Reset Confirmation"
msgstr "Confirmación de restablecimiento"
msgid ""
"There is a risk of data loss caused by reset without the %1 guest OS "
"shutdown. Would you like to continue?"
msgstr ""
msgid "Shut Down Confirmation"
msgstr "Confirmación de conclusión"
msgid ""
"Note the %1 guest OS may ignore this request. Would you like to continue?"
msgstr ""
msgid "Virtual Machine delete Confirmation"
msgstr "Confirmación de supresión de la máquina virtual "
msgid ""
"The %1 virtual machine is not persistent. Power Off will delete it. Continue?"
msgstr ""
msgid "Add Guest"
msgstr ""
msgid "Input is not a number"
msgstr ""
msgid "Memory value cannot be higher than Max Memory value"
msgstr ""
msgid ""
"For better performance it is recommended a threads per core value not "
"greater than %1."
msgstr ""
msgid ""
"This CDROM will be detached permanently and you can re-attach it. Continue "
"to detach it?"
msgstr ""
"Este CDROM se desconectará de forma permanente pero puede volver a "
"conectarlo. ¿Desea continuar para desconectarlo?"
msgid "Attaching..."
msgstr "Conectando..."
msgid ""
"This disk will be detached permanently and you can re-attach it. Continue to "
"detach it?"
msgstr ""
"Este disco se desconectará de forma permanente y podrá volver a conectarlo. "
"¿Desea continuardesconectándolo?"
msgid "interface:"
msgstr "interfaz: "
msgid "address:"
msgstr "dirección:"
msgid "link_type:"
msgstr "link_type:"
msgid "block:"
msgstr "bloque:"
msgid "drive_type:"
msgstr "drive_type:"
msgid "model:"
msgstr "modelo:"
msgid "Affected devices:"
msgstr "Dispositivos afectados:"
msgid "Less"
msgstr ""
msgid "Successfully attached device to VM"
msgstr ""
msgid "Successfully detached device from VM"
msgstr ""
msgid "Following devices will be affected, confirm?"
msgstr ""
msgid "Bridge"
msgstr ""
msgid "Vepa"
msgstr ""
msgid "None"
msgstr ""
msgid "unavailable"
msgstr "no disponible"
msgid ""
"This action will interrupt network connectivity for any virtual machine that "
"depend on the %1 network."
msgstr ""
msgid "Add Network"
msgstr ""
msgid ""
"The %1 network is not persistent. Instead of stop, this action will "
"permanently delete it. Would you like to continue?"
msgstr ""
msgid ""
"The bridged VLAN tag may not work well with NetworkManager enabled. You "
"should consider disabling it."
msgstr ""
"Es posible que el código VLAN ponteado no funcione bien si NetworkManager "
"está habilitado. Debería considerar la posibilidad de inhabilitarlo. "
msgid ""
"This will permanently delete the %1 storage pool. Would you like to continue?"
msgstr ""
msgid "This storage pool is empty."
msgstr "Esta agrupación de almacenamiento está vacía."
msgid ""
"It will format your disk and you will loose any data in there, are you sure "
"to continue? "
msgstr ""
"Dará formato al disco y se perderán los datos que tenga en él. ¿Está seguro "
"de que desea continuar? "
msgid "SCSI Fibre Channel"
msgstr "Canal de fibra de SCSI"
msgid "No SCSI adapters found."
msgstr "No se han encontrado adaptadores SCSI."
msgid "Loading iSCSI targets..."
msgstr "Se están cargando los destinos iSCSI..."
msgid "No iSCSI found. Please input one."
msgstr "No se ha encontrado el iSCSI. Indique uno. "
msgid "Failed to load iSCSI targets."
msgstr "No se han podido cargar los destinos iSCSI. "
msgid "Would you like to continue?"
msgstr ""
msgid "This will permanently delete the following storage volumes: %1"
msgstr ""
msgid "No available partitions found."
msgstr "No se han encontrado particiones disponibles."
msgid ""
"The %1 storage pool is not persistent. Instead of deactivate, this action "
"will permanently delete it. Would you like to continue?"
msgstr ""
msgid "Unable to retrieve partitions information."
msgstr "No se puede recuperar la información de particiones. "
msgid "In progress..."
msgstr "En curso..."
msgid "Failed!"
msgstr "Error"
msgid "No LVM found in the system."
msgstr ""
msgid "This will permanently wipe the following storage volumes: %1"
msgstr ""
msgid "Wipe Confirmation"
msgstr ""
msgid "Select one or more partitions to be added to the logical pool %1:"
msgstr ""
msgid "Add Storage"
msgstr ""
msgid "DIR"
msgstr ""
msgid "NFS"
msgstr ""
msgid "iSCSI"
msgstr ""
msgid "LOGICAL"
msgstr ""
msgid "device"
msgstr ""
msgid "path"
msgstr ""
msgid "size (GiB)"
msgstr ""
msgid "free size (GiB)"
msgstr ""
msgid "Invalid NFS mount path."
msgstr "Vía de acceso de montaje de NFS no válida."
msgid "No logical device selected."
msgstr "No se ha seleccionado ningún dispositivo lógico."
msgid "This is not a valid Server Name or IP. Please, modify it."
msgstr "No es un nombre de servidor válido o IP válida. Modifique el valor. "
msgid "CDROM path needs to be a valid local/remote path and cannot be blank."
msgstr ""
"La vía de acceso de CDROM ha de ser una vía de acceso local/remota válida y "
"no puede dejarse en blanco. "
msgid "Disk pool or volume cannot be blank."
msgstr "El volumen o la agrupación de discos no puede estar en blanco."
msgid ""
"Disk size or Format or Directory path cannot be blank and Directory path "
"needs to be a valid local/remote path."
msgstr ""
msgid "Disk path needs to be a valid local/remote path and cannot be blank."
msgstr ""
msgid "Storage pool or Disk size or Format cannot be blank."
msgstr ""
msgid "cdrom"
msgstr ""
msgid "disk"
msgstr ""
msgid "Pool"
msgstr ""
msgid "qcow"
msgstr ""
msgid "qcow2"
msgstr ""
msgid "qed"
msgstr ""
msgid "raw"
msgstr ""
msgid "vmdk"
msgstr ""
msgid "vpc"
msgstr ""
msgid "Create a network"
msgstr "Crear una red"
msgid "Network Name"
msgstr "Nombre de red"
msgid "Name should not contain '/' and '\"'."
msgstr "El nombre no debe contener '/' y '\"'."
msgid "Network Type"
msgstr "Tipo de red"
msgid "Isolated: no external network connection"
msgstr "Aislado: no hay conexión de red externa"
msgid "NAT: outbound physical network connection only"
msgstr "NAT: conexión de red física saliente solamente"
msgid "Macvtap: Virtual machines are connected to physical network directly"
msgstr ""
msgid ""
"Passthrough: Virtual machines are connected using a macvtap connection in "
"passthrough mode."
msgstr ""
msgid ""
"VEPA: special mode where virtual machines are connected to a VEPA-enabled "
"switch"
msgstr ""
msgid "Bridged: Virtual machines are connected through a network bridge"
msgstr ""
msgid "Destination"
msgstr "Destino"
msgid "Select an Interface"
msgstr ""
msgid "Enable VLAN"
msgstr "Habilitar VLAN"
msgid "VLAN ID"
msgstr "ID de VLAN"
msgid "Edit Network"
msgstr ""
msgid "Address Space"
msgstr ""
msgid "Define a New Storage Pool"
msgstr "Definir una agrupación de almacenamiento nueva"
msgid "Storage Pool Name"
msgstr "Nombre de agrupación de almacenamiento"
msgid ""
"The name used to identify the storage pools, and it should not be empty."
msgstr ""
"El nombre que se utiliza para identificar las agrupaciones de almacenamiento "
"y no debe estar vacío."
msgid "Storage Pool Type"
msgstr "Tipo de agrupación de almacenamiento"
msgid "Storage Path"
msgstr "Vía de acceso de almacenamiento"
msgid ""
"The path of the Storage Pool. Each Storage Pool must have a unique path."
msgstr ""
"La vía de acceso de la agrupación de almacenamiento. Cada agrupación de "
"almacenamiento debe tener una vía de acceso exclusiva."
msgid ""
"Kimchi will try to create the directory when it does not already exist in "
"your system."
msgstr "Kimchi intentará crear el directorio cuando no existe en el sistema."
msgid "NFS Server IP"
msgstr "IP de Servidor NFS"
msgid "NFS server IP or hostname. It can be input or chosen from history."
msgstr ""
"IP o nombre de host de servidor NFS. Puede especificarse o elegirse del "
"historial."
msgid "NFS Path"
msgstr "Vía de acceso NFS"
msgid "The NFS exported path on NFS server."
msgstr "La vía de acceso exportada de NFS en el servidor NFS."
msgid "Create from existing LVM"
msgstr ""
msgid "Create from raw disk"
msgstr ""
msgid "Looking for existing lvms ..."
msgstr ""
msgid "Looking for available partitions ..."
msgstr "Buscando particiones disponibles..."
msgid "iSCSI Server"
msgstr "Servidor iSCSI"
msgid "Server"
msgstr "Servidor"
msgid "Port"
msgstr "Puerto"
msgid "iSCSI server IP or hostname. It should not be empty."
msgstr "IP o nombre de host de servidor iSCSI. No debe estar vacío."
msgid "Target"
msgstr "Destino"
msgid "The iSCSI target on iSCSI server"
msgstr "El destino iSCSI en el servidor iSCSI"
msgid "Add iSCSI Authentication"
msgstr "Añadir Autenticación iSCSI"
msgid "User Name"
msgstr "Nombre de usuario"
msgid "SCSI Adapter"
msgstr "Adaptador SCSI"
msgid "Please, wait..."
msgstr "Por favor, espere..."
msgid "Add a Volume to Storage Pool"
msgstr "Añadir un volumen a la agrupación de almacenamiento"
msgid "Fetch from remote URL"
msgstr "Captar de URL remoto"
msgid "Enter the remote URL here."
msgstr "Escriba el URL remoto aquí. "
msgid "Upload a file"
msgstr "Cargar un archivo"
msgid "Choose the file you want to upload."
msgstr "Elija el archivo que desee cargar. "
msgid "Resize Volume"
msgstr ""
msgid "Size"
msgstr ""
msgid "The total space which can be used to store data. The unit is megabytes."
msgstr ""
msgid "Ok"
msgstr ""
msgid "Template Name"
msgstr ""
msgid ""
"The name used to identify the template. If omitted, a name will be "
"automatically chosen."
msgstr ""
msgid ""
"When selecting more than one Image Template, a name will be automatically "
"chosen for each Image Template selected."
msgstr ""
msgid "Where is the source media for this template? "
msgstr ""
msgid "Image Template"
msgstr ""
msgid "Netboot Template"
msgstr ""
msgid "File Path:"
msgstr "Vía de acceso del archivo:"
msgid "Search ISOs"
msgstr "Buscar ISOs"
msgid "The following ISOs are available:"
msgstr "Las siguientes ISO están disponibles:"
msgid "QEMU does not have enough permission to work with this file"
msgstr ""
msgid "Search more ISOs"
msgstr "Buscar más ISO"
msgid "Loading..."
msgstr ""
msgid "Edit Template"
msgstr "Editar plantilla"
msgid "CDROM"
msgstr "CDROM"
msgid "Image File"
msgstr "Archivo de imagen"
msgid "Graphics"
msgstr "Gráficos"
msgid "Disk(GB)"
msgstr "Disco (GB)"
msgid "Disk Format"
msgstr "Formato de disco"
msgid "Add Interface"
msgstr ""
msgid "pool"
msgstr ""
msgid "bridge"
msgstr ""
msgid "vepa"
msgstr ""
msgid "State"
msgstr ""
msgid "Guest Name ID"
msgstr ""
msgid "OS Type"
msgstr ""
msgid "VNC"
msgstr ""
msgid "No guests found."
msgstr ""
msgid "Stop"
msgstr ""
msgid "Location"
msgstr ""
msgid "%Used"
msgstr ""
msgid "Allocated"
msgstr ""
msgid "Capacity"
msgstr ""
msgid "Disks"
msgstr ""
msgid "Extending logical pool"
msgstr ""
msgid "%"
msgstr ""
msgid "Deactivate"
msgstr ""
msgid "Activate"
msgstr ""
msgid "Extend"
msgstr ""
msgid "Undefine"
msgstr ""
msgid "Add Volume"
msgstr ""
msgid "Resize"
msgstr ""
msgid "Wipe"
msgstr ""
msgid "Filter:"
msgstr ""
msgid "Used By"
msgstr ""
msgid "Used"
msgstr ""
msgid "Progress"
msgstr ""
msgid "Used by the following VMs:"
msgstr ""
msgid "Allocation"
msgstr ""
msgid "Template Name (ID)"
msgstr ""
msgid "No templates found."
msgstr ""
msgid "M"
msgstr ""
================================================
FILE: po/fr_FR.po
================================================
# Frensh translations for kimchi package.
# Copyright IBM Corp, 2014-2017
# Adam Litke , 2013.
#
msgid ""
msgstr ""
"Project-Id-Version: kimchi 0.1\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2017-06-30 10:27-0300\n"
"PO-Revision-Date: 2013-07-11 17:32-0400\n"
"Last-Translator: Crístian Viana \n"
"Language-Team: English\n"
"Language: fr_FR\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: pygettext.py 1.5\n"
"Plural-Forms: nplurals=2; plural=n>1;\n"
#, python-format
msgid "Unknown parameter %(value)s"
msgstr "Paramètre inconnu %(value)s"
#, python-format
msgid "User %(user_id)s not found with given LDAP settings."
msgstr ""
"L'utilisateur %(user_id)s est introuvable avec les paramètres LDAP donnés."
#, python-format
msgid "Partition %(name)s does not exist in the host"
msgstr "La partition %(name)s n'existe pas sur l'hôte"
#, python-format
msgid "Error while accessing dev mapper device, %(err)s"
msgstr ""
msgid "Block device not found."
msgstr ""
#, python-format
msgid "Block device %(device)s not found."
msgstr ""
#, python-format
msgid "Unable to retrieve LVM information. Details: %(err)s"
msgstr ""
msgid "Unknown \"_cap\" specified"
msgstr "\"_cap\" inconnu spécifié"
msgid "\"_passthrough\" should be \"true\" or \"false\""
msgstr "\"_passthrough\" doit avoir la valeur \"true\" ou \"false\""
msgid "\"_passthrough_affected_by\" should be a device name string"
msgstr "\"_passthrough_affected_by\" doit être une chaîne de nom d'unité"
msgid "\"_available_only\" should be \"true\" or \"false\""
msgstr "\"_available_only\" doit avoir la valeur \"true\" ou \"false\""
#, python-format
msgid "Unable to find distro file: %(filename)s"
msgstr "Fichier de distribution introuvable : %(filename)s"
#, python-format
msgid ""
"Unable to parse distro file: %(filename)s. Make sure, it is a JSON file."
msgstr ""
"Impossible d'analyser le fichier de distribution : %(filename)s. Vérifiez "
"qu'il s'agit d'un fichier JSON."
#, python-format
msgid "Unable to login to iSCSI host target %(portal)s. Details: %(err)s"
msgstr ""
"Impossible de se connecter à la cible hôte iSCSI %(portal)s. Détails : "
"%(err)s"
#, python-format
msgid "Unable to login to iSCSI host %(host)s target %(target)s"
msgstr "Impossible de se connecter à la cible hôte %(host)s iSCSI %(target)s"
#, python-format
msgid "Unable to find ISO file %(filename)s"
msgstr "Fichier ISO introuvable : %(filename)s"
#, python-format
msgid "The ISO file %(filename)s is not bootable"
msgstr "Le fichier ISO %(filename)s n'est pas amorçable"
#, python-format
msgid "The ISO file %(filename)s does not have a valid El Torito boot record"
msgstr ""
"Le fichier ISO %(filename)s ne possède pas d'enregistrement d'amorçage El "
"Torito valide"
#, python-format
msgid "Invalid El Torito validation entry in ISO %(filename)s"
msgstr ""
"Entrée de validation El Torito non valide dans le fichier ISO %(filename)s"
#, python-format
msgid "Invalid El Torito boot indicator in ISO %(filename)s"
msgstr ""
"Indicateur d'amorçage El Torito non valide dans le fichier ISO %(filename)s"
#, python-format
msgid "Unexpected volume type for primary volume in ISO %(filename)s"
msgstr ""
"Type de volume inattendu pour le volume principal dans le fichier ISO "
"%(filename)s"
#, python-format
msgid "Bad format while reading volume descriptor in ISO %(filename)s"
msgstr ""
"Format incorrect lors de la lecture du descripteur de volume dans le fichier "
"ISO %(filename)s"
#, python-format
msgid ""
"The hypervisor doesn't have permission to use this ISO %(filename)s. "
"Consider moving it under /var/lib/libvirt, or set the search permission to "
"file access control lists for '%(user)s' user if possible, or add the "
"'%(user)s' to the ISO path group, or (not recommended) 'chmod -R o+x "
"'path_to_iso'.Details: %(err)s"
msgstr ""
"L'hyperviseur ne dispose pas des droits pour utiliser ce fichier ISO "
"%(filename)s. placez-le dans /var/lib/libvirt, ou définissez le droit de "
"recherche sur les listes de contrôle d'accès d'accès aux fichiers pour "
"l'utilisateur '%(user)s', si possible, ou ajoutez '%(user)s' au groupe de "
"chemins d'accès ISO ou (non recommandé) 'chmod -R o+x 'path_to_iso'."
"Détails : %(err)s"
#, python-format
msgid "Unable to access remote ISO. Details: %(err)s"
msgstr ""
#, python-format
msgid "Error probing image OS information: %(err)s"
msgstr ""
#, python-format
msgid "Unable to read image file %(filename)s"
msgstr "Impossible de lire le fichier image %(filename)s"
#, python-format
msgid ""
"Image file must be an existing file on system. %(filename)s is not a valid "
"input."
msgstr ""
"Le fichier image doit être un fichier existant sur le système. %(filename)s "
"n'est pas une entrée valide."
#, python-format
msgid "Virtual machine %(name)s already exists"
msgstr "La machine virtuelle %(name)s existe déjà"
#, python-format
msgid "Virtual machine %(name)s does not exist"
msgstr "La machine virtuelle nommée %(name)s n'existe pas"
#, python-format
msgid "Unable to retrieve screenshot for stopped virtual machine %(name)s"
msgstr ""
"Impossible d'extraire la capture d'écran pour la machine virtuelle arrêtée "
"%(name)s"
msgid "Remote ISO image is not supported by this server."
msgstr "L'image ISO distante n'est pas prise en charge par ce serveur."
#, python-format
msgid "Screenshot is not supported on virtual machine %(name)s"
msgstr ""
"La capture d'écran n'est pas prise en charge sur la machine virtuelle "
"%(name)s"
#, python-format
msgid "Unable to create virtual machine %(name)s. Details: %(err)s"
msgstr "Impossible de créer la machine virtuelle %(name)s. Détails : %(err)s"
#, python-format
msgid "Unable to update virtual machine %(name)s. Details: %(err)s"
msgstr ""
"Impossible de mettre à jour la machine virtuelle %(name)s. Détails : %(err)s"
#, python-format
msgid "Unable to retrieve virtual machine %(name)s. Details: %(err)s"
msgstr ""
"Impossible de récupérer la machine virtuelle %(name)s. Détails : %(err)s"
#, python-format
msgid "Unable to connect to powered off virtual machine %(name)s."
msgstr ""
"Impossible de se connecter à la machine virtuelle hors tension %(name)s."
msgid "Virtual machine name must be a string without slashes (/)"
msgstr ""
"Le nom de la machine virtuelle doit être une chaîne sans barre oblique (/)"
#, python-format
msgid "Invalid template URI %(value)s specified for virtual machine"
msgstr "URI du modèle non valide %(value)s indiqué pour la machine virtuelle"
#, python-format
msgid "Invalid storage pool URI %(value)s specified for virtual machine"
msgstr ""
"URI du pool de stockage non valide %(value)s indiqué pour la machine "
"virtuelle"
msgid "Supported virtual machine graphics are Spice or VNC"
msgstr "Graphiques de machine virtuelle pris en charge : Spice ou VNC"
msgid "Graphics address to listen on must be IPv4 or IPv6"
msgstr "L'adresse des graphiques pour l'écoute doit être IPv4 ou IPv6"
msgid "Specify a template to create a virtual machine from"
msgstr "Indiquez un modèle pour créer une machine virtuelle depuis"
#, python-format
msgid "Unable to start virtual machine %(name)s. Details: %(err)s"
msgstr ""
"Impossible de démarrer la machine virtuelle %(name)s. Détails : %(err)s"
#, python-format
msgid "Unable to power off virtual machine %(name)s. Details: %(err)s"
msgstr ""
"Impossible de mettre hors tension la machine virtuelle %(name)s. Détails : "
"%(err)s"
#, python-format
msgid "Unable to delete virtual machine %(name)s. Details: %(err)s"
msgstr ""
"Impossible de supprimer la machine virtuelle %(name)s. Détails : %(err)s"
#, python-format
msgid "Unable to reset virtual machine %(name)s. Details: %(err)s"
msgstr ""
"Impossible de réinitialiser la machine virtuelle %(name)s. Détails : %(err)s"
msgid "User name list must be an array"
msgstr "La liste de noms d'utilisateur doit être un tableau"
msgid "User name must be a string"
msgstr "Le nom d'utilisateur doit être une chaîne"
msgid "Group name list must be an array"
msgstr "La liste de noms de groupe doit être un tableau"
msgid "Group name must be a string"
msgstr "Le nom de groupe doit être une chaîne"
#, python-format
msgid "User(s) '%(users)s' do not exist"
msgstr "Le ou les utilisateurs '%(users)s' n'existent pas"
#, python-format
msgid "Group(s) '%(groups)s' do not exist"
msgstr "Le ou les groupes '%(groups)s' n'existent pas"
#, python-format
msgid "Unable to shutdown virtual machine %(name)s. Details: %(err)s"
msgstr "Impossible d'arrêter la machine virtuelle %(name)s. Détails : %(err)s"
msgid "The guest console password must be a string."
msgstr "Le mot de passe de la console invité doit être une chaîne."
msgid "The life time for the guest console password must be a number."
msgstr ""
"La durée de vie du mot de passe de console invité doit être une valeur "
"numérique."
#, python-format
msgid "Virtual machine '%(name)s' must be stopped before cloning it."
msgstr "La machine virtuelle '%(name)s' doit être arrêtée avant d'être clonée."
#, python-format
msgid "Insufficient disk space to clone virtual machine '%(name)s'"
msgstr "Espace disque insuffisant pour cloner la machine virtuelle '%(name)s'"
#, python-format
msgid "Unable to clone VM '%(name)s'. Details: %(err)s"
msgstr ""
"Impossible de cloner la machine virtuelle '%(name)s'. Détails : %(err)s"
#, python-format
msgid "Invalid operation for non-persistent virtual machine %(name)s"
msgstr "Opération non valide pour la machine virtuelle non permanente %(name)s"
#, python-format
msgid "Cannot suspend VM '%(name)s' because it is not running."
msgstr ""
"Impossible d'interrompre la machine virtuelle '%(name)s' car elle n'est pas "
"en cours d'exécution."
#, python-format
msgid "Unable to suspend VM '%(name)s'. Details: %(err)s"
msgstr ""
"Impossible d'interrompre la machine virtuelle '%(name)s'. Détails : %(err)s"
#, python-format
msgid "Cannot resume VM '%(name)s' because it is not paused."
msgstr ""
"Impossible de reprendre la machine virtuelle '%(name)s' car elle n'est pas "
"interrompue."
#, python-format
msgid "Unable to resume VM '%(name)s'. Details: %(err)s"
msgstr ""
"Impossible de reprendre la machine virtuelle '%(name)s'. Détails : %(err)s"
#, python-format
msgid ""
"Memory assigned is higher then the maximum allowed in the host: "
"%(maxmem)sMib."
msgstr ""
#, python-format
msgid ""
"Guest '%(name)s' does not support live memory update. Please, with the guest "
"offline, set Maximum Memory with a value greater then Memory to enable this "
"feature."
msgstr ""
msgid "Only increase memory is allowed in active VMs"
msgstr ""
"Seule une augmentation de la mémoire est autorisée sur les machines "
"virtuelles actives"
msgid "There are not enough free slots to add a new memory device."
msgstr ""
msgid ""
"Host's libvirt or qemu version does not support memory devices and memory "
"hotplug. Libvirt must be >= 1.2.14 and QEMU must be >= 2.1."
msgstr ""
#, python-format
msgid "Error attaching memory device. Details: %(error)s"
msgstr "Erreur d'attachement de l'unité de mémoire. Détails : %(error)s"
#, python-format
msgid "Cannot start %(name)s. Virtual machine is already running."
msgstr ""
"Impossible de démarrer %(name)s. La machine virtuelle est déjà démarrée. "
#, python-format
msgid "Cannot power off %(name)s. Virtual machine is shut off."
msgstr ""
"Impossible de mettre %(name)s hors tension. La machine virtuelle est "
"arrêtée. "
#, python-format
msgid "Cannot shutdown %(name)s. Virtual machine is shut off."
msgstr "Impossible d'arrêter %(name)s. La machine virtuelle est arrêtée. "
#, python-format
msgid "Cannot reset %(name)s. Virtual machine is already shut off."
msgstr ""
"Impossible de réinitialiser %(name)s. La machine virtuelle est déjà arrêtée. "
msgid "Boot order must be a list. Devices accepted: hd, cdrom, fd or network."
msgstr ""
msgid "Bootmenu must be boolean. Values accepted: true of false."
msgstr ""
msgid "Graphic type not valid. Values accepted: vnc or spice."
msgstr ""
#, python-format
msgid "Migrate to localhost %(host)s is not allowed."
msgstr ""
#, python-format
msgid ""
"To migrate a virtual machine to the remote host %(host)s the user %(user)s "
"must have password-less login to the remote host."
msgstr ""
#, python-format
msgid "Can not migrate virtual machine %(name)s when its in %(state)s state."
msgstr ""
#, python-format
msgid "Failed to migrate virtual machine %(name)s due error: %(err)s"
msgstr ""
msgid "User name of the remote server must be a string."
msgstr ""
msgid "Destination host of the migration must be a string."
msgstr ""
#, python-format
msgid "Unable to create file %(path)s at %(host)s using user %(user)s."
msgstr ""
#, python-format
msgid "Unable to read disk size of %(path)s, error: %(error)s"
msgstr ""
#, python-format
msgid ""
"Unable to create disk image %(path)s at %(host)s using user %(user)s. Error: "
"%(error)s"
msgstr ""
#, python-format
msgid ""
"Unable to migrate virtual machine to remote host %(host)s with arch "
"%(destarch)s using localhost with arch %(srcarch)s."
msgstr ""
#, python-format
msgid ""
"Unable to migrate virtual machine to remote host %(host)s with hypervisor "
"%(desthyp)s because localhost uses hypervisor %(srchyp)s."
msgstr ""
#, python-format
msgid ""
"Unable to determine remote host hypervisor and architecture. Error: %(error)s"
msgstr ""
#, python-format
msgid ""
"Unable to migrate virtual machine: subcores per core setting from "
"localhostand remote host %(host)s differs."
msgstr ""
#, python-format
msgid ""
"Unable to setup password-less login at remote host %(host)s using user "
"%(user)s. Error: %(error)s"
msgstr ""
msgid "Password field must be a string."
msgstr ""
msgid "Error creating local host ssh rsa key of user 'root'."
msgstr ""
#, python-format
msgid "%(param)s value (%(mem)sMiB) must be aligned to %(alignment)sMiB."
msgstr ""
#, python-format
msgid ""
"Unable to update the following parameters while the VM is offline: %(params)s"
msgstr ""
#, python-format
msgid ""
"Unable to update the following parameters while the VM is online: %(params)s"
msgstr ""
#, python-format
msgid ""
"VM %(name)s must have serial and console defined to open a web serial console"
msgstr ""
#, python-format
msgid "Impossible to get the serial console of %(name)s"
msgstr ""
#, python-format
msgid ""
"Memory or Maximum Memory value is higher than amount supported by the host: "
"%(memHost)sMiB."
msgstr ""
#, python-format
msgid ""
"Memory or Maximum Memory value is higher than maximum amount recommended: "
"%(value)sTiB"
msgstr ""
msgid "Cannot update Maximum Memory when guest is running."
msgstr ""
#, python-format
msgid "Impossible to create %(dir)s directory."
msgstr ""
#, python-format
msgid ""
"Either the guest %(name)s did not start to listen to the serial or it is not "
"configured to use the serial console."
msgstr ""
#, python-format
msgid ""
"Unable to retrieve Virt Viewer file for stopped virtual machine %(name)s"
msgstr ""
#, python-format
msgid ""
"Error occured while retrieving the Virt Viewer file for virtual machine "
"%(name)s : %(err)s"
msgstr ""
msgid "Virtual machine title must be a string"
msgstr ""
msgid "Virtual machine description must be a string"
msgstr ""
msgid "console parameter is only supported for s390x/s390 architecture."
msgstr ""
msgid "invalid console type, supported types are sclp/virtio."
msgstr ""
#, python-format
msgid ""
"Unable to setup password-less login at remote host %(host)s using user "
"%(user)s: remote directory %(sshdir)s does not exist."
msgstr ""
#, python-format
msgid ""
"Unable to create a password-less libvirt connection to the remote libvirt "
"daemon at host %(host)s with the user %(user)s. Please verify the remote "
"server libvirt configuration. More information: http://libvirt.org/auth."
"html ."
msgstr ""
msgid "'enable_rdma' must be of type boolean (true or false)."
msgstr ""
#, python-format
msgid ""
"VM %(vmid)s does not contain directly assigned host device %(dev_name)s."
msgstr ""
"La machine virtuelle VM %(vmid)s ne contient pas l'unité hôte affectée "
"directement %(dev_name)s."
#, python-format
msgid "The host device %(dev_name)s is not allowed to directly assign to VM."
msgstr ""
"L'unité hôte %(dev_name)s n'est pas autorisée à être affectée directement à "
"la machine virtuelle."
msgid ""
"No IOMMU groups found. Host PCI pass through needs IOMMU group to function "
"correctly. Please enable Intel VT-d or AMD IOMMU in your BIOS, then verify "
"the Kernel is compiled with IOMMU support. For Intel CPU, add "
"'intel_iommu=on' to GRUB_CMDLINE_LINUX parameter in /etc/default/grub file. "
"For AMD CPU, add 'iommu=pt iommu=1'."
msgstr ""
msgid "\"name\" should be a device name string"
msgstr "\"name\" doit être une chaîne de nom d'unité"
#, python-format
msgid ""
"The device %(name)s is probably in use by the host. Unable to attach it to "
"the guest."
msgstr ""
"L'unité %(name)s est probablement utilisée par l'hôte. Impossible de "
"l'attacher à l'hôte."
#, python-format
msgid "Hot-(un)plug of device %(name)s is not supported."
msgstr ""
#, python-format
msgid "Failed to attach %(device)s to %(vm)s"
msgstr ""
#, python-format
msgid "VM %(vmid)s does not have a USB controller to accept PCI hotplug."
msgstr ""
#, python-format
msgid "Interface %(iface)s does not exist in virtual machine %(name)s"
msgstr "L'interface %(iface)s n'existe pas sur la machine virtuelle %(name)s"
#, python-format
msgid ""
"Network %(network)s specified for virtual machine %(name)s does not exist"
msgstr ""
"Le réseau %(network)s indiqué pour la machine virtuelle %(name)s n'existe pas"
msgid ""
"Supported virtual machine interfaces type are network, ovs and macvtap.Type "
"ovs and macvtap are only supported for s390x/s390 architecture."
msgstr ""
msgid "Network name for virtual machine interface must be a string"
msgstr ""
"Le nom de réseau pour l'interface de la machine virtuelle doit être une "
"chaîne"
msgid "Invalid network model card specified for virtual machine interface"
msgstr ""
"La carte de modèle réseau spécifiée pour l'interface de la machine virtuelle "
"n'est pas valide"
msgid "Specify type and network to add a new virtual machine interface"
msgstr ""
"Spécifiez un type et un réseau à ajouter à une nouvelle interface de machine "
"virtuelle"
msgid "MAC Address must respect this format FF:FF:FF:FF:FF:FF"
msgstr "L'adresse MAC doit être conforme au format FF:FF:FF:FF:FF:FF"
#, python-format
msgid "MAC Address %(mac)s already exists in virtual machine %(name)s"
msgstr "L'adresse MAC %(mac)s existe déjà sur la machine virtuelle %(name)s"
msgid "Invalid MAC Address"
msgstr "Adresse MAC non valide"
msgid "Cannot change MAC address of a running virtual machine"
msgstr ""
"Impossible de modifier l'adresse MAC d'une machine virtuelle en cours "
"d'exécution"
msgid "Type macvtap and ovs are only supported on s390x/s390 architecture."
msgstr ""
msgid "Source attribute is only supported on s390x/s390 architecture."
msgstr ""
msgid "If source is provided, only type supported are macvtap and ovs."
msgstr ""
msgid "For type macvtap and ovs, source has to be provided"
msgstr ""
msgid "Source name for virtual machine interface must be string"
msgstr ""
msgid "Invalid source mode. Valid options are: bridge or vepa."
msgstr ""
#, python-format
msgid "Template %(name)s already exists"
msgstr "Le modèle %(name)s existe déjà"
#, python-format
msgid "Source media %(path)s not found"
msgstr ""
#, python-format
msgid ""
"Network '%(network)s' specified for template %(template)s does not exist"
msgstr ""
"Le réseau '%(network)s' indiqué pour le modèle %(template)s n'existe pas"
#, python-format
msgid ""
"Storage pool %(pool)s specified for template %(template)s does not exist"
msgstr ""
"Le pool de stockage '%(pool)s' indiqué pour le modèle %(template)s n'existe "
"pas"
#, python-format
msgid "Invalid parameter '%(param)s' specified for CDROM."
msgstr "Paramètre non valide '%(param)s' spécifié pour le CD-ROM."
#, python-format
msgid "Network %(network)s specified for template %(template)s is not active"
msgstr ""
"Le réseau '%(network)s' indiqué pour le modèle %(template)s n'est pas actif"
msgid "Template name must be a string"
msgstr "Le nom du modèle doit être une chaîne"
msgid "Template icon must be a path to the image"
msgstr "L'icône de modèle doit être un chemin d'accès à l'image"
msgid "Template distribution must be a string"
msgstr "La distribution du modèle doit être une chaîne"
msgid "Template distribution version must be a string"
msgstr "La version de distribution du modèle doit être une chaîne"
msgid "The number of CPUs must be an integer greater than 0"
msgstr "Le nombre d'UC doit être un entier supérieur à 0"
msgid ""
"Amount of memory and maximum memory (MB) must be an integer greater than 512"
msgstr ""
msgid "Template CDROM must be a local or remote ISO file"
msgstr "Le CD-ROM modèle doit être un fichier ISO local ou distant"
#, python-format
msgid "Invalid storage pool URI %(value)s specified for template"
msgstr "URI du pool de stockage non valide %(value)s indiqué pour le modèle"
msgid ""
"Specify a path to source media (ISO, disk or remote ISO) to create a template"
msgstr ""
msgid "All networks for the template must be specified in a list."
msgstr "Tous les réseaux du modèle doivent être spécifiés dans une liste."
msgid "Specify a volume to a template when storage pool is iSCSI or SCSI"
msgstr ""
"Spécifiez un volume sur un modèle lorsque le pool de stockage est iSCSI ou "
"SCSI"
#, python-format
msgid "The volume %(volume)s is not in storage pool %(pool)s"
msgstr "Le volume %(volume)s n'est pas dans le pool de stockage %(pool)s"
#, python-format
msgid "Unable to create template due error: %(err)s"
msgstr "Impossible de créer le modèle en raison de l'erreur suivante : %(err)s"
#, python-format
msgid "Unable to delete template due error: %(err)s"
msgstr ""
"Impossible de supprimer le modèle en raison de l'erreur suivante : %(err)s"
msgid "Disk size must be an integer greater than 1GB."
msgstr "La taille du disque doit être un entier supérieur à 1 Go."
#, python-format
msgid "Cannot identify base image %(path)s format"
msgstr "Impossible d'identifier le format %(path)s de l'image de base"
msgid ""
"When specifying CPU topology, each element must be an integer greater than "
"zero."
msgstr ""
"Lors de la spécification de la topologie d'UC, chaque élément doit être un "
"entier supérieur à zéro."
msgid ""
"Invalid disk image format. Valid formats: qcow, qcow2, qed, raw, vmdk, vpc."
msgstr ""
msgid ""
"When setting template disks, following parameters are required: 'index', "
"'pool name', 'format', 'size' or 'volume' (for scsi/iscsi pools)"
msgstr ""
msgid "Disk format must be 'raw', for logical, iscsi, and scsi pools."
msgstr ""
msgid ""
"Memory expects an object with one or both parameters: 'current' and "
"'maxmemory'"
msgstr ""
#, python-format
msgid ""
"Memory value (%(mem)sMiB) must be equal or lesser than maximum memory value "
"(%(maxmem)sMiB)"
msgstr ""
#, python-format
msgid "Unable to update template due error: %(err)s"
msgstr ""
msgid "Parameter 'disks' requires at least one disk object"
msgstr ""
msgid ""
"Invalid interface type. Type should be 'macvtap' for host network interface "
"(Ethernet, Bond, VLAN) to be connected as direct MacVTap or 'ovs' for "
"openvswitch host network interface to be connected as virtual switch to a VM."
msgstr ""
msgid "Interface name should be string."
msgstr ""
msgid "Invalid interface mode. Valid options are: bridge or vepa."
msgstr ""
msgid ""
"Interfaces should be list of interfaces. Each interface should have name, "
"type and mode(optional, only applicable for interfcae type 'macvtap'."
msgstr ""
msgid ""
"Interface expects an object with parameters: 'name', 'type' and 'mode'. Name "
"should be name of host network interface (Ethernet, Bond, VLAN) for type "
"'macvtap' or the name of host openvswitch bridge interface for type 'ovs'. "
"Mode (optional) is only applicable for interface type 'macvtap' to indicates "
"whether packets will be delivered directly to target device (bridge) or to "
"the external bridge (vepa-capable bridge)."
msgstr ""
msgid "Interfaces parameter only supported on s390x or s390 architecture."
msgstr ""
msgid "Storage without libvirt pool is not supported on this architecture"
msgstr ""
#, python-format
msgid "Error while creating the virtual disk for the guest. Details: %(err)s"
msgstr ""
msgid ""
"When setting template disks without libvirt, following parameters are "
"required: 'index', 'format', 'path', 'size'"
msgstr ""
#, python-format
msgid "Storage pool %(name)s already exists"
msgstr "Le pool de stockage %(name)s existe déjà"
#, python-format
msgid "Storage pool %(name)s does not exist"
msgstr "Le pool de stockage %(name)s n'existe pas"
#, python-format
msgid "Specify %(item)s in order to create the storage pool %(name)s"
msgstr "Spécifiez %(item)s pour créer le pool de stockage %(name)s"
#, python-format
msgid "Unable to delete active storage pool %(name)s"
msgstr "Impossible de supprimer le pool de stockage actif %(name)s"
#, python-format
msgid "Unable to list storage pools. Details: %(err)s"
msgstr "Impossible de répertorier les pools de stockage. Détails : %(err)s"
#, python-format
msgid "Unable to create storage pool %(name)s. Details: %(err)s"
msgstr "Impossible de créer le pool de stockage %(name)s. Détails : %(err)s"
#, python-format
msgid "Unable to activate storage pool %(name)s. Details: %(err)s"
msgstr "Impossible d'activer le pool de stockage %(name)s. Détails : %(err)s"
#, python-format
msgid "Unable to deactivate storage pool %(name)s. Details: %(err)s"
msgstr ""
"Impossible de désactiver le pool de stockage %(name)s. Détails : %(err)s"
#, python-format
msgid "Unable to delete storage pool %(name)s. Details: %(err)s"
msgstr ""
"Impossible de supprimer le pool de stockage %(name)s. Détails : %(err)s"
#, python-format
msgid ""
"Unable to create NFS Pool as export path %(path)s may block during mount"
msgstr ""
"Impossible de créer le pool NFS car le chemin d'exportation %(path)s risque "
"de bloquer lors du montage"
#, python-format
msgid "Unable to create NFS Pool as export path %(path)s mount failed"
msgstr ""
"Impossible de créer le pool NFS car le montage du chemin d'exportation "
"%(path)s a échoué"
#, python-format
msgid "Unsupported storage pool type: %(type)s"
msgstr "Type de pool de stockage non pris en charge : %(type)s"
#, python-format
msgid "Error while retrieving storage pool XML to %(pool)s"
msgstr "Erreur d'extraction du fichier XML du pool de stockage dans %(pool)s"
msgid "Storage pool name must be a string without slashes (/)"
msgstr "Le nom du pool de stockage doit être une chaîne sans barre oblique (/)"
msgid ""
"Supported storage pool types are dir, netfs, logical, iscsi, isci and kimchi-"
"iso"
msgstr ""
"Types de pool de stockage pris en charge : dir, netfs, logical, iscsi, isci "
"et kimchi-iso"
msgid "Storage pool path must be a string"
msgstr "Le chemin du pool de stockage doit être une chaîne"
msgid "Storage pool host must be a IP or hostname"
msgstr "L'hôte du pool de stockage doit être une adresse IP ou un nom d'hôte"
msgid "Storage pool device must be the absolute path to the block device"
msgstr ""
"L'unité du pool de stockage doit correspondre au chemin d'accès absolu à "
"l'unité par bloc"
msgid "Storage pool devices parameter must be a list"
msgstr ""
"Le paramètre des unités du pool de stockage doivent constituer une liste"
msgid "Target IQN of an iSCSI pool must be a string"
msgstr "Le nom qualifié iSCSI (IQN) cible d'un pool iSCSI doit être une chaîne"
msgid "Port of a remote storage server must be an integer between 1 and 65535"
msgstr ""
"Le port d'un serveur de stockage distant doit être un entier compris entre 1 "
"et 65535"
msgid "iSCSI target username must be a string"
msgstr "Le nom d'utilisateur cible iSCSI doit être une chaîne"
msgid "iSCSI target password must be a string"
msgstr "Le mot de passe cible iSCSI doit être une chaîne"
msgid "Specify name and type to create a storage pool"
msgstr "Indiquez le nom et le type pour créer un pool de stockage"
#, python-format
msgid ""
"%(disk)s is not a valid disk/partition. Could not add it to the pool "
"%(pool)s."
msgstr ""
"%(disk)s n'est pas un disque/une partition valide. Impossible de l'ajouter "
"au pool %(pool)s."
#, python-format
msgid "Unable to extend logical pool %(pool)s. Details: %(err)s"
msgstr "Impossible d'étendre le pool logique %(pool)s. Détails : %(err)s"
msgid "The parameter disks only can be updated for logical storage pool."
msgstr ""
"Les disques de paramètre peuvent être mis à jour uniquement pour le pool de "
"stockage logique."
msgid "The SCSI host adapter name must be a string."
msgstr "Le nom de l'adaptateur hôte SCSI doit être une chaîne."
msgid "The storage pool kimchi_isos is reserved for internal use"
msgstr "Le pool de stockage kimchi_isos est réservé à un usage interne"
#, python-format
msgid ""
"Unable to activate NFS storage pool %(name)s. NFS server %(server)s is "
"unreachable."
msgstr ""
"Impossible d'activer le pool de stockage NFS %(name)s. Le serveur NFS "
"%(server)s est inaccessible."
#, python-format
msgid ""
"Unable to deactivate NFS storage pool %(name)s. NFS server %(server)s is "
"unreachable."
msgstr ""
"Impossible de désactiver le pool de stockage NFS %(name)s. Le serveur NFS "
"%(server)s est inaccessible."
#, python-format
msgid ""
"Unable to deactivate pool %(name)s as it is associated with some templates"
msgstr ""
"Impossible de désactiver le pool %(name)s car il est associé à plusieurs "
"modèles"
#, python-format
msgid "Unable to delete pool %(name)s as it is associated with some templates"
msgstr ""
"Impossible de supprimer le pool %(name)s car il est associé à plusieurs "
"modèles"
#, python-format
msgid ""
"A volume group named '%(name)s' already exists. Please, choose another name "
"to create the logical pool."
msgstr ""
"Un groupe de volumes nommé '%(name)s' existe déjà. Choisissez un autre nom "
"pour créer le pool logique."
#, python-format
msgid "Unable to update database with deep scan information due error: %(err)s"
msgstr ""
"Impossible de mettre à jour la base de données avec des informations "
"d'analyse approfondie en raison de l'erreur suivante : %(err)s"
#, python-format
msgid ""
"No volume group '%(name)s' found. Please, specify an existing volume group "
"to create the logical pool from."
msgstr ""
#, python-format
msgid "Unable to delete pool %(name)s as it is associated with guests: %(vms)s"
msgstr ""
#, python-format
msgid "Storage volume %(name)s already exists"
msgstr "Le volume de stockage %(name)s existe déjà"
#, python-format
msgid "Storage volume %(name)s does not exist in storage pool %(pool)s"
msgstr ""
"Le volume de stockage %(name)s n'existe pas dans le pool de stockage %(pool)s"
#, python-format
msgid ""
"Unable to create storage volume %(volume)s because storage pool %(pool)s is "
"not active"
msgstr ""
"Impossible de créer le volume de stockage %(volume)s car le pool de stockage "
"%(pool)s n'est pas actif"
#, python-format
msgid "Specify %(item)s in order to create storage volume %(volume)s"
msgstr "Spécifiez %(item)s afin de créer le volume de stockage %(volume)s"
#, python-format
msgid ""
"Unable to list storage volumes because storage pool %(pool)s is not active"
msgstr ""
"Impossible de répertorier les volumes de stockage car le pool de stockage "
"%(pool)s n'est pas actif"
#, python-format
msgid ""
"Unable to create storage volume %(name)s in storage pool %(pool)s. Details: "
"%(err)s"
msgstr ""
"Impossible de créer le volume de stockage %(name)s dans le pool de stockage "
"%(pool)s. Détails : %(err)s"
#, python-format
msgid "Unable to wipe storage volumes %(name)s. Details: %(err)s"
msgstr ""
"Impossible d'effacer les volumes de stockage %(name)s. Détails : %(err)s"
#, python-format
msgid "Unable to delete storage volume %(name)s. Details: %(err)s"
msgstr ""
"Impossible de supprimer le volume de stockage %(name)s. Détails : %(err)s"
#, python-format
msgid "Unable to resize storage volume %(name)s. Details: %(err)s"
msgstr ""
"Impossible de redimensionner le volume de stockage %(name)s. Détails : "
"%(err)s"
#, python-format
msgid "Storage type %(type)s does not support volume create and delete"
msgstr ""
"Le type de stockage %(type)s ne prend pas en charge la création et la "
"suppression de volume"
msgid "Storage volume name must be a string"
msgstr "Le nom du volume de stockage doit être une chaîne"
msgid "Storage volume allocation must be an integer number"
msgstr "L'allocation de volume de stockage doit être un nombre entier"
msgid ""
"Storage volume format not supported. Valid formats: qcow, qcow2, qed, raw, "
"vmdk, vpc."
msgstr ""
msgid "Storage volume requires a volume name"
msgstr "Le volume de stockage requiert un nom de volume"
#, python-format
msgid ""
"Unable to update database with storage volume information due error: %(err)s"
msgstr ""
"Impossible de mettre à jour la base de données avec des informations de "
"volume de stockage en raison de l'erreur suivante : %(err)s"
#, python-format
msgid "Only one of parameter %(param)s can be specified"
msgstr "Un seul paramètre %(param)s peut être spécifié"
#, python-format
msgid "Create volume from %(param)s is not supported"
msgstr ""
"La création d'un volume à partir de %(param)s n'est pas prise en charge"
msgid "Storage volume capacity must be an integer number."
msgstr ""
"La capacité du volume de stockage doit correspondre à un nombre entier."
msgid "Storage volume URL must be http://, https://, ftp:// or ftps://."
msgstr ""
"L'URL du volume de stockage doit être http://, https://, ftp:// ou ftps://."
#, python-format
msgid "Unable to access file %(url)s. Please, check it."
msgstr "Impossible d'accéder au fichier %(url)s. Vérifiez ce dernier."
#, python-format
msgid ""
"Unable to clone storage volume '%(name)s' in pool '%(pool)s'. Details: "
"%(err)s"
msgstr ""
"Impossible de cloner le volume de stockage '%(name)s' dans le pool "
"'%(pool)s'. Détails : %(err)s"
msgid "Specify chunk data and its size to upload a file."
msgstr ""
"Spécifiez les données de bloc et leur taille pour télécharger un fichier."
msgid "In order to upload a storage volume, specify the 'upload' parameter."
msgstr ""
"Pour télécharger un volume de stockage, spécifiez le paramètre 'upload'."
msgid ""
"Unable to upload chunk data as it does not match with requested chunk size."
msgstr ""
"Impossible de télécharger les données de bloc car elles ne correspondent pas "
"à la taille de bloc."
#, python-format
msgid "The storage volume %(vol)s is not under an upload process."
msgstr ""
"Le volume de stockage %(vol)s n'est pas soumis à un processus de "
"téléchargement."
msgid "The upload chunk data will exceed the storage volume size."
msgstr ""
"Le téléchargement des données de bloc dépasse la taille du volume de "
"stockage."
#, python-format
msgid "Unable to upload chunk data to storage volume. Details: %(err)s."
msgstr ""
"Impossible de télécharger les données de bloc dans le volume de stockage. "
"Détails : %(err)s."
#, python-format
msgid "Interface %(name)s does not exist"
msgstr "L'interface %(name)s n'existe pas"
#, python-format
msgid ""
"Failed to list interfaces. Invalid _inuse parameter. Supported options for "
"_inuse are: %(supported_inuse)s"
msgstr ""
#, python-format
msgid "Network %(name)s already exists"
msgstr "Le réseau %(name)s existe déjà"
#, python-format
msgid "Network %(name)s does not exist"
msgstr "Le réseau %(name)s n'existe pas"
#, python-format
msgid "Subnet %(subnet)s specified for network %(network)s is not valid."
msgstr ""
msgid "Specify a network interface to create bridged or macvtap networks."
msgstr ""
#, python-format
msgid "Unable to delete or update active network %(name)s"
msgstr ""
#, python-format
msgid "Interface %(iface)s specified for network %(network)s is already in use"
msgstr ""
"L'interface %(iface)s indiquée pour le réseau %(network)s est déjà utilisée"
msgid "Interface should be bare NIC, bonding or bridge device."
msgstr ""
"L'interface doit être un contrôleur NIC nu, une unité de pontage ou de "
"liaison."
#, python-format
msgid "Unable to create or update network %(name)s. Details: %(err)s"
msgstr ""
#, python-format
msgid "Unable to find a free IP address for network '%(name)s'"
msgstr ""
"Impossible de trouver une adresse IP disponible pour le réseau '%(name)s'"
#, python-format
msgid "The interface %(iface)s already exists."
msgstr "L'interface %(iface)s existe déjà."
msgid "Network name must be a string without slashes (/) or quotes (\")"
msgstr ""
"Le nom du réseau doit être une chaîne sans barre oblique (/) ni guillemet "
"(\")"
msgid ""
"Supported network types are isolated, NAT, macvtap, bridge, vepa and "
"passthrough."
msgstr ""
msgid "Network subnet must be a string with IP address and prefix or netmask"
msgstr ""
"Le sous-réseau du réseau doit être une chaîne avec adresse IP et préfixe ou "
"masque de réseau"
msgid "Network interfaces must be an array."
msgstr ""
msgid "Network VLAN ID must be an integer between 1 and 4094"
msgstr ""
"L'ID réseau local virtuel du réseau doit être un entier compris entre 1 et "
"4094"
msgid "Specify name and type to create a Network"
msgstr "Indiquez le nom et le type pour créer un réseau"
#, python-format
msgid ""
"Unable to delete or update network %(name)s as it is linked to some virtual "
"machines (%(vms)s) and/or templates (%(tmpls)s)."
msgstr ""
#, python-format
msgid ""
"Unable to deactivate network %(name)s as it is linked to are some virtual "
"machines (%(vms)s) and/or templates (%(tmpls)s)."
msgstr ""
#, python-format
msgid "Bridge device %(name)s can not be the trunk device of a VLAN."
msgstr ""
"L'unité de pontage %(name)s ne peut pas être l'unité de liaison d'un réseau "
"local virtuel."
#, python-format
msgid "Failed to activate interface %(iface)s: %(err)s."
msgstr "Echec de l'activation de l'interface %(iface)s: %(err)s."
#, python-format
msgid ""
"Failed to activate interface %(iface)s. Please check the physical link "
"status."
msgstr ""
"Echec de l'activation de l'interface %(iface)s. Vérifiez l'état de la "
"liaison physique."
#, python-format
msgid "Failed to start network %(name)s. Details: %(err)s"
msgstr "Echec du démarrage du réseau %(name)s. Détails : %(err)s"
#, python-format
msgid "Unable to redefine interface %(name)s. Details: %(err)s"
msgstr ""
#, python-format
msgid "Unable to create bridge %(name)s. Details: %(err)s"
msgstr ""
msgid ""
"Unable to create bridge with NetworkManager enabled. Disable it and try "
"again."
msgstr ""
msgid "Interface should be bare NIC or bonding."
msgstr ""
msgid "Network interfaces parameter must contain at least one interface."
msgstr ""
msgid "Only one interface is allowed for 'bridge' and 'macvtap' networks."
msgstr ""
msgid "Subnet is not a valid parameter for this type of virtual network."
msgstr ""
msgid ""
"VLAN ID and interfaces are not valid parameters for this type of virtual "
"network."
msgstr ""
#, python-format
msgid "Storage server %(server)s was not used by Kimchi"
msgstr "Le serveur de stockage %(server)s n'a pas été utilisé par Kimchi"
#, python-format
msgid "Distro '%(name)s' does not exist"
msgstr "La distribution '%(name)s' n'existe pas"
#, python-format
msgid "Node device '%(name)s' not found"
msgstr "Unité de noeud '%(name)s' introuvable"
msgid "Conflicting flag filters specified."
msgstr "Filtres d'indicateur en conflit spécifiés."
msgid "Unable to choose a virtual machine name"
msgstr "Impossible de sélectionner un nom de machine virtuelle"
msgid "Cannot upgrade objectstore data."
msgstr ""
msgid "Invalid storage type. Types supported: 'cdrom', 'disk'"
msgstr "Type de stockage non valide. Types pris en charge : 'cdrom', 'disk'"
#, python-format
msgid "The path '%(value)s' is not a valid local/remote path for the device"
msgstr ""
"Le chemin '%(value)s' n'est pas un chemin local/distant valide pour l'unité"
msgid "Only CDROM path can be update."
msgstr "Seul le chemin du CD-ROM peut être mis à jour."
#, python-format
msgid ""
"The storage device %(dev_name)s does not exist in the virtual machine "
"%(vm_name)s"
msgstr ""
"L'unité de stockage %(dev_name)s n'existe pas sur la machine virtuelle "
"%(vm_name)s"
#, python-format
msgid "Error while creating new storage device: %(error)s"
msgstr "Erreur lors de la création de l'unité de stockage : %(error)s"
#, python-format
msgid "Error while updating storage device: %(error)s"
msgstr "Erreur lors de la mise à jour de l'unité de stockage : %(error)s"
#, python-format
msgid "Error while removing storage device: %(error)s"
msgstr "Erreur lors du retrait de l'unité de stockage : %(error)s"
msgid "Do not support IDE device hot plug"
msgstr "Pas de prise en charge du remplacement à chaud d'unité IDE"
msgid ""
"Specify type and path or type and pool/volume to add a new virtual machine "
"disk"
msgstr ""
"Spécifiez un type et un chemin pour ajouter un nouveau disque de machine "
"virtuelle"
msgid "Specify path to update virtual machine disk"
msgstr "Indiquez le chemin pour mettre à jour le disque de machine virtuelle"
#, python-format
msgid "Controller type %(type)s limitation of %(limit)s devices reached"
msgstr "Le type de contrôleur %(type)s a atteint sa limite de %(limit)s unités"
#, python-format
msgid "Cannot retrieve disk path information for given pool/volume: %(error)s"
msgstr ""
"Impossible d'extraire les informations de chemin d'accès au disque pour le "
"pool/volume donné : %(error)s"
msgid "Volume already in use by other virtual machine."
msgstr "Le volume est déjà utilisé par une autre machine virtuelle."
msgid ""
"Only one of path or pool/volume can be specified to add a new virtual "
"machine disk"
msgstr ""
"Soit le chemin, soit le pool/volume peut être spécifié pour ajouter un "
"nouveau disque de machine virtuelle"
#, python-format
msgid ""
"Volume chosen with format %(format)s does not fit in the storage type "
"%(type)s"
msgstr ""
"Le volume choisi avec le format %(format)s n'est pas adapté au type de "
"stockage %(type)s"
msgid "On s390x arch one of pool, path of dir_path must be specified"
msgstr ""
msgid ""
"On s390x arch 'format' must be specified while attaching disk to virtual "
"machine"
msgstr ""
#, python-format
msgid "Virtual disk already exists on the system: %(disk_path)s"
msgstr ""
#, python-format
msgid ""
"Unable to create snapshot '%(name)s' on virtual machine '%(vm)s'. Details: "
"%(err)s"
msgstr ""
"Impossible de créer l'image instantanée '%(name)s' sur la machine virtuelle "
"'%(vm)s'. Détails : %(err)s"
#, python-format
msgid "Snapshot '%(name)s' does not exist on virtual machine '%(vm)s'."
msgstr ""
"L'image instantanée '%(name)s' n'existe pas sur la machine virtuelle "
"'%(vm)s'."
#, python-format
msgid ""
"Unable to retrieve snapshot '%(name)s' on virtual machine '%(vm)s'. Details: "
"%(err)s"
msgstr ""
"Impossible d'extraire l'image instantanée '%(name)s' sur la machine "
"virtuelle '%(vm)s'. Détails : %(err)s"
#, python-format
msgid "Unable to list snapshots on virtual machine '%(vm)s'. Details: %(err)s"
msgstr ""
"Impossible de répertorier les images instantanées sur la machine virtuelle "
"'%(vm)s'. Détails : %(err)s"
#, python-format
msgid ""
"Unable to delete snapshot '%(name)s' on virtual machine '%(vm)s'. Details: "
"%(err)s"
msgstr ""
"Impossible de supprimer l'image instantanée '%(name)s' sur la machine "
"virtuelle '%(vm)s'. Détails : %(err)s"
#, python-format
msgid ""
"Unable to retrieve current snapshot of virtual machine '%(vm)s'. Details: "
"%(err)s"
msgstr ""
"Impossible d'extraire l'image instantanée en cours de la machine virtuelle "
"'%(vm)s'. Détails : %(err)s"
#, python-format
msgid ""
"Unable to revert virtual machine '%(vm)s' to snapshot '%(name)s'. Details: "
"%(err)s"
msgstr ""
"Impossible de rétablir la machine virtuelle '%(vm)s' à l'image instantanée "
"'%(name)s'. Détails : %(err)s"
#, python-format
msgid ""
"Unable to create snapshot of virtual machine '%(vm)s' because it contains a "
"disk with format '%(format)s'; only 'qcow2' is supported."
msgstr ""
"Impossible de créer l'image instantanée de la machine virtuelle '%(vm)s' car "
"elle contient un disque au format '%(format)s' ; seul 'qcow2' est pris en "
"charge."
msgid ""
"The number of vCPUs must be less than or equal the maximum number of vCPUs "
"specified."
msgstr ""
msgid ""
"When CPU topology is defined, maximum number of vCPUs must be a product of "
"sockets, cores, and threads."
msgstr ""
msgid "This host (or current configuration) does not allow CPU topology."
msgstr "Cet hôte (ou configuration actuelle) n'autorise pas la topologie d'UC."
msgid "The maximum number of vCPUs is too large for this system."
msgstr ""
msgid ""
"When CPU topology is defined, CPUs must be a multiple of the 'threads' "
"number defined."
msgstr ""
msgid ""
"When CPU topology is specified, sockets, cores and threads are required "
"paramaters."
msgstr ""
msgid ""
"Parameter 'cpu_info' expects an object with fields among: 'vcpus', "
"'maxvcpus', 'topology'."
msgstr ""
msgid ""
"Parameter 'topology' expects an object with fields among: 'sockets', "
"'cores', 'threads'."
msgstr ""
msgid "Unable to update Max CPU or CPU topology when guest is running."
msgstr ""
#, python-format
msgid "Unable to hot plug/unplug CPUs. Details: %(err)s"
msgstr ""
#, python-format
msgid "Invalid volume group name parameter: %(name)s."
msgstr ""
msgid ""
"Unable to establish connection with libvirt. Please check your libvirt URI "
"which is often defined in /etc/libvirt/libvirt.conf"
msgstr ""
msgid ""
"Libvirt service is not active. Please start the libvirt service in your host "
"system."
msgstr ""
msgid "Failed to register the default event implementation."
msgstr ""
msgid "Failed to register timeout event."
msgstr ""
msgid "Failed to Run the default event implementation."
msgstr ""
#, python-format
msgid ""
"I/O error on guest '%(vm)s': storage pool out of space for %(devAlias)s "
"(%(srcPath)s)."
msgstr ""
#, python-format
msgid "Create virtual network '%(name)s' type '%(connection)s'"
msgstr ""
#, python-format
msgid "Remove virtual network '%(ident)s'"
msgstr ""
#, python-format
msgid "Update virtual network '%(ident)s'"
msgstr ""
#, python-format
msgid "Activate virtual network '%(ident)s'"
msgstr ""
#, python-format
msgid "Deactivate virtual network '%(ident)s'"
msgstr ""
#, python-format
msgid "Create storage pool '%(name)s' type '%(type)s'"
msgstr ""
#, python-format
msgid "Remove storage pool '%(ident)s'"
msgstr ""
#, python-format
msgid "Update storage pool '%(ident)s'"
msgstr ""
#, python-format
msgid "Activate storage pool '%(ident)s'"
msgstr ""
#, python-format
msgid "Deactivate storage pool '%(ident)s'"
msgstr ""
#, python-format
msgid "Create snapshot '%(name)s' at guest '%(vm)s'"
msgstr ""
#, python-format
msgid "Remove snapshot '%(ident)s' from guest '%(vm)s'"
msgstr ""
#, python-format
msgid "Revert guest '%(vm)s' to snapshot '%(ident)s'"
msgstr ""
#, python-format
msgid "Create template '%(name)s'"
msgstr ""
#, python-format
msgid "Remove template '%(ident)s'"
msgstr ""
#, python-format
msgid "Update template '%(ident)s'"
msgstr ""
#, python-format
msgid "Clone template '%(ident)s'"
msgstr ""
#, python-format
msgid "Create guest '%(name)s' from template '%(template)s'"
msgstr ""
#, python-format
msgid "Remove guest '%(ident)s'"
msgstr ""
#, python-format
msgid "Edit guest '%(ident)s'"
msgstr ""
#, python-format
msgid "Start guest '%(ident)s'"
msgstr ""
#, python-format
msgid "Power off guest '%(ident)s'"
msgstr ""
#, python-format
msgid "Shutdown guest '%(ident)s'"
msgstr ""
#, python-format
msgid "Restart guest '%(ident)s'"
msgstr ""
#, python-format
msgid "Connect to guest '%(ident)s' through novnc/spice"
msgstr ""
#, python-format
msgid "Clone guest '%(ident)s'"
msgstr ""
#, python-format
msgid "Migrate guest '%(ident)s' to '%(remote_host)s'"
msgstr ""
#, python-format
msgid "Suspend guest '%(ident)s'"
msgstr ""
#, python-format
msgid "Resume guest '%(ident)s'"
msgstr ""
#, python-format
msgid "Connect to guest '%(ident)s' through serial"
msgstr ""
#, python-format
msgid "Attach host device '%(name)s' to guest '%(vmid)s'"
msgstr ""
#, python-format
msgid "Detach host device '%(ident)s' from guest '%(vmid)s'"
msgstr ""
#, python-format
msgid "Attach network interface '%(network)s' to guest '%(vm)s'"
msgstr ""
#, python-format
msgid "Detach network interface '%(ident)s' from guest '%(vm)s'"
msgstr ""
#, python-format
msgid "Update network interface '%(ident)s' at guest '%(vm)s'"
msgstr ""
#, python-format
msgid "Attach %(type)s storage '%(path)s' to guest '%(vm)s'"
msgstr ""
#, python-format
msgid "Remove storage '%(ident)s' from guest '%(vm)s'"
msgstr ""
#, python-format
msgid "Update storage '%(ident)s' at guest '%(vm)s'"
msgstr ""
#, python-format
msgid "Create storage volume '%(name)s' at pool '%(pool)s'"
msgstr ""
#, python-format
msgid "Remove storage volume '%(ident)s' from pool '%(pool)s'"
msgstr ""
#, python-format
msgid "Update storage volume '%(ident)s' at pool '%(pool)s'"
msgstr ""
#, python-format
msgid "Wipe storage volume '%(ident)s' off pool '%(pool)s'"
msgstr ""
#, python-format
msgid "Resize storage volume '%(ident)s' at pool '%(pool)s' with size %(size)s"
msgstr ""
#, python-format
msgid "Clone storage volume '%(ident)s' at pool '%(pool)s'"
msgstr ""
msgid "Create a New Virtual Machine"
msgstr "Créer une machine virtuelle"
msgid "Virtual Machine Name"
msgstr "Nom de la machine virtuelle"
msgid ""
"The name used to identify the virtual machine. If omitted, a name will be "
"chosen based on the template used."
msgstr ""
"Nom utilisé pour identifier la machine virtuelle. S'il est omis, un nom sera "
"choisi en fonction du modèle utilisé."
msgid "Please create a template first."
msgstr "Commencez par créer un modèle."
msgid "Create a Template"
msgstr "Créer un modèle"
msgid "Please choose a template."
msgstr "Sélectionnez un modèle."
msgid "This template has invalid parameters."
msgstr ""
msgid "This template has invalid parameters"
msgstr ""
msgid "OS"
msgstr "SE"
msgid "Version"
msgstr "Version"
msgid "Current CPUs"
msgstr ""
msgid "Memory"
msgstr "Mémoire"
msgid "Create"
msgstr "Créer"
msgid "Creating..."
msgstr "Création..."
msgid "Cancel"
msgstr "Annuler"
msgid "Clone a Guest"
msgstr ""
msgid ""
"When the target guest has SCSI or iSCSI volumes, they will be cloned on the "
"default storage pool. The same will happen when the target pool does not "
"have enough space to clone the volumes. Do you want to continue?"
msgstr ""
msgid "Number of times to clone"
msgstr ""
msgid "Continue"
msgstr ""
msgid "Edit Guest"
msgstr "Editer l'invité"
msgid "General"
msgstr "Général"
msgid "Storage"
msgstr "Stockage"
msgid "Interface"
msgstr "Interface"
msgid "Permission"
msgstr ""
msgid "Pci"
msgstr ""
msgid "Snapshot"
msgstr ""
msgid "Processor"
msgstr "Processeur"
msgid "Name"
msgstr "Nom"
msgid "Memory (MB)"
msgstr "Mémoire (Mo)"
msgid "More"
msgstr ""
msgid "Max Memory (MB)"
msgstr ""
msgid "Host does not support memory hotplug"
msgstr ""
msgid "Icon"
msgstr "Icône"
msgid "Console"
msgstr ""
msgid "Nothing selected"
msgstr ""
msgid "sclp"
msgstr ""
msgid "virtio"
msgstr ""
msgid ""
"Select which items for boot order and grad them when needed to order them. "
"At least one option must be selected."
msgstr ""
msgid "Add"
msgstr "Ajouter"
msgid "Device"
msgstr "Unité"
msgid "Path"
msgstr "Chemin"
msgid "Actions"
msgstr "Actions"
msgid "Network"
msgstr "Réseau"
msgid "Type"
msgstr "Type"
msgid "MAC Address"
msgstr "Adresse MAC"
msgid "IP Address"
msgstr ""
msgid "Network/Interface"
msgstr ""
msgid "Mode"
msgstr ""
msgid "Available system users and groups"
msgstr "Groupes et utilisateurs système disponibles"
msgid "Users"
msgstr "Utilisateurs "
msgid "Groups"
msgstr "Groupes"
msgid "Selected system users and groups"
msgstr "Groupes et utilisateurs système sélectionnés"
msgid "User"
msgstr "Utilisateur"
msgid "All"
msgstr "Tout"
msgid "To Add"
msgstr "A ajouter"
msgid "Added"
msgstr "Ajouté"
msgid "Filter"
msgstr ""
msgid "Status"
msgstr ""
msgid "Product"
msgstr "Produit"
msgid "Vendor"
msgstr "Fournisseur"
msgid "Loading"
msgstr ""
msgid "Created"
msgstr "Créé"
msgid "Current CPU Number"
msgstr ""
msgid ""
"Current CPU must be equal or lower than the Maximum CPU value. If a topology "
"is set, it must be also be a multiple of the 'threads' value."
msgstr ""
msgid "Max CPU"
msgstr ""
msgid ""
"Unable to edit maximum CPU or CPU topology when editing a running or paused "
"virtual machine."
msgstr ""
msgid ""
"If a topology is set, this value will be the product of sockets * times * "
"cores."
msgstr ""
msgid "Manually set CPU topology"
msgstr "Définir manuellement la topologie d'UC"
msgid "Sockets"
msgstr ""
msgid "Cores"
msgstr "Coeurs"
msgid "Threads"
msgstr "Unités d'exécution"
msgid "Save"
msgstr "Sauvegarder"
msgid "Replace"
msgstr "Remplacer"
msgid "Detach"
msgstr "Détacher"
msgid "Remove"
msgstr "Retirer"
msgid "Edit"
msgstr "Editer"
msgid "LDAP User ID,e.g.foo@foo.com"
msgstr "ID utilisateur LDAP, par ex. foo@foo.com"
msgid "Revert"
msgstr ""
msgid "Running"
msgstr ""
msgid "Disconnected"
msgstr ""
msgid "Starting"
msgstr ""
msgid "Crashed"
msgstr ""
msgid "Unknown"
msgstr ""
msgid "Paused"
msgstr ""
msgid "Suspended"
msgstr ""
msgid "Resetting"
msgstr ""
msgid "View Console"
msgstr ""
msgid "View Serial"
msgstr ""
msgid "Clone"
msgstr "Cloner"
msgid "Migrate"
msgstr ""
msgid "Reset"
msgstr "Réinitialiser"
msgid "Pause"
msgstr "Pause"
msgid "Resume"
msgstr "Reprendre"
msgid "Shut Down"
msgstr "Arrêter"
msgid "Start"
msgstr "Démarrer"
msgid "Power Off"
msgstr "Mettre hors tension"
msgid "Delete"
msgstr "Supprimer"
msgid "No Data Available"
msgstr ""
msgid "Processors Utilization"
msgstr ""
msgid "Memory Utilization"
msgstr ""
msgid "Storage I/O"
msgstr ""
msgid "Network I/O"
msgstr "E-S réseau"
msgid "Migrate a Guest"
msgstr ""
msgid ""
"Disclaimer: This process cannot be stopped after started, can take a long "
"time to complete and will turn off the VM on this Hypervisor when it is "
"successfully migrated to the remote destination."
msgstr ""
msgid "Remote Server"
msgstr ""
msgid "IP Address or Hostname"
msgstr ""
msgid ""
"The following fields are optional. Fill them if you want Kimchi to setup a "
"password-less ssh session between the localhost and the remote host. The "
"setup process will only be successful if the user has 'SUDO ALL' permission "
"in the remote machine."
msgstr ""
msgid "Username of the remote host"
msgstr ""
msgid "Password"
msgstr "Mot de passe"
msgid "Password of the user in the remote host"
msgstr ""
msgid "Use RDMA transport"
msgstr ""
msgid ""
"Check this option only if RDMA is properly configured in both source and "
"destination hosts, otherwise migration will fail."
msgstr ""
msgid "Delete this VM when the migration is completed"
msgstr ""
msgid "Add a Storage Device to VM"
msgstr "Ajouter une unité de stockage à la machine virtuelle"
msgid "Device Type"
msgstr "Type d'unité"
msgid ""
"The device type. Currently, \"cdrom\" and \"disk\" are supported. If the "
"guest is running, only \"disk\" is supported."
msgstr ""
msgid "Create a new disk"
msgstr ""
msgid "Select an existing disk"
msgstr ""
msgid "Source"
msgstr ""
msgid "Storage based on Libvirt pool or direct block device"
msgstr ""
msgid "Storage Pool"
msgstr "Pool de stockage"
msgid "Storage pool to create the volume in"
msgstr ""
msgid "Disk Size (GB)"
msgstr ""
msgid "New disk size to be created"
msgstr ""
msgid "Format"
msgstr ""
msgid "Format of the new disk to be created"
msgstr ""
msgid "Directory Path"
msgstr ""
msgid "Provide a directory path"
msgstr ""
msgid "Storage pool in which the volume is located in"
msgstr ""
msgid "Storage Volume"
msgstr "Volume de stockage"
msgid "Storage volume to be attached"
msgstr "Volume de stockage à attacher"
msgid "Disk Path"
msgstr ""
msgid "Provide a block device"
msgstr ""
msgid "File Path"
msgstr "Chemin d'accès au fichier"
msgid "The ISO file path in the server for CDROM."
msgstr "Chemin d'accès au fichier ISO sur le serveur pour le CD-ROM."
msgid "Attach"
msgstr "Attacher"
msgid "Host"
msgstr "Hôte"
msgid "Guests"
msgstr "Invités"
msgid "Templates"
msgstr "Modèles"
msgid "This is not a valid Linux path"
msgstr "Ce chemin Linux n'est pas valide"
msgid "Unable to read file."
msgstr "Impossible de lire le fichier."
msgid "Error while uploading file."
msgstr "Erreur lors du téléchargement du fichier."
msgid "Delete Confirmation"
msgstr "Confirmation de suppression"
msgid "OK"
msgstr "OK"
msgid "Confirm"
msgstr "Confirmer"
msgid "Warning"
msgstr "Avertissement"
msgid "Cloning..."
msgstr "Clonage en cours..."
msgid "Saving..."
msgstr ""
msgid "Migrating..."
msgstr ""
msgid "No ISO found"
msgstr "ISO introuvable"
msgid "Add Template"
msgstr "Ajouter un modèle"
msgid "This may take a long time. Do you want to continue?"
msgstr "Cette opération peut être assez longue. Voulez-vous continuer ?"
msgid ""
"This will permanently delete the %1 template. Would you like to continue?"
msgstr ""
msgid "View Table"
msgstr ""
msgid "View Gallery"
msgstr ""
msgid "Not Available"
msgstr ""
msgid "Please check the invalid Storage Pools"
msgstr ""
msgid "Please check the invalid Storage Pools or Paths"
msgstr ""
msgid "macvtap"
msgstr ""
msgid "ovs"
msgstr ""
msgid "network"
msgstr ""
msgid ""
"This will delete the %1 virtual machine and its virtual disks. This "
"operation cannot be undone. Would you like to continue?"
msgstr ""
msgid "Power off Confirmation"
msgstr "Confirmation de mise hors tension"
msgid ""
"This action may produce undesirable results, for example unflushed disk "
"cache in the %1 guest. Would you like to continue?"
msgstr ""
msgid "Reset Confirmation"
msgstr "Confirmation de réinitialisation"
msgid ""
"There is a risk of data loss caused by reset without the %1 guest OS "
"shutdown. Would you like to continue?"
msgstr ""
msgid "Shut Down Confirmation"
msgstr "Confirmation d'arrêt"
msgid ""
"Note the %1 guest OS may ignore this request. Would you like to continue?"
msgstr ""
msgid "Virtual Machine delete Confirmation"
msgstr "Confirmation de la suppression de la machine virtuelle"
msgid ""
"The %1 virtual machine is not persistent. Power Off will delete it. Continue?"
msgstr ""
msgid "Add Guest"
msgstr ""
msgid "Input is not a number"
msgstr ""
msgid "Memory value cannot be higher than Max Memory value"
msgstr ""
msgid ""
"For better performance it is recommended a threads per core value not "
"greater than %1."
msgstr ""
msgid ""
"This CDROM will be detached permanently and you can re-attach it. Continue "
"to detach it?"
msgstr ""
"Ce CD-ROM va être détaché définitivement et ne pourra pas être attaché à "
"nouveau. Continuer le détachement ?"
msgid "Attaching..."
msgstr "Attachement en cours..."
msgid ""
"This disk will be detached permanently and you can re-attach it. Continue to "
"detach it?"
msgstr ""
"Ce disque va être détaché définitivement et ne pourra pas être attaché à "
"nouveau. Continuer le détachement ?"
msgid "interface:"
msgstr "interface :"
msgid "address:"
msgstr "adresse :"
msgid "link_type:"
msgstr "type_lien :"
msgid "block:"
msgstr "bloc :"
msgid "drive_type:"
msgstr "type_lecteur :"
msgid "model:"
msgstr "modèle :"
msgid "Affected devices:"
msgstr "Unités concernées :"
msgid "Less"
msgstr ""
msgid "Successfully attached device to VM"
msgstr ""
msgid "Successfully detached device from VM"
msgstr ""
msgid "Following devices will be affected, confirm?"
msgstr ""
msgid "Bridge"
msgstr ""
msgid "Vepa"
msgstr ""
msgid "None"
msgstr ""
msgid "unavailable"
msgstr "non disponible"
msgid ""
"This action will interrupt network connectivity for any virtual machine that "
"depend on the %1 network."
msgstr ""
msgid "Add Network"
msgstr ""
msgid ""
"The %1 network is not persistent. Instead of stop, this action will "
"permanently delete it. Would you like to continue?"
msgstr ""
msgid ""
"The bridged VLAN tag may not work well with NetworkManager enabled. You "
"should consider disabling it."
msgstr ""
"Il se peut que l'étiquette Réseau local virtuel local routé ne fonctionne "
"pas correctement lorsque NetworkManager est activé. Vous devez envisager de "
"désactiver ce dernier."
msgid ""
"This will permanently delete the %1 storage pool. Would you like to continue?"
msgstr ""
msgid "This storage pool is empty."
msgstr "Ce pool de stockage est vide."
msgid ""
"It will format your disk and you will loose any data in there, are you sure "
"to continue? "
msgstr ""
"Le disque va être formaté et vous perdrez toutes les données qu'il contient. "
"Voulez-vous vraiment continuer ? "
msgid "SCSI Fibre Channel"
msgstr "Fibre Channel SCSI"
msgid "No SCSI adapters found."
msgstr "Aucun adaptateur SCSI trouvé."
msgid "Loading iSCSI targets..."
msgstr "Chargement des cibles iSCSI..."
msgid "No iSCSI found. Please input one."
msgstr "iSCSI introuvable. Spécifiez-le."
msgid "Failed to load iSCSI targets."
msgstr "Echec du chargement des cibles iSCSI."
msgid "Would you like to continue?"
msgstr ""
msgid "This will permanently delete the following storage volumes: %1"
msgstr ""
msgid "No available partitions found."
msgstr "Aucune partition disponible trouvée."
msgid ""
"The %1 storage pool is not persistent. Instead of deactivate, this action "
"will permanently delete it. Would you like to continue?"
msgstr ""
msgid "Unable to retrieve partitions information."
msgstr "Impossible d'extraire les informations relatives aux partitions."
msgid "In progress..."
msgstr "En cours..."
msgid "Failed!"
msgstr "Echec !"
msgid "No LVM found in the system."
msgstr ""
msgid "This will permanently wipe the following storage volumes: %1"
msgstr ""
msgid "Wipe Confirmation"
msgstr ""
msgid "Select one or more partitions to be added to the logical pool %1:"
msgstr ""
msgid "Add Storage"
msgstr ""
msgid "DIR"
msgstr ""
msgid "NFS"
msgstr ""
msgid "iSCSI"
msgstr ""
msgid "LOGICAL"
msgstr ""
msgid "device"
msgstr ""
msgid "path"
msgstr ""
msgid "size (GiB)"
msgstr ""
msgid "free size (GiB)"
msgstr ""
msgid "Invalid NFS mount path."
msgstr "Chemin de montage NFS non valide."
msgid "No logical device selected."
msgstr "Aucune unité logique sélectionnée."
msgid "This is not a valid Server Name or IP. Please, modify it."
msgstr ""
"Il ne s'agit pas d'un nom de serveur ou d'une adresse IP valide. Modifiez "
"cet élément."
msgid "CDROM path needs to be a valid local/remote path and cannot be blank."
msgstr ""
"Le chemin de CD-ROM doit être un chemin local/distant et ne peut pas être à "
"blanc."
msgid "Disk pool or volume cannot be blank."
msgstr "Le pool de stockage sur disque ou le volume ne peut pas être à blanc."
msgid ""
"Disk size or Format or Directory path cannot be blank and Directory path "
"needs to be a valid local/remote path."
msgstr ""
msgid "Disk path needs to be a valid local/remote path and cannot be blank."
msgstr ""
msgid "Storage pool or Disk size or Format cannot be blank."
msgstr ""
msgid "cdrom"
msgstr ""
msgid "disk"
msgstr ""
msgid "Pool"
msgstr ""
msgid "qcow"
msgstr ""
msgid "qcow2"
msgstr ""
msgid "qed"
msgstr ""
msgid "raw"
msgstr ""
msgid "vmdk"
msgstr ""
msgid "vpc"
msgstr ""
msgid "Create a network"
msgstr "Créer un réseau"
msgid "Network Name"
msgstr "Nom du réseau"
msgid "Name should not contain '/' and '\"'."
msgstr "Le nom ne doit pas contenir '/' et '\"'."
msgid "Network Type"
msgstr "Type de réseau"
msgid "Isolated: no external network connection"
msgstr "Isolé : aucune connexion réseau externe"
msgid "NAT: outbound physical network connection only"
msgstr "NAT : connexion réseau physique sortante uniquement"
msgid "Macvtap: Virtual machines are connected to physical network directly"
msgstr ""
msgid ""
"Passthrough: Virtual machines are connected using a macvtap connection in "
"passthrough mode."
msgstr ""
msgid ""
"VEPA: special mode where virtual machines are connected to a VEPA-enabled "
"switch"
msgstr ""
msgid "Bridged: Virtual machines are connected through a network bridge"
msgstr ""
msgid "Destination"
msgstr "Destination"
msgid "Select an Interface"
msgstr ""
msgid "Enable VLAN"
msgstr "Activer le réseau local virtuel"
msgid "VLAN ID"
msgstr "ID réseau local virtuel"
msgid "Edit Network"
msgstr ""
msgid "Address Space"
msgstr ""
msgid "Define a New Storage Pool"
msgstr "Définir un nouveau pool de stockage"
msgid "Storage Pool Name"
msgstr "Nom du pool de stockage"
msgid ""
"The name used to identify the storage pools, and it should not be empty."
msgstr ""
"Nom utilisé pour identifier les pools de stockage. Ne doit pas être vide."
msgid "Storage Pool Type"
msgstr "Type de pool de stockage"
msgid "Storage Path"
msgstr "Chemin de stockage"
msgid ""
"The path of the Storage Pool. Each Storage Pool must have a unique path."
msgstr ""
"Chemin du pool de stockage. Chaque pool de stockage doit avoir un chemin "
"unique."
msgid ""
"Kimchi will try to create the directory when it does not already exist in "
"your system."
msgstr ""
"Kimchi va tenter de créer le répertoire s'il n'en existe pas déjà un sur "
"votre système."
msgid "NFS Server IP"
msgstr "IP du serveur NFS"
msgid "NFS server IP or hostname. It can be input or chosen from history."
msgstr ""
"IP ou nom d'hôte du serveur NFS. Peut être entré ou sélectionné depuis "
"l'historique."
msgid "NFS Path"
msgstr "Chemin NFS"
msgid "The NFS exported path on NFS server."
msgstr "Chemin NFS exporté ou serveur NFS."
msgid "Create from existing LVM"
msgstr ""
msgid "Create from raw disk"
msgstr ""
msgid "Looking for existing lvms ..."
msgstr ""
msgid "Looking for available partitions ..."
msgstr "Recherche des partitions disponibles..."
msgid "iSCSI Server"
msgstr "Serveur iSCSI"
msgid "Server"
msgstr "Serveur"
msgid "Port"
msgstr "Port"
msgid "iSCSI server IP or hostname. It should not be empty."
msgstr "IP ou nom d'hôte du serveur iSCSI. Ne doit pas être vide."
msgid "Target"
msgstr "Cible"
msgid "The iSCSI target on iSCSI server"
msgstr "Cible iSCSI sur le serveur iSCSI"
msgid "Add iSCSI Authentication"
msgstr "Ajouter l'authentification iSCSI"
msgid "User Name"
msgstr "Nom d'utilisateur"
msgid "SCSI Adapter"
msgstr "Adaptateur SCSI"
msgid "Please, wait..."
msgstr "Veuillez patienter..."
msgid "Add a Volume to Storage Pool"
msgstr "Ajouter un volume au pool de stockage"
msgid "Fetch from remote URL"
msgstr "Extraire de l'URL distante"
msgid "Enter the remote URL here."
msgstr "Indiquez ici l'URL distante."
msgid "Upload a file"
msgstr "Télécharger un fichier"
msgid "Choose the file you want to upload."
msgstr "Sélectionnez le fichier à télécharger."
msgid "Resize Volume"
msgstr ""
msgid "Size"
msgstr ""
msgid "The total space which can be used to store data. The unit is megabytes."
msgstr ""
msgid "Ok"
msgstr ""
msgid "Template Name"
msgstr ""
msgid ""
"The name used to identify the template. If omitted, a name will be "
"automatically chosen."
msgstr ""
msgid ""
"When selecting more than one Image Template, a name will be automatically "
"chosen for each Image Template selected."
msgstr ""
msgid "Where is the source media for this template? "
msgstr ""
msgid "Image Template"
msgstr ""
msgid "Netboot Template"
msgstr ""
msgid "File Path:"
msgstr "Chemin d'accès au fichier : "
msgid "Search ISOs"
msgstr "Recherche d'ISO"
msgid "The following ISOs are available:"
msgstr "Les images ISO suivantes sont disponibles :"
msgid "QEMU does not have enough permission to work with this file"
msgstr ""
msgid "Search more ISOs"
msgstr "Rechercher d'autres images ISO"
msgid "Loading..."
msgstr ""
msgid "Edit Template"
msgstr "Editer le modèle"
msgid "CDROM"
msgstr "CD-ROM"
msgid "Image File"
msgstr "Fichier image"
msgid "Graphics"
msgstr "Graphiques"
msgid "Disk(GB)"
msgstr "Disque (Go)"
msgid "Disk Format"
msgstr "Format de disque"
msgid "Add Interface"
msgstr ""
msgid "pool"
msgstr ""
msgid "bridge"
msgstr ""
msgid "vepa"
msgstr ""
msgid "State"
msgstr ""
msgid "Guest Name ID"
msgstr ""
msgid "OS Type"
msgstr ""
msgid "VNC"
msgstr ""
msgid "No guests found."
msgstr ""
msgid "Stop"
msgstr ""
msgid "Location"
msgstr ""
msgid "%Used"
msgstr ""
msgid "Allocated"
msgstr ""
msgid "Capacity"
msgstr ""
msgid "Disks"
msgstr ""
msgid "Extending logical pool"
msgstr ""
msgid "%"
msgstr ""
msgid "Deactivate"
msgstr ""
msgid "Activate"
msgstr ""
msgid "Extend"
msgstr ""
msgid "Undefine"
msgstr ""
msgid "Add Volume"
msgstr ""
msgid "Resize"
msgstr ""
msgid "Wipe"
msgstr ""
msgid "Filter:"
msgstr ""
msgid "Used By"
msgstr ""
msgid "Used"
msgstr ""
msgid "Progress"
msgstr ""
msgid "Used by the following VMs:"
msgstr ""
msgid "Allocation"
msgstr ""
msgid "Template Name (ID)"
msgstr ""
msgid "No templates found."
msgstr ""
msgid "M"
msgstr ""
================================================
FILE: po/gen-pot.in
================================================
#!/bin/bash
#
# Project Kimchi
#
# Copyright IBM Corp, 2013-2016
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
for src in $@; do
if [ ${src: -3} == ".py" ]; then
cat $src
else
cat $src | @CHEETAH@ compile -
fi
done | xgettext --no-location -o kimchi.pot -L Python -
================================================
FILE: po/it_IT.po
================================================
# Italian translations for kimchi package.
# Copyright IBM Corp, 2014-2017
# Adam Litke , 2013.
#
msgid ""
msgstr ""
"Project-Id-Version: kimchi 0.1\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2017-06-30 10:27-0300\n"
"PO-Revision-Date: 2013-07-11 17:32-0400\n"
"Last-Translator: Crístian Viana \n"
"Language-Team: English\n"
"Language: it_IT\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: pygettext.py 1.5\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
#, python-format
msgid "Unknown parameter %(value)s"
msgstr "Parametro sconosciuto %(value)s"
#, python-format
msgid "User %(user_id)s not found with given LDAP settings."
msgstr "Utente %(user_id)s non trovato con le impostazioni LDAP fornite."
#, python-format
msgid "Partition %(name)s does not exist in the host"
msgstr "La partizione %(name)s non esiste nell'host"
#, python-format
msgid "Error while accessing dev mapper device, %(err)s"
msgstr ""
msgid "Block device not found."
msgstr ""
#, python-format
msgid "Block device %(device)s not found."
msgstr ""
#, python-format
msgid "Unable to retrieve LVM information. Details: %(err)s"
msgstr ""
msgid "Unknown \"_cap\" specified"
msgstr "Specificato \"_cap\" sconosciuto"
msgid "\"_passthrough\" should be \"true\" or \"false\""
msgstr "\"_passthrough\" deve essere \"true\" o \"false\""
msgid "\"_passthrough_affected_by\" should be a device name string"
msgstr "\"_passthrough_affected_by\" deve essere una stringa nome dispositivo"
msgid "\"_available_only\" should be \"true\" or \"false\""
msgstr "\"_available_only\" deve essere \"true\" o \"false\""
#, python-format
msgid "Unable to find distro file: %(filename)s"
msgstr "Impossibile trovare il file distro: %(filename)s"
#, python-format
msgid ""
"Unable to parse distro file: %(filename)s. Make sure, it is a JSON file."
msgstr ""
"Impossibile analizzare il file distro: %(filename)s. Verificare che sia un "
"file JSON."
#, python-format
msgid "Unable to login to iSCSI host target %(portal)s. Details: %(err)s"
msgstr ""
"Impossibile accedere alla destinazione host iSCSI %(portal)s. Dettagli: "
"%(err)s"
#, python-format
msgid "Unable to login to iSCSI host %(host)s target %(target)s"
msgstr "Impossibile accedere alla destinazione %(target)s host %(host)s iSCSI"
#, python-format
msgid "Unable to find ISO file %(filename)s"
msgstr "Impossibile trovare il file ISO %(filename)s"
#, python-format
msgid "The ISO file %(filename)s is not bootable"
msgstr "Il file ISO %(filename)s non è avviabile"
#, python-format
msgid "The ISO file %(filename)s does not have a valid El Torito boot record"
msgstr "Il file ISO %(filename)s non ha un record di avvio El Torito valido"
#, python-format
msgid "Invalid El Torito validation entry in ISO %(filename)s"
msgstr "Voce di convalida El Torito non valida in ISO %(filename)s"
#, python-format
msgid "Invalid El Torito boot indicator in ISO %(filename)s"
msgstr "Indicatore di avvio El Torito non valido in ISO %(filename)s"
#, python-format
msgid "Unexpected volume type for primary volume in ISO %(filename)s"
msgstr "Tipo di volume imprevisto per il volume primario in ISO %(filename)s"
#, python-format
msgid "Bad format while reading volume descriptor in ISO %(filename)s"
msgstr ""
"Formato non corretto durante la lettura del descrittore volume in ISO "
"%(filename)s"
#, python-format
msgid ""
"The hypervisor doesn't have permission to use this ISO %(filename)s. "
"Consider moving it under /var/lib/libvirt, or set the search permission to "
"file access control lists for '%(user)s' user if possible, or add the "
"'%(user)s' to the ISO path group, or (not recommended) 'chmod -R o+x "
"'path_to_iso'.Details: %(err)s"
msgstr ""
"L'hypervisor non dispone dell'autorizzazione per utilizzare questo ISO "
"%(filename)s. Spostarlo in /var/lib/libvirt o impostare l'autorizzazione di "
"ricerca sugli elenchi di controllo di accesso file per l'utente '%(user)s' "
"se possibile, oppure aggiungere '%(user)s' al gruppo percorso ISO oppure "
"(non consigliato) 'chmod -R o+x 'path_to_iso'. Dettagli: %(err)s"
#, python-format
msgid "Unable to access remote ISO. Details: %(err)s"
msgstr ""
#, python-format
msgid "Error probing image OS information: %(err)s"
msgstr ""
#, python-format
msgid "Unable to read image file %(filename)s"
msgstr "Impossibile leggere il file immagine %(filename)s"
#, python-format
msgid ""
"Image file must be an existing file on system. %(filename)s is not a valid "
"input."
msgstr ""
"Il file immagine deve essere un file esistente sul sistema. %(filename)s non "
"è un valido input."
#, python-format
msgid "Virtual machine %(name)s already exists"
msgstr "Macchina virtuale %(name)s già esistente"
#, python-format
msgid "Virtual machine %(name)s does not exist"
msgstr "La macchina virtuale %(name)s non esiste"
#, python-format
msgid "Unable to retrieve screenshot for stopped virtual machine %(name)s"
msgstr ""
"Impossibile richiamare l'immagine per la macchina virtuale arrestata %(name)s"
msgid "Remote ISO image is not supported by this server."
msgstr "L'immagine ISO remota non è supportata da questo server."
#, python-format
msgid "Screenshot is not supported on virtual machine %(name)s"
msgstr ""
"L'esecuzione di un'immagine non è supportata sulla macchina virtuale %(name)s"
#, python-format
msgid "Unable to create virtual machine %(name)s. Details: %(err)s"
msgstr "Impossibile creare la macchina virtuale %(name)s. Dettagli: %(err)s"
#, python-format
msgid "Unable to update virtual machine %(name)s. Details: %(err)s"
msgstr ""
"Impossibile aggiornare la macchina virtuale %(name)s. Dettagli: %(err)s"
#, python-format
msgid "Unable to retrieve virtual machine %(name)s. Details: %(err)s"
msgstr ""
"Impossibile richiamare la macchina virtuale %(name)s. Dettagli: %(err)s"
#, python-format
msgid "Unable to connect to powered off virtual machine %(name)s."
msgstr "Impossibile connettere la macchina virtuale %(name)s."
msgid "Virtual machine name must be a string without slashes (/)"
msgstr ""
"Il nome della macchina virtuale deve essere una stringa senza barre (/)"
#, python-format
msgid "Invalid template URI %(value)s specified for virtual machine"
msgstr "URI modello non valido %(value)s specificato per la macchina virtuale"
#, python-format
msgid "Invalid storage pool URI %(value)s specified for virtual machine"
msgstr ""
"URI pool di memoria non valido %(value)s specificato per la macchina virtuale"
msgid "Supported virtual machine graphics are Spice or VNC"
msgstr "I grafici macchina virtuale supportati sono Spice o VNC"
msgid "Graphics address to listen on must be IPv4 or IPv6"
msgstr ""
"L'indirizzo dei grafici su cui rimanere in ascolto deve essere IPv4 o IPv6"
msgid "Specify a template to create a virtual machine from"
msgstr "Specificare un modello da cui creare una macchina virtuale"
#, python-format
msgid "Unable to start virtual machine %(name)s. Details: %(err)s"
msgstr "Impossibile avviare la macchina virtuale %(name)s. Dettagli: %(err)s"
#, python-format
msgid "Unable to power off virtual machine %(name)s. Details: %(err)s"
msgstr "Impossibile spegnere la macchina virtuale %(name)s. Dettagli: %(err)s"
#, python-format
msgid "Unable to delete virtual machine %(name)s. Details: %(err)s"
msgstr "Impossibile eliminare la macchina virtuale %(name)s. Dettagli: %(err)s"
#, python-format
msgid "Unable to reset virtual machine %(name)s. Details: %(err)s"
msgstr ""
"Impossibile reimpostare la macchina virtuale %(name)s. Dettagli: %(err)s"
msgid "User name list must be an array"
msgstr "L'elenco di nomi utente deve essere un array"
msgid "User name must be a string"
msgstr "Il nome utente deve essere una stringa"
msgid "Group name list must be an array"
msgstr "L'elenco di nomi gruppo deve essere un array"
msgid "Group name must be a string"
msgstr "Il nome gruppo deve essere una stringa"
#, python-format
msgid "User(s) '%(users)s' do not exist"
msgstr "L'utente o gli utenti '%(users)s' non esistono"
#, python-format
msgid "Group(s) '%(groups)s' do not exist"
msgstr "Il gruppo o i gruppi '%(groups)s' non esistono"
#, python-format
msgid "Unable to shutdown virtual machine %(name)s. Details: %(err)s"
msgstr "Impossibile arrestare la macchina virtuale %(name)s. Dettagli: %(err)s"
msgid "The guest console password must be a string."
msgstr ""
"La password della console della macchina guest deve essere una stringa."
msgid "The life time for the guest console password must be a number."
msgstr ""
"La durata per la password della console della macchina guest deve essere un "
"numero."
#, python-format
msgid "Virtual machine '%(name)s' must be stopped before cloning it."
msgstr ""
"La macchina virtuale '%(name)s' deve essere arrestata prima di poterla "
"clonare."
#, python-format
msgid "Insufficient disk space to clone virtual machine '%(name)s'"
msgstr ""
"Spazio su disco insufficiente per clonare la macchina virtuale '%(name)s'"
#, python-format
msgid "Unable to clone VM '%(name)s'. Details: %(err)s"
msgstr "Impossibile clonare la VM '%(name)s'. Dettagli: %(err)s"
#, python-format
msgid "Invalid operation for non-persistent virtual machine %(name)s"
msgstr ""
"Operazione non valida per la macchina virtuale non persistente %(name)s"
#, python-format
msgid "Cannot suspend VM '%(name)s' because it is not running."
msgstr "Impossibile sospendere la VM '%(name)s' perché non è in esecuzione."
#, python-format
msgid "Unable to suspend VM '%(name)s'. Details: %(err)s"
msgstr "Impossibile sospendere la VM '%(name)s'. Dettagli: %(err)s"
#, python-format
msgid "Cannot resume VM '%(name)s' because it is not paused."
msgstr "Impossibile riprendere la VM '%(name)s' perché non è in pausa."
#, python-format
msgid "Unable to resume VM '%(name)s'. Details: %(err)s"
msgstr "Impossibile riprendere la VM '%(name)s'. Dettagli: %(err)s"
#, python-format
msgid ""
"Memory assigned is higher then the maximum allowed in the host: "
"%(maxmem)sMib."
msgstr ""
#, python-format
msgid ""
"Guest '%(name)s' does not support live memory update. Please, with the guest "
"offline, set Maximum Memory with a value greater then Memory to enable this "
"feature."
msgstr ""
msgid "Only increase memory is allowed in active VMs"
msgstr "Nelle VM attive è consentito solo aumentare la memoria."
msgid "There are not enough free slots to add a new memory device."
msgstr ""
msgid ""
"Host's libvirt or qemu version does not support memory devices and memory "
"hotplug. Libvirt must be >= 1.2.14 and QEMU must be >= 2.1."
msgstr ""
#, python-format
msgid "Error attaching memory device. Details: %(error)s"
msgstr ""
"Errore durante il collegamento del dispositivo di memoria. Dettagli: "
"%(error)s"
#, python-format
msgid "Cannot start %(name)s. Virtual machine is already running."
msgstr ""
"Impossibile avviare %(name)s. La macchina virtuale è già in esecuzione."
#, python-format
msgid "Cannot power off %(name)s. Virtual machine is shut off."
msgstr "Impossibile spegnere %(name)s. La macchina virtuale è spenta. "
#, python-format
msgid "Cannot shutdown %(name)s. Virtual machine is shut off."
msgstr "Impossibile arrestare %(name)s. La macchina virtuale è spenta. "
#, python-format
msgid "Cannot reset %(name)s. Virtual machine is already shut off."
msgstr "Impossibile reimpostare %(name)s. La macchina virtuale è già spenta. "
msgid "Boot order must be a list. Devices accepted: hd, cdrom, fd or network."
msgstr ""
msgid "Bootmenu must be boolean. Values accepted: true of false."
msgstr ""
msgid "Graphic type not valid. Values accepted: vnc or spice."
msgstr ""
#, python-format
msgid "Migrate to localhost %(host)s is not allowed."
msgstr ""
#, python-format
msgid ""
"To migrate a virtual machine to the remote host %(host)s the user %(user)s "
"must have password-less login to the remote host."
msgstr ""
#, python-format
msgid "Can not migrate virtual machine %(name)s when its in %(state)s state."
msgstr ""
#, python-format
msgid "Failed to migrate virtual machine %(name)s due error: %(err)s"
msgstr ""
msgid "User name of the remote server must be a string."
msgstr ""
msgid "Destination host of the migration must be a string."
msgstr ""
#, python-format
msgid "Unable to create file %(path)s at %(host)s using user %(user)s."
msgstr ""
#, python-format
msgid "Unable to read disk size of %(path)s, error: %(error)s"
msgstr ""
#, python-format
msgid ""
"Unable to create disk image %(path)s at %(host)s using user %(user)s. Error: "
"%(error)s"
msgstr ""
#, python-format
msgid ""
"Unable to migrate virtual machine to remote host %(host)s with arch "
"%(destarch)s using localhost with arch %(srcarch)s."
msgstr ""
#, python-format
msgid ""
"Unable to migrate virtual machine to remote host %(host)s with hypervisor "
"%(desthyp)s because localhost uses hypervisor %(srchyp)s."
msgstr ""
#, python-format
msgid ""
"Unable to determine remote host hypervisor and architecture. Error: %(error)s"
msgstr ""
#, python-format
msgid ""
"Unable to migrate virtual machine: subcores per core setting from "
"localhostand remote host %(host)s differs."
msgstr ""
#, python-format
msgid ""
"Unable to setup password-less login at remote host %(host)s using user "
"%(user)s. Error: %(error)s"
msgstr ""
msgid "Password field must be a string."
msgstr ""
msgid "Error creating local host ssh rsa key of user 'root'."
msgstr ""
#, python-format
msgid "%(param)s value (%(mem)sMiB) must be aligned to %(alignment)sMiB."
msgstr ""
#, python-format
msgid ""
"Unable to update the following parameters while the VM is offline: %(params)s"
msgstr ""
#, python-format
msgid ""
"Unable to update the following parameters while the VM is online: %(params)s"
msgstr ""
#, python-format
msgid ""
"VM %(name)s must have serial and console defined to open a web serial console"
msgstr ""
#, python-format
msgid "Impossible to get the serial console of %(name)s"
msgstr ""
#, python-format
msgid ""
"Memory or Maximum Memory value is higher than amount supported by the host: "
"%(memHost)sMiB."
msgstr ""
#, python-format
msgid ""
"Memory or Maximum Memory value is higher than maximum amount recommended: "
"%(value)sTiB"
msgstr ""
msgid "Cannot update Maximum Memory when guest is running."
msgstr ""
#, python-format
msgid "Impossible to create %(dir)s directory."
msgstr ""
#, python-format
msgid ""
"Either the guest %(name)s did not start to listen to the serial or it is not "
"configured to use the serial console."
msgstr ""
#, python-format
msgid ""
"Unable to retrieve Virt Viewer file for stopped virtual machine %(name)s"
msgstr ""
#, python-format
msgid ""
"Error occured while retrieving the Virt Viewer file for virtual machine "
"%(name)s : %(err)s"
msgstr ""
msgid "Virtual machine title must be a string"
msgstr ""
msgid "Virtual machine description must be a string"
msgstr ""
msgid "console parameter is only supported for s390x/s390 architecture."
msgstr ""
msgid "invalid console type, supported types are sclp/virtio."
msgstr ""
#, python-format
msgid ""
"Unable to setup password-less login at remote host %(host)s using user "
"%(user)s: remote directory %(sshdir)s does not exist."
msgstr ""
#, python-format
msgid ""
"Unable to create a password-less libvirt connection to the remote libvirt "
"daemon at host %(host)s with the user %(user)s. Please verify the remote "
"server libvirt configuration. More information: http://libvirt.org/auth."
"html ."
msgstr ""
msgid "'enable_rdma' must be of type boolean (true or false)."
msgstr ""
#, python-format
msgid ""
"VM %(vmid)s does not contain directly assigned host device %(dev_name)s."
msgstr ""
"La VM %(vmid)s non contiene un dispositivo host assegnato direttamente "
"%(dev_name)s."
#, python-format
msgid "The host device %(dev_name)s is not allowed to directly assign to VM."
msgstr ""
"Il dispositivo host %(dev_name)s non consente di assegnare direttamente al "
"VM."
msgid ""
"No IOMMU groups found. Host PCI pass through needs IOMMU group to function "
"correctly. Please enable Intel VT-d or AMD IOMMU in your BIOS, then verify "
"the Kernel is compiled with IOMMU support. For Intel CPU, add "
"'intel_iommu=on' to GRUB_CMDLINE_LINUX parameter in /etc/default/grub file. "
"For AMD CPU, add 'iommu=pt iommu=1'."
msgstr ""
msgid "\"name\" should be a device name string"
msgstr "\"name\" deve essere una stringa nome dispositivo"
#, python-format
msgid ""
"The device %(name)s is probably in use by the host. Unable to attach it to "
"the guest."
msgstr ""
"Il dispositivo %(name)s è probabilmente utilizzato dall'host. Impossibile "
"collegarlo alla macchina guest."
#, python-format
msgid "Hot-(un)plug of device %(name)s is not supported."
msgstr ""
#, python-format
msgid "Failed to attach %(device)s to %(vm)s"
msgstr ""
#, python-format
msgid "VM %(vmid)s does not have a USB controller to accept PCI hotplug."
msgstr ""
#, python-format
msgid "Interface %(iface)s does not exist in virtual machine %(name)s"
msgstr "L'interfaccia %(iface)s non esiste nella macchina virtuale %(name)s"
#, python-format
msgid ""
"Network %(network)s specified for virtual machine %(name)s does not exist"
msgstr ""
"La rete %(network)s specificata per la macchina virtuale %(name)s non esiste"
msgid ""
"Supported virtual machine interfaces type are network, ovs and macvtap.Type "
"ovs and macvtap are only supported for s390x/s390 architecture."
msgstr ""
msgid "Network name for virtual machine interface must be a string"
msgstr ""
"Il nome di rete per l'interfaccia della macchina virtuale deve essere una "
"stringa"
msgid "Invalid network model card specified for virtual machine interface"
msgstr ""
"Scheda modello di rete non valida per l'interfaccia della macchina virtuale"
msgid "Specify type and network to add a new virtual machine interface"
msgstr ""
"Specificare il tipo e la rete per aggiungere una nuova interfaccia della "
"macchina virtuale"
msgid "MAC Address must respect this format FF:FF:FF:FF:FF:FF"
msgstr "L'indirizzo MAC deve rispettare il formato FF:FF:FF:FF:FF:FF"
#, python-format
msgid "MAC Address %(mac)s already exists in virtual machine %(name)s"
msgstr "L'indirizzo MAC %(mac)s esiste già nella macchina virtuale %(name)s"
msgid "Invalid MAC Address"
msgstr "Indirizzo MAC non valido"
msgid "Cannot change MAC address of a running virtual machine"
msgstr ""
"Impossibile modificare l'indirizzo MAC di una macchina virtuale in esecuzione"
msgid "Type macvtap and ovs are only supported on s390x/s390 architecture."
msgstr ""
msgid "Source attribute is only supported on s390x/s390 architecture."
msgstr ""
msgid "If source is provided, only type supported are macvtap and ovs."
msgstr ""
msgid "For type macvtap and ovs, source has to be provided"
msgstr ""
msgid "Source name for virtual machine interface must be string"
msgstr ""
msgid "Invalid source mode. Valid options are: bridge or vepa."
msgstr ""
#, python-format
msgid "Template %(name)s already exists"
msgstr "Modello %(name)s già esistente"
#, python-format
msgid "Source media %(path)s not found"
msgstr ""
#, python-format
msgid ""
"Network '%(network)s' specified for template %(template)s does not exist"
msgstr ""
"La rete '%(network)s' specificata per il modello %(template)s non esiste"
#, python-format
msgid ""
"Storage pool %(pool)s specified for template %(template)s does not exist"
msgstr ""
"Il pool di memoria %(pool)s specificato per il modello %(template)s non "
"esiste"
#, python-format
msgid "Invalid parameter '%(param)s' specified for CDROM."
msgstr "Parametro non valido '%(param)s' specificato per CDROM."
#, python-format
msgid "Network %(network)s specified for template %(template)s is not active"
msgstr ""
"La rete %(network)s specificata per il modello %(template)s non è attiva"
msgid "Template name must be a string"
msgstr "Il nome del modello deve essere una stringa"
msgid "Template icon must be a path to the image"
msgstr "L'icona del modello deve essere un percorso all'immagine"
msgid "Template distribution must be a string"
msgstr "La distribuzione del modello deve essere una stringa"
msgid "Template distribution version must be a string"
msgstr "La versione della distribuzione del modello deve essere una stringa"
msgid "The number of CPUs must be an integer greater than 0"
msgstr "Il numero di CPU deve essere un numero intero maggiore di 0"
msgid ""
"Amount of memory and maximum memory (MB) must be an integer greater than 512"
msgstr ""
msgid "Template CDROM must be a local or remote ISO file"
msgstr "Il CDROM del modello deve essere un file ISO locale o remoto"
#, python-format
msgid "Invalid storage pool URI %(value)s specified for template"
msgstr "URI pool di memoria non valido %(value)s specificato per il modello"
msgid ""
"Specify a path to source media (ISO, disk or remote ISO) to create a template"
msgstr ""
msgid "All networks for the template must be specified in a list."
msgstr "Tutte le reti per il modello devono essere specificate in un elenco."
msgid "Specify a volume to a template when storage pool is iSCSI or SCSI"
msgstr ""
"Se il pool di memoria è iSCSI o SCSI specificare un volume per un modello"
#, python-format
msgid "The volume %(volume)s is not in storage pool %(pool)s"
msgstr "Il volume %(volume)s non è nel pool di memoria %(pool)s"
#, python-format
msgid "Unable to create template due error: %(err)s"
msgstr "Impossibile creare il modello a causa dell'errore: %(err)s"
#, python-format
msgid "Unable to delete template due error: %(err)s"
msgstr "Impossibile eliminare il modello a causa dell'errore: %(err)s"
msgid "Disk size must be an integer greater than 1GB."
msgstr "La dimensione del disco deve essere un numero intero maggiore di 1GB."
#, python-format
msgid "Cannot identify base image %(path)s format"
msgstr "Impossibile identificare il formato %(path)s dell'immagine di base"
msgid ""
"When specifying CPU topology, each element must be an integer greater than "
"zero."
msgstr ""
"Quando si specifica la topologia CPU, ogni elemento deve essere un numero "
"intero maggiore di zero."
msgid ""
"Invalid disk image format. Valid formats: qcow, qcow2, qed, raw, vmdk, vpc."
msgstr ""
msgid ""
"When setting template disks, following parameters are required: 'index', "
"'pool name', 'format', 'size' or 'volume' (for scsi/iscsi pools)"
msgstr ""
msgid "Disk format must be 'raw', for logical, iscsi, and scsi pools."
msgstr ""
msgid ""
"Memory expects an object with one or both parameters: 'current' and "
"'maxmemory'"
msgstr ""
#, python-format
msgid ""
"Memory value (%(mem)sMiB) must be equal or lesser than maximum memory value "
"(%(maxmem)sMiB)"
msgstr ""
#, python-format
msgid "Unable to update template due error: %(err)s"
msgstr ""
msgid "Parameter 'disks' requires at least one disk object"
msgstr ""
msgid ""
"Invalid interface type. Type should be 'macvtap' for host network interface "
"(Ethernet, Bond, VLAN) to be connected as direct MacVTap or 'ovs' for "
"openvswitch host network interface to be connected as virtual switch to a VM."
msgstr ""
msgid "Interface name should be string."
msgstr ""
msgid "Invalid interface mode. Valid options are: bridge or vepa."
msgstr ""
msgid ""
"Interfaces should be list of interfaces. Each interface should have name, "
"type and mode(optional, only applicable for interfcae type 'macvtap'."
msgstr ""
msgid ""
"Interface expects an object with parameters: 'name', 'type' and 'mode'. Name "
"should be name of host network interface (Ethernet, Bond, VLAN) for type "
"'macvtap' or the name of host openvswitch bridge interface for type 'ovs'. "
"Mode (optional) is only applicable for interface type 'macvtap' to indicates "
"whether packets will be delivered directly to target device (bridge) or to "
"the external bridge (vepa-capable bridge)."
msgstr ""
msgid "Interfaces parameter only supported on s390x or s390 architecture."
msgstr ""
msgid "Storage without libvirt pool is not supported on this architecture"
msgstr ""
#, python-format
msgid "Error while creating the virtual disk for the guest. Details: %(err)s"
msgstr ""
msgid ""
"When setting template disks without libvirt, following parameters are "
"required: 'index', 'format', 'path', 'size'"
msgstr ""
#, python-format
msgid "Storage pool %(name)s already exists"
msgstr "Pool di memoria %(name)s già esistente"
#, python-format
msgid "Storage pool %(name)s does not exist"
msgstr "Il pool di memoria %(name)s non esiste"
#, python-format
msgid "Specify %(item)s in order to create the storage pool %(name)s"
msgstr "Specificare %(item)s per poter creare il pool di memoria %(name)s"
#, python-format
msgid "Unable to delete active storage pool %(name)s"
msgstr "Impossibile eliminare il pool di memoria attivo %(name)s"
#, python-format
msgid "Unable to list storage pools. Details: %(err)s"
msgstr "Impossibile elencare i pool di memoria. Dettagli: %(err)s"
#, python-format
msgid "Unable to create storage pool %(name)s. Details: %(err)s"
msgstr "Impossibile creare il pool di memoria %(name)s. Dettagli: %(err)s"
#, python-format
msgid "Unable to activate storage pool %(name)s. Details: %(err)s"
msgstr "Impossibile attivare il pool di memoria %(name)s. Dettagli: %(err)s"
#, python-format
msgid "Unable to deactivate storage pool %(name)s. Details: %(err)s"
msgstr "Impossibile disattivare il pool di memoria %(name)s. Dettagli: %(err)s"
#, python-format
msgid "Unable to delete storage pool %(name)s. Details: %(err)s"
msgstr "Impossibile eliminare il pool di memoria %(name)s. Dettagli: %(err)s"
#, python-format
msgid ""
"Unable to create NFS Pool as export path %(path)s may block during mount"
msgstr ""
"Impossibile creare il pool NFS poiché il percorso di esportazione %(path)s "
"potrebbe bloccarsi durante il montaggio"
#, python-format
msgid "Unable to create NFS Pool as export path %(path)s mount failed"
msgstr ""
"Impossibile creare il pool NFS poiché il montaggio del percorso di "
"esportazione %(path)s ha avuto esito negativo"
#, python-format
msgid "Unsupported storage pool type: %(type)s"
msgstr "Tipo di pool di memoria non supportato: %(type)s"
#, python-format
msgid "Error while retrieving storage pool XML to %(pool)s"
msgstr "Errore durante il richiamo dell'XML del pool di memoria per %(pool)s"
msgid "Storage pool name must be a string without slashes (/)"
msgstr "Il nome del pool di memoria deve essere una stringa senza barre (/)"
msgid ""
"Supported storage pool types are dir, netfs, logical, iscsi, isci and kimchi-"
"iso"
msgstr ""
"I tipi di pool di memoria supportati sono dir, netfs, logico, iscsi, isci e "
"kimchi-iso"
msgid "Storage pool path must be a string"
msgstr "Il percorso del pool di memoria deve essere una stringa"
msgid "Storage pool host must be a IP or hostname"
msgstr "L'host del pool di memoria deve essere un nome host o IP"
msgid "Storage pool device must be the absolute path to the block device"
msgstr ""
"Il dispositivo pool di memoria deve essere il percorso assoluto al "
"dispositivo del blocco"
msgid "Storage pool devices parameter must be a list"
msgstr "Il parametro dispositivi pool di memoria deve essere un elenco"
msgid "Target IQN of an iSCSI pool must be a string"
msgstr "L'IQN di destinazione di un pool iSCSI deve essere una stringa"
msgid "Port of a remote storage server must be an integer between 1 and 65535"
msgstr ""
"La porta di un server di memoria remoto deve essere un numero intero tra 1 e "
"65535"
msgid "iSCSI target username must be a string"
msgstr "Il nome utente della destinazione iSCSI deve essere una stringa"
msgid "iSCSI target password must be a string"
msgstr "La password della destinazione iSCSI deve essere una stringa"
msgid "Specify name and type to create a storage pool"
msgstr "Specificare nome e tipo per creare un pool di memoria"
#, python-format
msgid ""
"%(disk)s is not a valid disk/partition. Could not add it to the pool "
"%(pool)s."
msgstr ""
"%(disk)s non è un disco/partizione valido. Impossibile aggiungerlo al pool "
"%(pool)s."
#, python-format
msgid "Unable to extend logical pool %(pool)s. Details: %(err)s"
msgstr "Impossibile estendere il pool logico %(pool)s. Dettagli: %(err)s"
msgid "The parameter disks only can be updated for logical storage pool."
msgstr ""
"Solo il parametro dischi può essere aggiornato per il pool di memoria logico."
msgid "The SCSI host adapter name must be a string."
msgstr "Il nome adattatore host SCSI deve essere una stringa."
msgid "The storage pool kimchi_isos is reserved for internal use"
msgstr "Il pool di memoria kimchi_isos è riservato per uso interno"
#, python-format
msgid ""
"Unable to activate NFS storage pool %(name)s. NFS server %(server)s is "
"unreachable."
msgstr ""
"Impossibile attivare il pool di memoria NFS %(name)s. Il server NFS "
"%(server)s è irraggiungibile."
#, python-format
msgid ""
"Unable to deactivate NFS storage pool %(name)s. NFS server %(server)s is "
"unreachable."
msgstr ""
"Impossibile disattivare il pool di memoria NFS %(name)s. Il server NFS "
"%(server)s è irraggiungibile."
#, python-format
msgid ""
"Unable to deactivate pool %(name)s as it is associated with some templates"
msgstr ""
"Impossibile disattivare il pool %(name)s poiché è associato ad alcuni modelli"
#, python-format
msgid "Unable to delete pool %(name)s as it is associated with some templates"
msgstr ""
"Impossibile eliminare il pool %(name)s poiché è associato ad alcuni modelli"
#, python-format
msgid ""
"A volume group named '%(name)s' already exists. Please, choose another name "
"to create the logical pool."
msgstr ""
"Un gruppo di volumi denominato '%(name)s' esiste già. Scegliere un altro "
"nome per creare il pool logico."
#, python-format
msgid "Unable to update database with deep scan information due error: %(err)s"
msgstr ""
"Impossibile aggiornare il database con informazioni approfondite sulla "
"scansione a causa dell'errore: %(err)s"
#, python-format
msgid ""
"No volume group '%(name)s' found. Please, specify an existing volume group "
"to create the logical pool from."
msgstr ""
#, python-format
msgid "Unable to delete pool %(name)s as it is associated with guests: %(vms)s"
msgstr ""
#, python-format
msgid "Storage volume %(name)s already exists"
msgstr "Volume di memoria %(name)s già esistente"
#, python-format
msgid "Storage volume %(name)s does not exist in storage pool %(pool)s"
msgstr "Il volume di memoria %(name)s non esiste nel pool di memoria %(pool)s"
#, python-format
msgid ""
"Unable to create storage volume %(volume)s because storage pool %(pool)s is "
"not active"
msgstr ""
"Impossibile creare il volume di memoria %(volume)s perché il pool di memoria "
"%(pool)s non è attivo"
#, python-format
msgid "Specify %(item)s in order to create storage volume %(volume)s"
msgstr "Specificare %(item)s per poter creare il volume di memoria %(volume)s"
#, python-format
msgid ""
"Unable to list storage volumes because storage pool %(pool)s is not active"
msgstr ""
"Impossibile elencare i volumi di memoria poiché il pool di memoria %(pool)s "
"non è attivo"
#, python-format
msgid ""
"Unable to create storage volume %(name)s in storage pool %(pool)s. Details: "
"%(err)s"
msgstr ""
"Impossibile creare il volume di memoria %(name)s nel pool di memoria "
"%(pool)s. Dettagli: %(err)s"
#, python-format
msgid "Unable to wipe storage volumes %(name)s. Details: %(err)s"
msgstr "Impossibile ripulire i volumi di memoria %(name)s. Dettagli: %(err)s"
#, python-format
msgid "Unable to delete storage volume %(name)s. Details: %(err)s"
msgstr "Impossibile eliminare il volume di memoria %(name)s. Dettagli: %(err)s"
#, python-format
msgid "Unable to resize storage volume %(name)s. Details: %(err)s"
msgstr ""
"Impossibile ridimensionare il volume di memoria %(name)s. Dettagli: %(err)s"
#, python-format
msgid "Storage type %(type)s does not support volume create and delete"
msgstr ""
"Il tipo di memoria %(type)s non supporta la creazione ed eliminazione del "
"volume"
msgid "Storage volume name must be a string"
msgstr "Il nome del volume di memoria deve essere una stringa"
msgid "Storage volume allocation must be an integer number"
msgstr "L'assegnazione del volume di memoria deve essere un numero intero"
msgid ""
"Storage volume format not supported. Valid formats: qcow, qcow2, qed, raw, "
"vmdk, vpc."
msgstr ""
msgid "Storage volume requires a volume name"
msgstr "Il volume di memoria richiede un nome volume"
#, python-format
msgid ""
"Unable to update database with storage volume information due error: %(err)s"
msgstr ""
"Impossibile aggiornare il database con informazioni sul volume di memoria a "
"causa dell'errore: %(err)s"
#, python-format
msgid "Only one of parameter %(param)s can be specified"
msgstr "È possibile specificare solo un parametro %(param)s"
#, python-format
msgid "Create volume from %(param)s is not supported"
msgstr "La creazione del volume da %(param)s non è supportata"
msgid "Storage volume capacity must be an integer number."
msgstr "La capacità del volume di memoria deve essere un numero intero."
msgid "Storage volume URL must be http://, https://, ftp:// or ftps://."
msgstr ""
"L'URL del volume di memoria deve essere http://, https://, ftp:// o ftps://."
#, python-format
msgid "Unable to access file %(url)s. Please, check it."
msgstr "Impossibile accedere al file %(url)s. Verificare."
#, python-format
msgid ""
"Unable to clone storage volume '%(name)s' in pool '%(pool)s'. Details: "
"%(err)s"
msgstr ""
"Impossibile clonare il volume di memoria '%(name)s' nel pool '%(pool)s'. "
"Dettagli: %(err)s"
msgid "Specify chunk data and its size to upload a file."
msgstr "Specificare dati sezione e dimensioni per caricare un file."
msgid "In order to upload a storage volume, specify the 'upload' parameter."
msgstr "Per caricare un volume di memoria, specificare il parametro 'upload'."
msgid ""
"Unable to upload chunk data as it does not match with requested chunk size."
msgstr ""
"Impossibile caricare i dati sezione perché non corrispondono con la "
"dimensione sezione richiesta."
#, python-format
msgid "The storage volume %(vol)s is not under an upload process."
msgstr ""
"Il volume di memoria %(vol)s non è sottoposto a un processo di caricamento."
msgid "The upload chunk data will exceed the storage volume size."
msgstr ""
"I dati sezione da caricare supereranno la dimensione del volume di memoria."
#, python-format
msgid "Unable to upload chunk data to storage volume. Details: %(err)s."
msgstr ""
"Impossibile caricare i dati sezione nel volume di memoria. Dettagli: %(err)s."
#, python-format
msgid "Interface %(name)s does not exist"
msgstr "L'interfaccia %(name)s non esiste"
#, python-format
msgid ""
"Failed to list interfaces. Invalid _inuse parameter. Supported options for "
"_inuse are: %(supported_inuse)s"
msgstr ""
#, python-format
msgid "Network %(name)s already exists"
msgstr "Rete %(name)s già esistente"
#, python-format
msgid "Network %(name)s does not exist"
msgstr "La rete %(name)s non esiste"
#, python-format
msgid "Subnet %(subnet)s specified for network %(network)s is not valid."
msgstr ""
msgid "Specify a network interface to create bridged or macvtap networks."
msgstr ""
#, python-format
msgid "Unable to delete or update active network %(name)s"
msgstr ""
#, python-format
msgid "Interface %(iface)s specified for network %(network)s is already in use"
msgstr ""
"L'interfaccia %(iface)s specificata per la rete %(network)s è già in uso"
msgid "Interface should be bare NIC, bonding or bridge device."
msgstr ""
"L'interfaccia deve essere un dispositivo bridge o di collegamento NIC bare-"
"metal."
#, python-format
msgid "Unable to create or update network %(name)s. Details: %(err)s"
msgstr ""
#, python-format
msgid "Unable to find a free IP address for network '%(name)s'"
msgstr "Impossibile trovare un indirizzo IP libero per la rete '%(name)s'"
#, python-format
msgid "The interface %(iface)s already exists."
msgstr "Interfaccia %(iface)s già esistente."
msgid "Network name must be a string without slashes (/) or quotes (\")"
msgstr ""
"Il nome della rete deve essere una stringa senza barre (/) o virgolette (\")"
msgid ""
"Supported network types are isolated, NAT, macvtap, bridge, vepa and "
"passthrough."
msgstr ""
msgid "Network subnet must be a string with IP address and prefix or netmask"
msgstr ""
"La sottorete della rete deve essere una stringa con indirizzo IP e prefisso "
"o maschera di rete"
msgid "Network interfaces must be an array."
msgstr ""
msgid "Network VLAN ID must be an integer between 1 and 4094"
msgstr "L'ID VLAN di rete deve essere un numero intero tra 1 e 4094"
msgid "Specify name and type to create a Network"
msgstr "Specificare nome e tipo per creare una rete"
#, python-format
msgid ""
"Unable to delete or update network %(name)s as it is linked to some virtual "
"machines (%(vms)s) and/or templates (%(tmpls)s)."
msgstr ""
#, python-format
msgid ""
"Unable to deactivate network %(name)s as it is linked to are some virtual "
"machines (%(vms)s) and/or templates (%(tmpls)s)."
msgstr ""
#, python-format
msgid "Bridge device %(name)s can not be the trunk device of a VLAN."
msgstr ""
"Il dispositivo bridge %(name)s non può essere il dispositivo trunk di una "
"VLAN."
#, python-format
msgid "Failed to activate interface %(iface)s: %(err)s."
msgstr "Impossibile attivare l'interfaccia %(iface)s: %(err)s."
#, python-format
msgid ""
"Failed to activate interface %(iface)s. Please check the physical link "
"status."
msgstr ""
"Impossibile attivare l'interfaccia %(iface)s. Controllare lo stato del link "
"fisico."
#, python-format
msgid "Failed to start network %(name)s. Details: %(err)s"
msgstr "Impossibile avviare la rete %(name)s. Dettagli: %(err)s"
#, python-format
msgid "Unable to redefine interface %(name)s. Details: %(err)s"
msgstr ""
#, python-format
msgid "Unable to create bridge %(name)s. Details: %(err)s"
msgstr ""
msgid ""
"Unable to create bridge with NetworkManager enabled. Disable it and try "
"again."
msgstr ""
msgid "Interface should be bare NIC or bonding."
msgstr ""
msgid "Network interfaces parameter must contain at least one interface."
msgstr ""
msgid "Only one interface is allowed for 'bridge' and 'macvtap' networks."
msgstr ""
msgid "Subnet is not a valid parameter for this type of virtual network."
msgstr ""
msgid ""
"VLAN ID and interfaces are not valid parameters for this type of virtual "
"network."
msgstr ""
#, python-format
msgid "Storage server %(server)s was not used by Kimchi"
msgstr "Il server di memoria %(server)s non è stato utilizzato da Kimchi"
#, python-format
msgid "Distro '%(name)s' does not exist"
msgstr "Distro '%(name)s' non esistente"
#, python-format
msgid "Node device '%(name)s' not found"
msgstr "Dispositivo nodo '%(name)s' non trovato"
msgid "Conflicting flag filters specified."
msgstr "Sono stati specificati dei filtri indicatore in conflitto."
msgid "Unable to choose a virtual machine name"
msgstr "Impossibile scegliere un nome di macchina virtuale"
msgid "Cannot upgrade objectstore data."
msgstr ""
msgid "Invalid storage type. Types supported: 'cdrom', 'disk'"
msgstr "Tipo di memoria non valido. Tipi supportati: 'cdrom', 'disk'"
#, python-format
msgid "The path '%(value)s' is not a valid local/remote path for the device"
msgstr ""
"Il percorso '%(value)s' non è un percorso locale/remoto valido per il "
"dispositivo"
msgid "Only CDROM path can be update."
msgstr "È possibile aggiornare solo il percorso CDROM."
#, python-format
msgid ""
"The storage device %(dev_name)s does not exist in the virtual machine "
"%(vm_name)s"
msgstr ""
"Il dispositivo di memoria %(dev_name)s non esiste nella macchina virtuale "
"%(vm_name)s"
#, python-format
msgid "Error while creating new storage device: %(error)s"
msgstr ""
"Errore durante la creazione del nuovo dispositivo di memoria: %(error)s"
#, python-format
msgid "Error while updating storage device: %(error)s"
msgstr "Errore durante l'aggiornamento del dispositivo di memoria: %(error)s"
#, python-format
msgid "Error while removing storage device: %(error)s"
msgstr "Errore durante la rimozione del dispositivo di memoria: %(error)s"
msgid "Do not support IDE device hot plug"
msgstr "Non supportare hot plug dispositivo IDE"
msgid ""
"Specify type and path or type and pool/volume to add a new virtual machine "
"disk"
msgstr ""
"Specificare il tipo e il percorso oppure il tipo e il pool/volume per "
"aggiungere un nuovo disco di macchina virtuale"
msgid "Specify path to update virtual machine disk"
msgstr ""
"Specificare il percorso per aggiornare il disco della macchina virtuale"
#, python-format
msgid "Controller type %(type)s limitation of %(limit)s devices reached"
msgstr ""
"Il tipo di controller %(type)s ha raggiunto il limite di %(limit)s "
"dispositivi"
#, python-format
msgid "Cannot retrieve disk path information for given pool/volume: %(error)s"
msgstr ""
"Impossibile richiamare le informazioni del percorso disco per il pool/volume "
"fornito: %(error)s"
msgid "Volume already in use by other virtual machine."
msgstr "Il volume è già utilizzato da un'altra macchina virtuale."
msgid ""
"Only one of path or pool/volume can be specified to add a new virtual "
"machine disk"
msgstr ""
"È possibile specificare solo uno tra percorso o pool/volume per aggiungere "
"un nuovo disco di macchina virtuale"
#, python-format
msgid ""
"Volume chosen with format %(format)s does not fit in the storage type "
"%(type)s"
msgstr ""
"Il volume scelto con il formato %(format)s non si adatta nel tipo di memoria "
"%(type)s"
msgid "On s390x arch one of pool, path of dir_path must be specified"
msgstr ""
msgid ""
"On s390x arch 'format' must be specified while attaching disk to virtual "
"machine"
msgstr ""
#, python-format
msgid "Virtual disk already exists on the system: %(disk_path)s"
msgstr ""
#, python-format
msgid ""
"Unable to create snapshot '%(name)s' on virtual machine '%(vm)s'. Details: "
"%(err)s"
msgstr ""
"Impossibile creare l'istantanea '%(name)s' sulla macchina virtuale '%(vm)s'. "
"Dettagli: %(err)s"
#, python-format
msgid "Snapshot '%(name)s' does not exist on virtual machine '%(vm)s'."
msgstr "L'istantanea '%(name)s' non esiste sulla macchina virtuale '%(vm)s'."
#, python-format
msgid ""
"Unable to retrieve snapshot '%(name)s' on virtual machine '%(vm)s'. Details: "
"%(err)s"
msgstr ""
"Impossibile richiamare l'istantanea '%(name)s' sulla macchina virtuale "
"'%(vm)s'. Dettagli: %(err)s"
#, python-format
msgid "Unable to list snapshots on virtual machine '%(vm)s'. Details: %(err)s"
msgstr ""
"Impossibile elencare le istantanee sulla macchina virtuale '%(vm)s'. "
"Dettagli: %(err)s"
#, python-format
msgid ""
"Unable to delete snapshot '%(name)s' on virtual machine '%(vm)s'. Details: "
"%(err)s"
msgstr ""
"Impossibile eliminare l'istantanea '%(name)s' sulla macchina virtuale "
"'%(vm)s'. Dettagli: %(err)s"
#, python-format
msgid ""
"Unable to retrieve current snapshot of virtual machine '%(vm)s'. Details: "
"%(err)s"
msgstr ""
"Impossibile richiamare l'istantanea corrente sulla macchina virtuale "
"'%(vm)s'. Dettagli: %(err)s"
#, python-format
msgid ""
"Unable to revert virtual machine '%(vm)s' to snapshot '%(name)s'. Details: "
"%(err)s"
msgstr ""
"Impossibile invertire la macchina virtuale '%(vm)s' alla istantanea "
"'%(name)s'. Dettagli: %(err)s"
#, python-format
msgid ""
"Unable to create snapshot of virtual machine '%(vm)s' because it contains a "
"disk with format '%(format)s'; only 'qcow2' is supported."
msgstr ""
"Impossibile creare l'istantanea della macchina virtuale '%(vm)s' perché "
"contiene un disco con formato '%(format)s'; solo 'qcow2' è supportato."
msgid ""
"The number of vCPUs must be less than or equal the maximum number of vCPUs "
"specified."
msgstr ""
msgid ""
"When CPU topology is defined, maximum number of vCPUs must be a product of "
"sockets, cores, and threads."
msgstr ""
msgid "This host (or current configuration) does not allow CPU topology."
msgstr "Questo host (o configurazione corrente) non consente la topologia CPU."
msgid "The maximum number of vCPUs is too large for this system."
msgstr ""
msgid ""
"When CPU topology is defined, CPUs must be a multiple of the 'threads' "
"number defined."
msgstr ""
msgid ""
"When CPU topology is specified, sockets, cores and threads are required "
"paramaters."
msgstr ""
msgid ""
"Parameter 'cpu_info' expects an object with fields among: 'vcpus', "
"'maxvcpus', 'topology'."
msgstr ""
msgid ""
"Parameter 'topology' expects an object with fields among: 'sockets', "
"'cores', 'threads'."
msgstr ""
msgid "Unable to update Max CPU or CPU topology when guest is running."
msgstr ""
#, python-format
msgid "Unable to hot plug/unplug CPUs. Details: %(err)s"
msgstr ""
#, python-format
msgid "Invalid volume group name parameter: %(name)s."
msgstr ""
msgid ""
"Unable to establish connection with libvirt. Please check your libvirt URI "
"which is often defined in /etc/libvirt/libvirt.conf"
msgstr ""
msgid ""
"Libvirt service is not active. Please start the libvirt service in your host "
"system."
msgstr ""
msgid "Failed to register the default event implementation."
msgstr ""
msgid "Failed to register timeout event."
msgstr ""
msgid "Failed to Run the default event implementation."
msgstr ""
#, python-format
msgid ""
"I/O error on guest '%(vm)s': storage pool out of space for %(devAlias)s "
"(%(srcPath)s)."
msgstr ""
#, python-format
msgid "Create virtual network '%(name)s' type '%(connection)s'"
msgstr ""
#, python-format
msgid "Remove virtual network '%(ident)s'"
msgstr ""
#, python-format
msgid "Update virtual network '%(ident)s'"
msgstr ""
#, python-format
msgid "Activate virtual network '%(ident)s'"
msgstr ""
#, python-format
msgid "Deactivate virtual network '%(ident)s'"
msgstr ""
#, python-format
msgid "Create storage pool '%(name)s' type '%(type)s'"
msgstr ""
#, python-format
msgid "Remove storage pool '%(ident)s'"
msgstr ""
#, python-format
msgid "Update storage pool '%(ident)s'"
msgstr ""
#, python-format
msgid "Activate storage pool '%(ident)s'"
msgstr ""
#, python-format
msgid "Deactivate storage pool '%(ident)s'"
msgstr ""
#, python-format
msgid "Create snapshot '%(name)s' at guest '%(vm)s'"
msgstr ""
#, python-format
msgid "Remove snapshot '%(ident)s' from guest '%(vm)s'"
msgstr ""
#, python-format
msgid "Revert guest '%(vm)s' to snapshot '%(ident)s'"
msgstr ""
#, python-format
msgid "Create template '%(name)s'"
msgstr ""
#, python-format
msgid "Remove template '%(ident)s'"
msgstr ""
#, python-format
msgid "Update template '%(ident)s'"
msgstr ""
#, python-format
msgid "Clone template '%(ident)s'"
msgstr ""
#, python-format
msgid "Create guest '%(name)s' from template '%(template)s'"
msgstr ""
#, python-format
msgid "Remove guest '%(ident)s'"
msgstr ""
#, python-format
msgid "Edit guest '%(ident)s'"
msgstr ""
#, python-format
msgid "Start guest '%(ident)s'"
msgstr ""
#, python-format
msgid "Power off guest '%(ident)s'"
msgstr ""
#, python-format
msgid "Shutdown guest '%(ident)s'"
msgstr ""
#, python-format
msgid "Restart guest '%(ident)s'"
msgstr ""
#, python-format
msgid "Connect to guest '%(ident)s' through novnc/spice"
msgstr ""
#, python-format
msgid "Clone guest '%(ident)s'"
msgstr ""
#, python-format
msgid "Migrate guest '%(ident)s' to '%(remote_host)s'"
msgstr ""
#, python-format
msgid "Suspend guest '%(ident)s'"
msgstr ""
#, python-format
msgid "Resume guest '%(ident)s'"
msgstr ""
#, python-format
msgid "Connect to guest '%(ident)s' through serial"
msgstr ""
#, python-format
msgid "Attach host device '%(name)s' to guest '%(vmid)s'"
msgstr ""
#, python-format
msgid "Detach host device '%(ident)s' from guest '%(vmid)s'"
msgstr ""
#, python-format
msgid "Attach network interface '%(network)s' to guest '%(vm)s'"
msgstr ""
#, python-format
msgid "Detach network interface '%(ident)s' from guest '%(vm)s'"
msgstr ""
#, python-format
msgid "Update network interface '%(ident)s' at guest '%(vm)s'"
msgstr ""
#, python-format
msgid "Attach %(type)s storage '%(path)s' to guest '%(vm)s'"
msgstr ""
#, python-format
msgid "Remove storage '%(ident)s' from guest '%(vm)s'"
msgstr ""
#, python-format
msgid "Update storage '%(ident)s' at guest '%(vm)s'"
msgstr ""
#, python-format
msgid "Create storage volume '%(name)s' at pool '%(pool)s'"
msgstr ""
#, python-format
msgid "Remove storage volume '%(ident)s' from pool '%(pool)s'"
msgstr ""
#, python-format
msgid "Update storage volume '%(ident)s' at pool '%(pool)s'"
msgstr ""
#, python-format
msgid "Wipe storage volume '%(ident)s' off pool '%(pool)s'"
msgstr ""
#, python-format
msgid "Resize storage volume '%(ident)s' at pool '%(pool)s' with size %(size)s"
msgstr ""
#, python-format
msgid "Clone storage volume '%(ident)s' at pool '%(pool)s'"
msgstr ""
msgid "Create a New Virtual Machine"
msgstr "Crea una nuova macchina virtuale"
msgid "Virtual Machine Name"
msgstr "Nome macchina virtuale"
msgid ""
"The name used to identify the virtual machine. If omitted, a name will be "
"chosen based on the template used."
msgstr ""
"Il nome utilizzato per identificare la macchina virtuale. Se il nome viene "
"omesso ne verrà scelto uno in base al modello utilizzato."
msgid "Please create a template first."
msgstr "Creare prima un modello."
msgid "Create a Template"
msgstr "Crea un modello"
msgid "Please choose a template."
msgstr "Scegliere un modello."
msgid "This template has invalid parameters."
msgstr ""
msgid "This template has invalid parameters"
msgstr ""
msgid "OS"
msgstr "SO"
msgid "Version"
msgstr "Versione"
msgid "Current CPUs"
msgstr ""
msgid "Memory"
msgstr "Memoria"
msgid "Create"
msgstr "Crea"
msgid "Creating..."
msgstr "Creazione..."
msgid "Cancel"
msgstr "Annulla"
msgid "Clone a Guest"
msgstr ""
msgid ""
"When the target guest has SCSI or iSCSI volumes, they will be cloned on the "
"default storage pool. The same will happen when the target pool does not "
"have enough space to clone the volumes. Do you want to continue?"
msgstr ""
msgid "Number of times to clone"
msgstr ""
msgid "Continue"
msgstr ""
msgid "Edit Guest"
msgstr "Modifica macchina guest"
msgid "General"
msgstr "Generale"
msgid "Storage"
msgstr "Memoria"
msgid "Interface"
msgstr "Interfaccia"
msgid "Permission"
msgstr ""
msgid "Pci"
msgstr ""
msgid "Snapshot"
msgstr ""
msgid "Processor"
msgstr "Processore"
msgid "Name"
msgstr "Nome"
msgid "Memory (MB)"
msgstr "Memoria (MB)"
msgid "More"
msgstr ""
msgid "Max Memory (MB)"
msgstr ""
msgid "Host does not support memory hotplug"
msgstr ""
msgid "Icon"
msgstr "Icona"
msgid "Console"
msgstr ""
msgid "Nothing selected"
msgstr ""
msgid "sclp"
msgstr ""
msgid "virtio"
msgstr ""
msgid ""
"Select which items for boot order and grad them when needed to order them. "
"At least one option must be selected."
msgstr ""
msgid "Add"
msgstr "Aggiungi"
msgid "Device"
msgstr "Dispositivo"
msgid "Path"
msgstr "Percorso"
msgid "Actions"
msgstr "Azioni"
msgid "Network"
msgstr "Rete"
msgid "Type"
msgstr "Tipo"
msgid "MAC Address"
msgstr "Indirizzo MAC"
msgid "IP Address"
msgstr ""
msgid "Network/Interface"
msgstr ""
msgid "Mode"
msgstr ""
msgid "Available system users and groups"
msgstr "Utenti e gruppi di sistema disponibili"
msgid "Users"
msgstr "Utenti"
msgid "Groups"
msgstr "Gruppi"
msgid "Selected system users and groups"
msgstr "Utenti e gruppi di sistema selezionati"
msgid "User"
msgstr "Utente"
msgid "All"
msgstr "Tutti"
msgid "To Add"
msgstr "Da aggiungere"
msgid "Added"
msgstr "Aggiunto"
msgid "Filter"
msgstr ""
msgid "Status"
msgstr ""
msgid "Product"
msgstr "Prodotto"
msgid "Vendor"
msgstr "Fornitore"
msgid "Loading"
msgstr ""
msgid "Created"
msgstr "Creato"
msgid "Current CPU Number"
msgstr ""
msgid ""
"Current CPU must be equal or lower than the Maximum CPU value. If a topology "
"is set, it must be also be a multiple of the 'threads' value."
msgstr ""
msgid "Max CPU"
msgstr ""
msgid ""
"Unable to edit maximum CPU or CPU topology when editing a running or paused "
"virtual machine."
msgstr ""
msgid ""
"If a topology is set, this value will be the product of sockets * times * "
"cores."
msgstr ""
msgid "Manually set CPU topology"
msgstr "Imposta manualmente la topologia CPU"
msgid "Sockets"
msgstr ""
msgid "Cores"
msgstr "Core"
msgid "Threads"
msgstr "Thread"
msgid "Save"
msgstr "Salva"
msgid "Replace"
msgstr "Sostituisci"
msgid "Detach"
msgstr "Scollega"
msgid "Remove"
msgstr "Rimuovi"
msgid "Edit"
msgstr "Modifica"
msgid "LDAP User ID,e.g.foo@foo.com"
msgstr "ID utente LDAP, ad esempio foo@foo.com"
msgid "Revert"
msgstr ""
msgid "Running"
msgstr ""
msgid "Disconnected"
msgstr ""
msgid "Starting"
msgstr ""
msgid "Crashed"
msgstr ""
msgid "Unknown"
msgstr ""
msgid "Paused"
msgstr ""
msgid "Suspended"
msgstr ""
msgid "Resetting"
msgstr ""
msgid "View Console"
msgstr ""
msgid "View Serial"
msgstr ""
msgid "Clone"
msgstr "Clona"
msgid "Migrate"
msgstr ""
msgid "Reset"
msgstr "Reimposta"
msgid "Pause"
msgstr "In pausa"
msgid "Resume"
msgstr "Riprendi"
msgid "Shut Down"
msgstr "Arresta"
msgid "Start"
msgstr "Avvia"
msgid "Power Off"
msgstr "Spegni"
msgid "Delete"
msgstr "Elimina"
msgid "No Data Available"
msgstr ""
msgid "Processors Utilization"
msgstr ""
msgid "Memory Utilization"
msgstr ""
msgid "Storage I/O"
msgstr ""
msgid "Network I/O"
msgstr "I/O di rete"
msgid "Migrate a Guest"
msgstr ""
msgid ""
"Disclaimer: This process cannot be stopped after started, can take a long "
"time to complete and will turn off the VM on this Hypervisor when it is "
"successfully migrated to the remote destination."
msgstr ""
msgid "Remote Server"
msgstr ""
msgid "IP Address or Hostname"
msgstr ""
msgid ""
"The following fields are optional. Fill them if you want Kimchi to setup a "
"password-less ssh session between the localhost and the remote host. The "
"setup process will only be successful if the user has 'SUDO ALL' permission "
"in the remote machine."
msgstr ""
msgid "Username of the remote host"
msgstr ""
msgid "Password"
msgstr "Password"
msgid "Password of the user in the remote host"
msgstr ""
msgid "Use RDMA transport"
msgstr ""
msgid ""
"Check this option only if RDMA is properly configured in both source and "
"destination hosts, otherwise migration will fail."
msgstr ""
msgid "Delete this VM when the migration is completed"
msgstr ""
msgid "Add a Storage Device to VM"
msgstr "Aggiungi un dispositivo di memoria alla VM"
msgid "Device Type"
msgstr "Tipo dispositivo"
msgid ""
"The device type. Currently, \"cdrom\" and \"disk\" are supported. If the "
"guest is running, only \"disk\" is supported."
msgstr ""
msgid "Create a new disk"
msgstr ""
msgid "Select an existing disk"
msgstr ""
msgid "Source"
msgstr ""
msgid "Storage based on Libvirt pool or direct block device"
msgstr ""
msgid "Storage Pool"
msgstr "Pool di memoria"
msgid "Storage pool to create the volume in"
msgstr ""
msgid "Disk Size (GB)"
msgstr ""
msgid "New disk size to be created"
msgstr ""
msgid "Format"
msgstr ""
msgid "Format of the new disk to be created"
msgstr ""
msgid "Directory Path"
msgstr ""
msgid "Provide a directory path"
msgstr ""
msgid "Storage pool in which the volume is located in"
msgstr ""
msgid "Storage Volume"
msgstr "Volume di memoria"
msgid "Storage volume to be attached"
msgstr "Volume di memoria oggetto del collegamento"
msgid "Disk Path"
msgstr ""
msgid "Provide a block device"
msgstr ""
msgid "File Path"
msgstr "Percorso file"
msgid "The ISO file path in the server for CDROM."
msgstr "Il percorso file ISO nel server per CDROM."
msgid "Attach"
msgstr "Allega"
msgid "Host"
msgstr "Host"
msgid "Guests"
msgstr "Guest"
msgid "Templates"
msgstr "Modelli"
msgid "This is not a valid Linux path"
msgstr "Non è un percorso Linux valido"
msgid "Unable to read file."
msgstr "Impossibile leggere il file."
msgid "Error while uploading file."
msgstr "Errore durante il caricamento del file."
msgid "Delete Confirmation"
msgstr "Conferma eliminazione"
msgid "OK"
msgstr "OK"
msgid "Confirm"
msgstr "Conferma"
msgid "Warning"
msgstr "Avvertenza"
msgid "Cloning..."
msgstr "Clonazione..."
msgid "Saving..."
msgstr ""
msgid "Migrating..."
msgstr ""
msgid "No ISO found"
msgstr "Nessun file ISO trovato"
msgid "Add Template"
msgstr "Aggiungi modello"
msgid "This may take a long time. Do you want to continue?"
msgstr "Questa operazione può richiedere del tempo. Si desidera continuare?"
msgid ""
"This will permanently delete the %1 template. Would you like to continue?"
msgstr ""
msgid "View Table"
msgstr ""
msgid "View Gallery"
msgstr ""
msgid "Not Available"
msgstr ""
msgid "Please check the invalid Storage Pools"
msgstr ""
msgid "Please check the invalid Storage Pools or Paths"
msgstr ""
msgid "macvtap"
msgstr ""
msgid "ovs"
msgstr ""
msgid "network"
msgstr ""
msgid ""
"This will delete the %1 virtual machine and its virtual disks. This "
"operation cannot be undone. Would you like to continue?"
msgstr ""
msgid "Power off Confirmation"
msgstr "Conferma spegnimento"
msgid ""
"This action may produce undesirable results, for example unflushed disk "
"cache in the %1 guest. Would you like to continue?"
msgstr ""
msgid "Reset Confirmation"
msgstr "Conferma reimpostazione"
msgid ""
"There is a risk of data loss caused by reset without the %1 guest OS "
"shutdown. Would you like to continue?"
msgstr ""
msgid "Shut Down Confirmation"
msgstr "Conferma dell'arresto"
msgid ""
"Note the %1 guest OS may ignore this request. Would you like to continue?"
msgstr ""
msgid "Virtual Machine delete Confirmation"
msgstr "Conferma di eliminazione della macchina virtuale"
msgid ""
"The %1 virtual machine is not persistent. Power Off will delete it. Continue?"
msgstr ""
msgid "Add Guest"
msgstr ""
msgid "Input is not a number"
msgstr ""
msgid "Memory value cannot be higher than Max Memory value"
msgstr ""
msgid ""
"For better performance it is recommended a threads per core value not "
"greater than %1."
msgstr ""
msgid ""
"This CDROM will be detached permanently and you can re-attach it. Continue "
"to detach it?"
msgstr ""
"Il CDROM verrà scollegato permanentemente e non sarà possibile ricollegarlo. "
"Continuare con lo scollegamento?"
msgid "Attaching..."
msgstr "Collegamento in corso..."
msgid ""
"This disk will be detached permanently and you can re-attach it. Continue to "
"detach it?"
msgstr ""
"Il disco verrà scollegato permanentemente e sarà possibile ricollegarlo. "
"Continuare con lo scollegamento?"
msgid "interface:"
msgstr "interfaccia:"
msgid "address:"
msgstr "indirizzo:"
msgid "link_type:"
msgstr "tipo_link:"
msgid "block:"
msgstr "blocco:"
msgid "drive_type:"
msgstr "tipo_drive:"
msgid "model:"
msgstr "modello:"
msgid "Affected devices:"
msgstr "Dispositivi influenzati:"
msgid "Less"
msgstr ""
msgid "Successfully attached device to VM"
msgstr ""
msgid "Successfully detached device from VM"
msgstr ""
msgid "Following devices will be affected, confirm?"
msgstr ""
msgid "Bridge"
msgstr ""
msgid "Vepa"
msgstr ""
msgid "None"
msgstr ""
msgid "unavailable"
msgstr "non disponibile"
msgid ""
"This action will interrupt network connectivity for any virtual machine that "
"depend on the %1 network."
msgstr ""
msgid "Add Network"
msgstr ""
msgid ""
"The %1 network is not persistent. Instead of stop, this action will "
"permanently delete it. Would you like to continue?"
msgstr ""
msgid ""
"The bridged VLAN tag may not work well with NetworkManager enabled. You "
"should consider disabling it."
msgstr ""
"La tag VLAN con bridge potrebbe non funzionare bene con NetworkManager "
"abilitato. Si dovrebbe prendere in considerazione la sua disabilitazione."
msgid ""
"This will permanently delete the %1 storage pool. Would you like to continue?"
msgstr ""
msgid "This storage pool is empty."
msgstr "Il pool di memoria è vuoto."
msgid ""
"It will format your disk and you will loose any data in there, are you sure "
"to continue? "
msgstr ""
"Il disco verrà formattato e tutti i dati su di esso andranno persi, sicuri "
"di voler continuare? "
msgid "SCSI Fibre Channel"
msgstr "Canale a fibre ottiche SCSI"
msgid "No SCSI adapters found."
msgstr "Nessun adattatore SCSI trovato."
msgid "Loading iSCSI targets..."
msgstr "Caricamento delle destinazioni iSCSI..."
msgid "No iSCSI found. Please input one."
msgstr "iSCSI non trovato. Immetterne uno."
msgid "Failed to load iSCSI targets."
msgstr "Impossibile caricare le destinazioni iSCSI."
msgid "Would you like to continue?"
msgstr ""
msgid "This will permanently delete the following storage volumes: %1"
msgstr ""
msgid "No available partitions found."
msgstr "Nessuna partizione disponibile trovata."
msgid ""
"The %1 storage pool is not persistent. Instead of deactivate, this action "
"will permanently delete it. Would you like to continue?"
msgstr ""
msgid "Unable to retrieve partitions information."
msgstr "Impossibile caricare le informazioni sulla partizione."
msgid "In progress..."
msgstr "In corso..."
msgid "Failed!"
msgstr "Non riuscito."
msgid "No LVM found in the system."
msgstr ""
msgid "This will permanently wipe the following storage volumes: %1"
msgstr ""
msgid "Wipe Confirmation"
msgstr ""
msgid "Select one or more partitions to be added to the logical pool %1:"
msgstr ""
msgid "Add Storage"
msgstr ""
msgid "DIR"
msgstr ""
msgid "NFS"
msgstr ""
msgid "iSCSI"
msgstr ""
msgid "LOGICAL"
msgstr ""
msgid "device"
msgstr ""
msgid "path"
msgstr ""
msgid "size (GiB)"
msgstr ""
msgid "free size (GiB)"
msgstr ""
msgid "Invalid NFS mount path."
msgstr "Percorso di montaggio NFS non valido."
msgid "No logical device selected."
msgstr "Nessun dispositivo logico selezionato."
msgid "This is not a valid Server Name or IP. Please, modify it."
msgstr "Nome server o IP non validi. Modificarli."
msgid "CDROM path needs to be a valid local/remote path and cannot be blank."
msgstr ""
"Il percorso CDROM deve essere un percorso locale/remoto valido e non può "
"essere vuoto."
msgid "Disk pool or volume cannot be blank."
msgstr "Il volume o il pool di dischi non può essere vuoto."
msgid ""
"Disk size or Format or Directory path cannot be blank and Directory path "
"needs to be a valid local/remote path."
msgstr ""
msgid "Disk path needs to be a valid local/remote path and cannot be blank."
msgstr ""
msgid "Storage pool or Disk size or Format cannot be blank."
msgstr ""
msgid "cdrom"
msgstr ""
msgid "disk"
msgstr ""
msgid "Pool"
msgstr ""
msgid "qcow"
msgstr ""
msgid "qcow2"
msgstr ""
msgid "qed"
msgstr ""
msgid "raw"
msgstr ""
msgid "vmdk"
msgstr ""
msgid "vpc"
msgstr ""
msgid "Create a network"
msgstr "Crea una rete"
msgid "Network Name"
msgstr "Nome rete"
msgid "Name should not contain '/' and '\"'."
msgstr "Il nome non deve contenere '/' e '\"'."
msgid "Network Type"
msgstr "Tipo di Rete"
msgid "Isolated: no external network connection"
msgstr "Isolata: nessuna connessione di rete esterna"
msgid "NAT: outbound physical network connection only"
msgstr "NAT: solo connessione di rete fisica in uscita"
msgid "Macvtap: Virtual machines are connected to physical network directly"
msgstr ""
msgid ""
"Passthrough: Virtual machines are connected using a macvtap connection in "
"passthrough mode."
msgstr ""
msgid ""
"VEPA: special mode where virtual machines are connected to a VEPA-enabled "
"switch"
msgstr ""
msgid "Bridged: Virtual machines are connected through a network bridge"
msgstr ""
msgid "Destination"
msgstr "Destinazione"
msgid "Select an Interface"
msgstr ""
msgid "Enable VLAN"
msgstr "Abilita VLAN"
msgid "VLAN ID"
msgstr "ID VLAN"
msgid "Edit Network"
msgstr ""
msgid "Address Space"
msgstr ""
msgid "Define a New Storage Pool"
msgstr "Definisci un nuovo pool di memoria"
msgid "Storage Pool Name"
msgstr "Nome pool di memoria"
msgid ""
"The name used to identify the storage pools, and it should not be empty."
msgstr ""
"Il nome utilizzato per identificare i pool di memoria; il campo non deve "
"essere vuoto."
msgid "Storage Pool Type"
msgstr "Tipo di pool di memoria"
msgid "Storage Path"
msgstr "Percorso di memoria"
msgid ""
"The path of the Storage Pool. Each Storage Pool must have a unique path."
msgstr ""
"Il percorso del pool di memoria. Ogni pool di memoria deve avere un percorso "
"univoco."
msgid ""
"Kimchi will try to create the directory when it does not already exist in "
"your system."
msgstr ""
"Kimchi tenterà di creare la directory nel caso non esista ancora sul sistema."
msgid "NFS Server IP"
msgstr "IP server NFS"
msgid "NFS server IP or hostname. It can be input or chosen from history."
msgstr ""
"Il nome host o l'indirizzo IP del server NFS. È possibile immetterlo o "
"sceglierlo dalla cronologia."
msgid "NFS Path"
msgstr "Percorso NFS"
msgid "The NFS exported path on NFS server."
msgstr "Il percorso esportato NFS sul server NFS."
msgid "Create from existing LVM"
msgstr ""
msgid "Create from raw disk"
msgstr ""
msgid "Looking for existing lvms ..."
msgstr ""
msgid "Looking for available partitions ..."
msgstr "Ricerca di partizioni disponibili in corso..."
msgid "iSCSI Server"
msgstr "Server iSCSI"
msgid "Server"
msgstr "Server"
msgid "Port"
msgstr "Porta"
msgid "iSCSI server IP or hostname. It should not be empty."
msgstr ""
"Il nome host o l'indirizzo IP del server iSCSI. Il campo non deve essere "
"vuoto."
msgid "Target"
msgstr "Destinazione"
msgid "The iSCSI target on iSCSI server"
msgstr "La destinazione iSCSI sul server iSCSI"
msgid "Add iSCSI Authentication"
msgstr "Aggiungi autenticazione iSCSI"
msgid "User Name"
msgstr "Nome utente"
msgid "SCSI Adapter"
msgstr "Adattatore SCSI"
msgid "Please, wait..."
msgstr "Attendere..."
msgid "Add a Volume to Storage Pool"
msgstr "Aggiungi un volume al pool di memoria"
msgid "Fetch from remote URL"
msgstr "Richiama da URL remoto"
msgid "Enter the remote URL here."
msgstr "Immettere qui l'URL remoto."
msgid "Upload a file"
msgstr "Carica un file"
msgid "Choose the file you want to upload."
msgstr "Selezionare il file da caricare."
msgid "Resize Volume"
msgstr ""
msgid "Size"
msgstr ""
msgid "The total space which can be used to store data. The unit is megabytes."
msgstr ""
msgid "Ok"
msgstr ""
msgid "Template Name"
msgstr ""
msgid ""
"The name used to identify the template. If omitted, a name will be "
"automatically chosen."
msgstr ""
msgid ""
"When selecting more than one Image Template, a name will be automatically "
"chosen for each Image Template selected."
msgstr ""
msgid "Where is the source media for this template? "
msgstr ""
msgid "Image Template"
msgstr ""
msgid "Netboot Template"
msgstr ""
msgid "File Path:"
msgstr "Percorso file:"
msgid "Search ISOs"
msgstr "Ricerca ISO"
msgid "The following ISOs are available:"
msgstr "Sono disponibili i seguenti file ISO:"
msgid "QEMU does not have enough permission to work with this file"
msgstr ""
msgid "Search more ISOs"
msgstr "Ricerca più ISO"
msgid "Loading..."
msgstr ""
msgid "Edit Template"
msgstr "Modifica modello"
msgid "CDROM"
msgstr "CDROM"
msgid "Image File"
msgstr "File immagine"
msgid "Graphics"
msgstr "Grafici"
msgid "Disk(GB)"
msgstr "Disco (GB)"
msgid "Disk Format"
msgstr "Formato disco"
msgid "Add Interface"
msgstr ""
msgid "pool"
msgstr ""
msgid "bridge"
msgstr ""
msgid "vepa"
msgstr ""
msgid "State"
msgstr ""
msgid "Guest Name ID"
msgstr ""
msgid "OS Type"
msgstr ""
msgid "VNC"
msgstr ""
msgid "No guests found."
msgstr ""
msgid "Stop"
msgstr ""
msgid "Location"
msgstr ""
msgid "%Used"
msgstr ""
msgid "Allocated"
msgstr ""
msgid "Capacity"
msgstr ""
msgid "Disks"
msgstr ""
msgid "Extending logical pool"
msgstr ""
msgid "%"
msgstr ""
msgid "Deactivate"
msgstr ""
msgid "Activate"
msgstr ""
msgid "Extend"
msgstr ""
msgid "Undefine"
msgstr ""
msgid "Add Volume"
msgstr ""
msgid "Resize"
msgstr ""
msgid "Wipe"
msgstr ""
msgid "Filter:"
msgstr ""
msgid "Used By"
msgstr ""
msgid "Used"
msgstr ""
msgid "Progress"
msgstr ""
msgid "Used by the following VMs:"
msgstr ""
msgid "Allocation"
msgstr ""
msgid "Template Name (ID)"
msgstr ""
msgid "No templates found."
msgstr ""
msgid "M"
msgstr ""
================================================
FILE: po/ja_JP.po
================================================
# Japonese translations for kimchi package.
# Copyright IBM Corp, 2014-2017
# Adam Litke , 2013.
#
msgid ""
msgstr ""
"Project-Id-Version: kimchi 0.1\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2017-06-30 10:27-0300\n"
"PO-Revision-Date: 2013-07-11 17:32-0400\n"
"Last-Translator: Crístian Viana \n"
"Language-Team: English\n"
"Language: ja_JP\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: pygettext.py 1.5\n"
"Plural-Forms: nplurals=1; plural=0;\n"
#, python-format
msgid "Unknown parameter %(value)s"
msgstr "パラメーター %(value)s が不明です"
#, python-format
msgid "User %(user_id)s not found with given LDAP settings."
msgstr "指定の LDAP 設定を持つユーザー %(user_id)s が見つかりません。"
#, python-format
msgid "Partition %(name)s does not exist in the host"
msgstr "パーティション %(name)s はホストに存在しません"
#, python-format
msgid "Error while accessing dev mapper device, %(err)s"
msgstr ""
msgid "Block device not found."
msgstr ""
#, python-format
msgid "Block device %(device)s not found."
msgstr ""
#, python-format
msgid "Unable to retrieve LVM information. Details: %(err)s"
msgstr ""
msgid "Unknown \"_cap\" specified"
msgstr "不明な「_cap」が指定されました"
msgid "\"_passthrough\" should be \"true\" or \"false\""
msgstr "「_passthrough」は「true」または「false」でなければなりません"
msgid "\"_passthrough_affected_by\" should be a device name string"
msgstr "「_passthrough_affected_by」はデバイス名ストリングでなければなりません"
msgid "\"_available_only\" should be \"true\" or \"false\""
msgstr "「_available_only」は「true」または「false」でなければなりません"
#, python-format
msgid "Unable to find distro file: %(filename)s"
msgstr "distro ファイル %(filename)s が見つかりません"
#, python-format
msgid ""
"Unable to parse distro file: %(filename)s. Make sure, it is a JSON file."
msgstr ""
"distro ファイル %(filename)s を解析できません。JSON ファイルであることを確認"
"してください。"
#, python-format
msgid "Unable to login to iSCSI host target %(portal)s. Details: %(err)s"
msgstr ""
"iSCSI ホスト・ターゲット %(portal)s にログインできません。詳細: %(err)s"
#, python-format
msgid "Unable to login to iSCSI host %(host)s target %(target)s"
msgstr "iSCSI ホスト %(host)s ターゲット %(target)s にログインできません"
#, python-format
msgid "Unable to find ISO file %(filename)s"
msgstr "ISO ファイル %(filename)s が見つかりません"
#, python-format
msgid "The ISO file %(filename)s is not bootable"
msgstr "ISO ファイル %(filename)s がブート可能ではありません"
#, python-format
msgid "The ISO file %(filename)s does not have a valid El Torito boot record"
msgstr ""
"ISO ファイル %(filename)s に有効な El Torito ブート・レコードがありません"
#, python-format
msgid "Invalid El Torito validation entry in ISO %(filename)s"
msgstr "ISO %(filename)s に無効な El Torito 検証項目があります"
#, python-format
msgid "Invalid El Torito boot indicator in ISO %(filename)s"
msgstr "ISO %(filename)s に無効な El Torito ブート・インジケーターがあります"
#, python-format
msgid "Unexpected volume type for primary volume in ISO %(filename)s"
msgstr "ISO %(filename)s 内の 1 次ボリュームが予期しないボリューム・タイプです"
#, python-format
msgid "Bad format while reading volume descriptor in ISO %(filename)s"
msgstr ""
"ISO %(filename)s 内のボリューム・ディスクリプターを読み取り中にフォーマットが"
"正しくありませんでした"
#, python-format
msgid ""
"The hypervisor doesn't have permission to use this ISO %(filename)s. "
"Consider moving it under /var/lib/libvirt, or set the search permission to "
"file access control lists for '%(user)s' user if possible, or add the "
"'%(user)s' to the ISO path group, or (not recommended) 'chmod -R o+x "
"'path_to_iso'.Details: %(err)s"
msgstr ""
"ハイパーバイザーにこの ISO %(filename)s を使用する権限がありません。これを /"
"var/lib/libvirt の下に移動することを検討してください。あるいは、「%(user)s」"
"ユーザーのファイル・アクセス制御リストに検索許可を設定する (可能な場合) か、"
"「%(user)s」を ISO パス・グループに追加するか、または (非推奨ですが)「chmod -"
"R o+x 'path_to_iso'」を実行してください。詳細: %(err)s"
#, python-format
msgid "Unable to access remote ISO. Details: %(err)s"
msgstr "リモート ISO にアクセスできません。詳細: %(err)s"
#, python-format
msgid "Error probing image OS information: %(err)s"
msgstr ""
#, python-format
msgid "Unable to read image file %(filename)s"
msgstr "イメージ・ファイル %(filename)s を読み取ることができません"
#, python-format
msgid ""
"Image file must be an existing file on system. %(filename)s is not a valid "
"input."
msgstr ""
"イメージ・ファイルはシステム上に存在するファイルでなければなりませ"
"ん。%(filename)s は有効な入力ではありません。"
#, python-format
msgid "Virtual machine %(name)s already exists"
msgstr "仮想マシン %(name)s は既に存在します"
#, python-format
msgid "Virtual machine %(name)s does not exist"
msgstr "仮想マシン %(name)s は存在しません"
#, python-format
msgid "Unable to retrieve screenshot for stopped virtual machine %(name)s"
msgstr "停止している仮想マシン %(name)s のスクリーン・ショットを取得できません"
msgid "Remote ISO image is not supported by this server."
msgstr "リモート ISO イメージは、このサーバーではサポートされていません。"
#, python-format
msgid "Screenshot is not supported on virtual machine %(name)s"
msgstr ""
"スクリーン・ショットはこの仮想マシン %(name)s ではサポートされていません"
#, python-format
msgid "Unable to create virtual machine %(name)s. Details: %(err)s"
msgstr "仮想マシン %(name)s を作成できません。詳細: %(err)s"
#, python-format
msgid "Unable to update virtual machine %(name)s. Details: %(err)s"
msgstr "仮想マシン %(name)s を更新できません。詳細: %(err)s"
#, python-format
msgid "Unable to retrieve virtual machine %(name)s. Details: %(err)s"
msgstr "仮想マシン %(name)s を取得できません。詳細: %(err)s"
#, python-format
msgid "Unable to connect to powered off virtual machine %(name)s."
msgstr "電源オフされた仮想マシン %(name)s に接続できません。"
msgid "Virtual machine name must be a string without slashes (/)"
msgstr "仮想マシン名はスラッシュ (/) のないストリングでなければなりません"
#, python-format
msgid "Invalid template URI %(value)s specified for virtual machine"
msgstr "無効なテンプレート URI %(value)s が仮想マシンに指定されています"
#, python-format
msgid "Invalid storage pool URI %(value)s specified for virtual machine"
msgstr "無効なストレージ・プール URI %(value)s が仮想マシンに指定されています"
msgid "Supported virtual machine graphics are Spice or VNC"
msgstr "サポートされている仮想マシン・グラフィックスは Spice または VNC です"
msgid "Graphics address to listen on must be IPv4 or IPv6"
msgstr ""
"listen を行うグラフィックス・アドレスは IPv4 または IPv6 でなければなりません"
msgid "Specify a template to create a virtual machine from"
msgstr "仮想マシンの作成元となるテンプレートを指定してください"
#, python-format
msgid "Unable to start virtual machine %(name)s. Details: %(err)s"
msgstr "仮想マシン %(name)s を開始できません。詳細: %(err)s"
#, python-format
msgid "Unable to power off virtual machine %(name)s. Details: %(err)s"
msgstr "仮想マシン %(name)s を電源オフできません。詳細: %(err)s"
#, python-format
msgid "Unable to delete virtual machine %(name)s. Details: %(err)s"
msgstr "仮想マシン %(name)s を削除できません。詳細: %(err)s"
#, python-format
msgid "Unable to reset virtual machine %(name)s. Details: %(err)s"
msgstr "仮想マシン %(name)s をリセットできません。詳細: %(err)s"
msgid "User name list must be an array"
msgstr "ユーザー名リストは配列でなければなりません"
msgid "User name must be a string"
msgstr "ユーザー名はストリングでなければなりません"
msgid "Group name list must be an array"
msgstr "グループ名リストは配列でなければなりません"
msgid "Group name must be a string"
msgstr "グループ名はストリングでなければなりません"
#, python-format
msgid "User(s) '%(users)s' do not exist"
msgstr "ユーザー「%(users)s」は存在しません"
#, python-format
msgid "Group(s) '%(groups)s' do not exist"
msgstr "グループ「%(groups)s」は存在しません"
#, python-format
msgid "Unable to shutdown virtual machine %(name)s. Details: %(err)s"
msgstr "仮想マシン %(name)s をシャットダウンできません。詳細: %(err)s"
msgid "The guest console password must be a string."
msgstr "ゲスト・コンソール・パスワードはストリングでなければなりません。"
msgid "The life time for the guest console password must be a number."
msgstr "ゲスト・コンソール・パスワードの存続時間は数値でなければなりません。"
#, python-format
msgid "Virtual machine '%(name)s' must be stopped before cloning it."
msgstr "仮想マシン「%(name)s」のクローンを作成する前に停止する必要があります。"
#, python-format
msgid "Insufficient disk space to clone virtual machine '%(name)s'"
msgstr ""
"仮想マシン「%(name)s」のクローンを作成するためのディスク・スペースが不足して"
"います"
#, python-format
msgid "Unable to clone VM '%(name)s'. Details: %(err)s"
msgstr "VM「%(name)s」のクローンを作成できません。詳細: %(err)s"
#, python-format
msgid "Invalid operation for non-persistent virtual machine %(name)s"
msgstr "非永続仮想マシン %(name)s の操作が無効です"
#, python-format
msgid "Cannot suspend VM '%(name)s' because it is not running."
msgstr "VM「%(name)s」は実行されていないため、中断できません。"
#, python-format
msgid "Unable to suspend VM '%(name)s'. Details: %(err)s"
msgstr "VM「%(name)s」を中断できません。詳細: %(err)s"
#, python-format
msgid "Cannot resume VM '%(name)s' because it is not paused."
msgstr "VM「%(name)s」は一時停止されていないため、再開できません。"
#, python-format
msgid "Unable to resume VM '%(name)s'. Details: %(err)s"
msgstr "VM「%(name)s」を再開できません。詳細: %(err)s"
#, python-format
msgid ""
"Memory assigned is higher then the maximum allowed in the host: "
"%(maxmem)sMib."
msgstr ""
"割り当てられたメモリーはホストで許可された最大を超えています: %(maxmem)sMib。"
#, python-format
msgid ""
"Guest '%(name)s' does not support live memory update. Please, with the guest "
"offline, set Maximum Memory with a value greater then Memory to enable this "
"feature."
msgstr ""
"ゲスト「%(name)s」はライブ・メモリー・アップデートをサポートしていません。こ"
"の機能を使用可能にするには、このゲストをオフラインにした状態で、Maximum "
"Memory を Memory より大きい値で設定してください。"
msgid "Only increase memory is allowed in active VMs"
msgstr "アクティブ VM ではメモリーの増加のみが許可されています"
msgid "There are not enough free slots to add a new memory device."
msgstr ""
"新規メモリー・デバイスを追加するだけの十分なフリー・スロットがありません。"
msgid ""
"Host's libvirt or qemu version does not support memory devices and memory "
"hotplug. Libvirt must be >= 1.2.14 and QEMU must be >= 2.1."
msgstr ""
"ホストの libvirt または qemu のバージョンはデバイスやメモリー・ホット・プラグ"
"をサポートしていません。Libvirt は 1.2.14 以上でなければなりません。QEMU は "
"2.1 以上でなければなりません。"
#, python-format
msgid "Error attaching memory device. Details: %(error)s"
msgstr "メモリー・デバイスの接続エラーです。詳細: %(error)s"
#, python-format
msgid "Cannot start %(name)s. Virtual machine is already running."
msgstr "%(name)s を開始できません。仮想マシンは既に稼働中です。"
#, python-format
msgid "Cannot power off %(name)s. Virtual machine is shut off."
msgstr ""
"%(name)s の電源をオフにできません。仮想マシンはシャットオフされています。"
#, python-format
msgid "Cannot shutdown %(name)s. Virtual machine is shut off."
msgstr ""
"%(name)s をシャットダウンできません。仮想マシンはシャットオフされています。"
#, python-format
msgid "Cannot reset %(name)s. Virtual machine is already shut off."
msgstr ""
"%(name)s をリセットできません。仮想マシンは既にシャットオフされています。"
msgid "Boot order must be a list. Devices accepted: hd, cdrom, fd or network."
msgstr ""
"Boot order はリストになっていなければなりません。受け入れられるデバイス: hd、"
"cdrom、fd、または network。"
msgid "Bootmenu must be boolean. Values accepted: true of false."
msgstr ""
"Bootmenu はブール値になっていなければなりません。受け入れられる値: true また"
"は false。"
msgid "Graphic type not valid. Values accepted: vnc or spice."
msgstr "グラフィック・タイプが無効です。受け入れられる値: vnc または spice。"
#, python-format
msgid "Migrate to localhost %(host)s is not allowed."
msgstr "ローカル・ホスト %(host)s へのマイグレーションは許可されていません。"
#, python-format
msgid ""
"To migrate a virtual machine to the remote host %(host)s the user %(user)s "
"must have password-less login to the remote host."
msgstr ""
"ユーザー %(user)s がリモート・ホスト %(host)s に仮想マシンをマイグレーション"
"するには、そのユーザーがリモート・ホストにパスワードなしでログインできなけれ"
"ばなりません。"
#, python-format
msgid "Can not migrate virtual machine %(name)s when its in %(state)s state."
msgstr ""
"%(state)s 状態になっている仮想マシン %(name)s はマイグレーションできません。"
#, python-format
msgid "Failed to migrate virtual machine %(name)s due error: %(err)s"
msgstr ""
"エラーが発生したため、仮想マシン %(name)s をマイグレーションできませんでし"
"た: %(err)s"
msgid "User name of the remote server must be a string."
msgstr "リモート・サーバーのユーザー名はストリングでなければなりません。"
msgid "Destination host of the migration must be a string."
msgstr "マイグレーションの宛先ホストはストリングでなければなりません。"
#, python-format
msgid "Unable to create file %(path)s at %(host)s using user %(user)s."
msgstr ""
"ユーザー %(user)s を使用してホスト %(host)s でファイル %(path)s を作成できま"
"せん。"
#, python-format
msgid "Unable to read disk size of %(path)s, error: %(error)s"
msgstr "%(path)s のディスク・サイズを読み取れません。エラー: %(error)s"
#, python-format
msgid ""
"Unable to create disk image %(path)s at %(host)s using user %(user)s. Error: "
"%(error)s"
msgstr ""
"ユーザー %(user)s を使用して %(host)s でディスク・イメージ %(path)s を作成で"
"きません。エラー: %(error)s"
#, python-format
msgid ""
"Unable to migrate virtual machine to remote host %(host)s with arch "
"%(destarch)s using localhost with arch %(srcarch)s."
msgstr ""
"アーキテクチャー %(srcarch)s のローカル・ホストを使用してアーキテクチャー "
"%(destarch)s のリモート・ホスト %(host)s に仮想マシンをマイグレーションできま"
"せん。"
#, python-format
msgid ""
"Unable to migrate virtual machine to remote host %(host)s with hypervisor "
"%(desthyp)s because localhost uses hypervisor %(srchyp)s."
msgstr ""
"ローカル・ホストではハイパーバイザー %(srchyp)s が使用されているため、ハイ"
"パーバイザー %(desthyp)s のリモート・ホスト %(host)s に仮想マシンをマイグレー"
"ションできません。"
#, python-format
msgid ""
"Unable to determine remote host hypervisor and architecture. Error: %(error)s"
msgstr ""
"リモート・ホストのハイパーバイザーとアーキテクチャーを判別できません。エ"
"ラー: %(error)s"
#, python-format
msgid ""
"Unable to migrate virtual machine: subcores per core setting from "
"localhostand remote host %(host)s differs."
msgstr ""
"仮想マシンをマイグレーションできません: コアあたりのサブコアの設定がローカ"
"ル・ホストとリモート・ホスト %(host)s で異なります。"
#, python-format
msgid ""
"Unable to setup password-less login at remote host %(host)s using user "
"%(user)s. Error: %(error)s"
msgstr ""
"ユーザー %(user)s を使用したリモート・ホスト %(host)s へのパスワードなしのロ"
"グインをセットアップできません。エラー: %(error)s"
msgid "Password field must be a string."
msgstr "「パスワード」フィールドの値はストリングでなければなりません。"
msgid "Error creating local host ssh rsa key of user 'root'."
msgstr ""
"ユーザー「root」のローカル・ホスト ssh rsa 鍵を作成するときにエラーが発生しま"
"した。"
#, python-format
msgid "%(param)s value (%(mem)sMiB) must be aligned to %(alignment)sMiB."
msgstr ""
"%(param)s 値 (%(mem)sMiB) は %(alignment)sMiB に調整する必要があります。"
#, python-format
msgid ""
"Unable to update the following parameters while the VM is offline: %(params)s"
msgstr ""
"次のパラメーターは、VM がオフラインのときには更新できません: %(params)s"
#, python-format
msgid ""
"Unable to update the following parameters while the VM is online: %(params)s"
msgstr ""
"次のパラメーターは、VM がオンラインのときには更新できません: %(params)s"
#, python-format
msgid ""
"VM %(name)s must have serial and console defined to open a web serial console"
msgstr ""
"VM %(name)s には、Web シリアル・コンソールを開くために定義されているシリアル"
"およびコンソールが必要です"
#, python-format
msgid "Impossible to get the serial console of %(name)s"
msgstr "%(name)s のシリアル・コンソールを取得できません"
#, python-format
msgid ""
"Memory or Maximum Memory value is higher than amount supported by the host: "
"%(memHost)sMiB."
msgstr ""
"Memory または Maximum Memory の値が、ホストでサポートされている量 "
"(%(memHost)sMiB) より大きい値です。"
#, python-format
msgid ""
"Memory or Maximum Memory value is higher than maximum amount recommended: "
"%(value)sTiB"
msgstr ""
"Memory または Maximum Memory の値が最大推奨量 (%(value)sTiB) より大きい値です"
msgid "Cannot update Maximum Memory when guest is running."
msgstr "ゲストで実行しているときは Maximum Memory は更新できません。"
#, python-format
msgid "Impossible to create %(dir)s directory."
msgstr "%(dir)s ディレクトリーを作成できません。"
#, python-format
msgid ""
"Either the guest %(name)s did not start to listen to the serial or it is not "
"configured to use the serial console."
msgstr ""
"ゲスト %(name)s はシリアルを listen し始めなかったか、またはシリアル・コン"
"ソールを使用するように構成されていません。"
#, python-format
msgid ""
"Unable to retrieve Virt Viewer file for stopped virtual machine %(name)s"
msgstr ""
"停止した仮想マシン %(name)s の Virt ビューアー・ファイルを取得できません"
#, python-format
msgid ""
"Error occured while retrieving the Virt Viewer file for virtual machine "
"%(name)s : %(err)s"
msgstr ""
"仮想マシン %(name)s の Virt ビューアー・ファイルを取得するときにエラーが発生"
"しました: %(err)s"
msgid "Virtual machine title must be a string"
msgstr "仮想マシン名はストリングでなければなりません"
msgid "Virtual machine description must be a string"
msgstr "仮想マシンの説明はストリングでなければなりません"
msgid "console parameter is only supported for s390x/s390 architecture."
msgstr ""
"コンソール・パラメーターは s390x/s390 アーキテクチャーに対してのみサポートさ"
"れています。"
msgid "invalid console type, supported types are sclp/virtio."
msgstr ""
"コンソール・タイプが無効です。サポートされているタイプは sclp/virtio です。"
#, python-format
msgid ""
"Unable to setup password-less login at remote host %(host)s using user "
"%(user)s: remote directory %(sshdir)s does not exist."
msgstr ""
"ユーザー %(user)s を使用したリモート・ホスト %(host)s へのパスワードなしのロ"
"グインをセットアップできません: リモート・ディレクトリー %(sshdir)s がありま"
"せん。"
#, python-format
msgid ""
"Unable to create a password-less libvirt connection to the remote libvirt "
"daemon at host %(host)s with the user %(user)s. Please verify the remote "
"server libvirt configuration. More information: http://libvirt.org/auth."
"html ."
msgstr ""
"リモート libvirt デーモンへのパスワード不要 libvirt 接続 (ホスト %(host)s、"
"ユーザー %(user)s) を作成できません。リモート・サーバー libvirt 構成を確認し"
"てください。詳細は、http://libvirt.org/auth.html にあります。"
msgid "'enable_rdma' must be of type boolean (true or false)."
msgstr ""
#, python-format
msgid ""
"VM %(vmid)s does not contain directly assigned host device %(dev_name)s."
msgstr ""
"直接割り当てられたホスト・デバイス %(dev_name)s が VM %(vmid)s に含まれていま"
"せん。"
#, python-format
msgid "The host device %(dev_name)s is not allowed to directly assign to VM."
msgstr ""
"ホスト・デバイス %(dev_name)s は VM への直接割り当てを許可されていません。"
msgid ""
"No IOMMU groups found. Host PCI pass through needs IOMMU group to function "
"correctly. Please enable Intel VT-d or AMD IOMMU in your BIOS, then verify "
"the Kernel is compiled with IOMMU support. For Intel CPU, add "
"'intel_iommu=on' to GRUB_CMDLINE_LINUX parameter in /etc/default/grub file. "
"For AMD CPU, add 'iommu=pt iommu=1'."
msgstr ""
"IOMMU グループが見つかりません。ホスト PCI パススルーでは IOMMU グループが正"
"しく機能しなければなりません。BIOS で Intel VT-d または AMD IOMMU を使用可能"
"にして、カーネルが IOMMU サポートを使用してコンパイルされていることを確認して"
"ください。Intel CPU に関しては、/etc/default/grub ファイルにおいて"
"「intel_iommu=on」を GRUB_CMDLINE_LINUX パラメーターに追加してください。AMD "
"CPU に関しては、「iommu=pt iommu=1」を追加してください。"
msgid "\"name\" should be a device name string"
msgstr "「name」はデバイス名ストリングでなければなりません"
#, python-format
msgid ""
"The device %(name)s is probably in use by the host. Unable to attach it to "
"the guest."
msgstr ""
"デバイス %(name)s はホストで使用中である可能性があります。これはゲストに接続"
"できません。"
#, python-format
msgid "Hot-(un)plug of device %(name)s is not supported."
msgstr ""
"デバイス %(name)s のホット・プラグ/アンプラグはサポートされていません。"
#, python-format
msgid "Failed to attach %(device)s to %(vm)s"
msgstr "%(device)s を %(vm)s に接続できませんでした"
#, python-format
msgid "VM %(vmid)s does not have a USB controller to accept PCI hotplug."
msgstr ""
#, python-format
msgid "Interface %(iface)s does not exist in virtual machine %(name)s"
msgstr "インターフェース %(iface)s は仮想マシン %(name)s に存在しません"
#, python-format
msgid ""
"Network %(network)s specified for virtual machine %(name)s does not exist"
msgstr ""
"仮想マシン %(name)s に指定されたネットワーク %(network)s は存在しません"
msgid ""
"Supported virtual machine interfaces type are network, ovs and macvtap.Type "
"ovs and macvtap are only supported for s390x/s390 architecture."
msgstr ""
"サポートされている仮想マシン・インターフェース・タイプは network、ovs、およ"
"び macvtap です。タイプ ovs および macvtap は s390x/s390 アーキテクチャーに対"
"してのみサポートされています。"
msgid "Network name for virtual machine interface must be a string"
msgstr ""
"仮想マシン・インターフェースのネットワーク名はストリングでなければなりません"
msgid "Invalid network model card specified for virtual machine interface"
msgstr ""
"無効なネットワーク・モデル・カードが仮想マシン・インターフェースに指定されて"
"います"
msgid "Specify type and network to add a new virtual machine interface"
msgstr ""
"新しい仮想マシン・インターフェースに追加するタイプおよびネットワークを指定し"
"てください"
msgid "MAC Address must respect this format FF:FF:FF:FF:FF:FF"
msgstr "MAC アドレスは FF:FF:FF:FF:FF:FF の形式に従っていなければなりません"
#, python-format
msgid "MAC Address %(mac)s already exists in virtual machine %(name)s"
msgstr "MAC アドレス %(mac)s は既に仮想マシン %(name)s に存在します"
msgid "Invalid MAC Address"
msgstr "MAC アドレスが無効です"
msgid "Cannot change MAC address of a running virtual machine"
msgstr "実行中の仮想マシンの MAC アドレスは変更できません"
msgid "Type macvtap and ovs are only supported on s390x/s390 architecture."
msgstr ""
"タイプ macvtap および ovs は s390x/s390 アーキテクチャーでのみサポートされて"
"います。"
msgid "Source attribute is only supported on s390x/s390 architecture."
msgstr "ソース属性は s390x/s390 アーキテクチャーでのみサポートされています。"
msgid "If source is provided, only type supported are macvtap and ovs."
msgstr ""
"ソースが指定されている場合、サポートされているタイプは macvtap と ovs のみで"
"す。"
msgid "For type macvtap and ovs, source has to be provided"
msgstr "タイプ macvtap および ovs に関しては、ソースを指定する必要があります。"
msgid "Source name for virtual machine interface must be string"
msgstr "仮想マシン・インターフェースのソース名はストリングでなければなりません"
msgid "Invalid source mode. Valid options are: bridge or vepa."
msgstr "ソース・モードが無効です。有効なオプションは bridge または vepa です。"
#, python-format
msgid "Template %(name)s already exists"
msgstr "テンプレート %(name)s は既に存在します"
#, python-format
msgid "Source media %(path)s not found"
msgstr "ソース・メディア %(path)s が見つかりません"
#, python-format
msgid ""
"Network '%(network)s' specified for template %(template)s does not exist"
msgstr ""
"テンプレート %(template)s に指定されたネットワーク「%(network)s」は存在しませ"
"ん"
#, python-format
msgid ""
"Storage pool %(pool)s specified for template %(template)s does not exist"
msgstr ""
"テンプレート %(template)s に指定されたストレージ・プール %(pool)s は存在しま"
"せん"
#, python-format
msgid "Invalid parameter '%(param)s' specified for CDROM."
msgstr "無効なパラメーター「%(param)s」が CDROM に指定されました。"
#, python-format
msgid "Network %(network)s specified for template %(template)s is not active"
msgstr ""
"テンプレート %(template)s に指定されたネットワーク %(network)s はアクティブで"
"はありません"
msgid "Template name must be a string"
msgstr "テンプレート名はストリングでなければなりません"
msgid "Template icon must be a path to the image"
msgstr "テンプレート・アイコンはイメージのパスでなければなりません"
msgid "Template distribution must be a string"
msgstr "テンプレート・ディストリビューションはストリングでなければなりません"
msgid "Template distribution version must be a string"
msgstr ""
"テンプレート・ディストリビューション・バージョンはストリングでなければなりま"
"せん"
msgid "The number of CPUs must be an integer greater than 0"
msgstr "CPU の数は 0 より大きい整数でなければなりません"
msgid ""
"Amount of memory and maximum memory (MB) must be an integer greater than 512"
msgstr ""
"メモリー量および最大メモリー量 (MB) は 512 を超える整数でなければなりません"
msgid "Template CDROM must be a local or remote ISO file"
msgstr ""
"テンプレート CDROM はローカルまたはリモートの ISO ファイルでなければなりませ"
"ん"
#, python-format
msgid "Invalid storage pool URI %(value)s specified for template"
msgstr ""
"無効なストレージ・プール URI %(value)s がテンプレートに指定されています"
msgid ""
"Specify a path to source media (ISO, disk or remote ISO) to create a template"
msgstr ""
"テンプレートを作成するには、ソース・メディア (ISO、ディスク、またはリモート "
"ISO) へのパスを指定してください"
msgid "All networks for the template must be specified in a list."
msgstr "テンプレート用のネットワークをすべてリストに指定する必要があります。"
msgid "Specify a volume to a template when storage pool is iSCSI or SCSI"
msgstr ""
"ストレージ・プールが iSCSI または SCSI である場合はテンプレートに対してボ"
"リュームを指定してください"
#, python-format
msgid "The volume %(volume)s is not in storage pool %(pool)s"
msgstr "ボリューム %(volume)s がストレージ・プール %(pool)s にありません"
#, python-format
msgid "Unable to create template due error: %(err)s"
msgstr "次のエラーのため、テンプレートを作成できません: %(err)s"
#, python-format
msgid "Unable to delete template due error: %(err)s"
msgstr "次のエラーのため、テンプレートを削除できません: %(err)s"
msgid "Disk size must be an integer greater than 1GB."
msgstr "ディスク・サイズは 1GB より大きい整数でなければなりません。"
#, python-format
msgid "Cannot identify base image %(path)s format"
msgstr "ベース・イメージ %(path)s のフォーマットを識別できません"
msgid ""
"When specifying CPU topology, each element must be an integer greater than "
"zero."
msgstr ""
"CPU トポロジーを指定する場合、各エレメントはゼロより大きい整数でなければなり"
"ません。"
msgid ""
"Invalid disk image format. Valid formats: qcow, qcow2, qed, raw, vmdk, vpc."
msgstr ""
"ディスク・イメージ・フォーマットが無効です。有効なフォーマット: qcow、qcow2、"
"qed、raw、vmdk、vpc。"
msgid ""
"When setting template disks, following parameters are required: 'index', "
"'pool name', 'format', 'size' or 'volume' (for scsi/iscsi pools)"
msgstr ""
"テンプレート・ディスクを設定する場合は、次のパラメーターが必要です: "
"「index」、「pool name」、「format」、「size」、または「volume」(scsi/iscsi "
"プールの場合)"
msgid "Disk format must be 'raw', for logical, iscsi, and scsi pools."
msgstr ""
"論理プール、iscsi プール、および scsi プールに関しては、ディスク・フォーマッ"
"トは「raw」でなければなりません。"
msgid ""
"Memory expects an object with one or both parameters: 'current' and "
"'maxmemory'"
msgstr ""
"Memory には、パラメーター「current」と「maxmemory」の一方または両方が指定され"
"たオブジェクトが予想されます。"
#, python-format
msgid ""
"Memory value (%(mem)sMiB) must be equal or lesser than maximum memory value "
"(%(maxmem)sMiB)"
msgstr ""
"メモリー値 (%(mem)sMiB) は最大メモリー値 (%(maxmem)sMiB) 以下でなければなりま"
"せん"
#, python-format
msgid "Unable to update template due error: %(err)s"
msgstr "エラーが発生したため、テンプレートを更新できません: %(err)s"
msgid "Parameter 'disks' requires at least one disk object"
msgstr ""
"パラメーター「disks」にはディスク・オブジェクトが少なくとも 1 つは必要です"
msgid ""
"Invalid interface type. Type should be 'macvtap' for host network interface "
"(Ethernet, Bond, VLAN) to be connected as direct MacVTap or 'ovs' for "
"openvswitch host network interface to be connected as virtual switch to a VM."
msgstr ""
"インターフェース・タイプが無効です。タイプは、ホスト・ネットワーク・インター"
"フェース (イーサネット、結合、VLAN) を直接 MacVTap として接続する場合は"
"「macvtap」でなければならず、openvswitch ホスト・ネットワーク・インターフェー"
"スを VM に仮想スイッチとして接続する場合は「ovs」でなければなりません。"
msgid "Interface name should be string."
msgstr "インターフェース名はストリングでなければなりません。"
msgid "Invalid interface mode. Valid options are: bridge or vepa."
msgstr ""
"インターフェース・モードが無効です。有効なオプションは bridge または vepa で"
"す。"
msgid ""
"Interfaces should be list of interfaces. Each interface should have name, "
"type and mode(optional, only applicable for interfcae type 'macvtap'."
msgstr ""
"Interfaces はインターフェースのリストでなければなりません。各インターフェース"
"には名前、タイプ、およびモード (インターフェース・タイプ「macvtap」の場合にの"
"み使用できるオプション) が必要です。"
msgid ""
"Interface expects an object with parameters: 'name', 'type' and 'mode'. Name "
"should be name of host network interface (Ethernet, Bond, VLAN) for type "
"'macvtap' or the name of host openvswitch bridge interface for type 'ovs'. "
"Mode (optional) is only applicable for interface type 'macvtap' to indicates "
"whether packets will be delivered directly to target device (bridge) or to "
"the external bridge (vepa-capable bridge)."
msgstr ""
"インターフェースには、パラメーター「name」、「type」、および「mode」が指定さ"
"れたオブジェクトが予想されます。name は、タイプ「macvtap」の場合はホスト・"
"ネットワーク・インターフェース (イーサネット、結合、VLAN) の名前でなければな"
"らず、タイプ「ovs」の場合はホスト openvswitch ブリッジ・インターフェースの名"
"前でなければなりません。mode (オプション) は、インターフェース・タイプ"
"「macvtap」の場合に限り、パケットをターゲット・デバイス (ブリッジ) に直接送信"
"するのか外部ブリッジ (vepa 対応ブリッジ) に送信するのかを指示するために使用で"
"きます。"
msgid "Interfaces parameter only supported on s390x or s390 architecture."
msgstr ""
"Interfaces パラメーターは s390x または s390 アーキテクチャーでのみサポートさ"
"れています。"
msgid "Storage without libvirt pool is not supported on this architecture"
msgstr ""
"libvirt プールがないストレージは、このアーキテクチャーではサポートされていま"
"せん"
#, python-format
msgid "Error while creating the virtual disk for the guest. Details: %(err)s"
msgstr ""
"ゲスト用の仮想ディスクを作成するときにエラーが発生しました。詳細: %(err)s"
msgid ""
"When setting template disks without libvirt, following parameters are "
"required: 'index', 'format', 'path', 'size'"
msgstr ""
"libvirt なしでテンプレート・ディスクを設定する場合は、次のパラメーターが必要"
"です: 「index」、「format」、「path」、「size」"
#, python-format
msgid "Storage pool %(name)s already exists"
msgstr "ストレージ・プール %(name)s は既に存在します"
#, python-format
msgid "Storage pool %(name)s does not exist"
msgstr "ストレージ・プール %(name)s は存在しません"
#, python-format
msgid "Specify %(item)s in order to create the storage pool %(name)s"
msgstr ""
"ストレージ・プール %(name)s を作成するには、%(item)s を指定してください"
#, python-format
msgid "Unable to delete active storage pool %(name)s"
msgstr "アクティブ・ストレージ・プール %(name)s を削除できません"
#, python-format
msgid "Unable to list storage pools. Details: %(err)s"
msgstr "ストレージ・プールをリストできません。詳細: %(err)s"
#, python-format
msgid "Unable to create storage pool %(name)s. Details: %(err)s"
msgstr "ストレージ・プール %(name)s を作成できません。詳細: %(err)s"
#, python-format
msgid "Unable to activate storage pool %(name)s. Details: %(err)s"
msgstr "ストレージ・プール %(name)s をアクティブにできません。詳細: %(err)s"
#, python-format
msgid "Unable to deactivate storage pool %(name)s. Details: %(err)s"
msgstr "ストレージ・プール %(name)s を非アクティブにできません。詳細: %(err)s"
#, python-format
msgid "Unable to delete storage pool %(name)s. Details: %(err)s"
msgstr "ストレージ・プール %(name)s を削除にできません。詳細: %(err)s"
#, python-format
msgid ""
"Unable to create NFS Pool as export path %(path)s may block during mount"
msgstr ""
"エクスポート・パス %(path)s がマウント中にブロックしている可能性があるため、"
"NFS プールを作成できません"
#, python-format
msgid "Unable to create NFS Pool as export path %(path)s mount failed"
msgstr ""
"エクスポート・パス %(path)s マウントが失敗したため、NFS プールを作成できませ"
"ん"
#, python-format
msgid "Unsupported storage pool type: %(type)s"
msgstr "ストレージ・プール・タイプ %(type)s はサポートされていません"
#, python-format
msgid "Error while retrieving storage pool XML to %(pool)s"
msgstr "ストレージ・プール XML を %(pool)s に取得中にエラーが発生しました"
msgid "Storage pool name must be a string without slashes (/)"
msgstr ""
"ストレージ・プール名はスラッシュ (/) のないストリングでなければなりません"
msgid ""
"Supported storage pool types are dir, netfs, logical, iscsi, isci and kimchi-"
"iso"
msgstr ""
"サポートされているストレージ・プール・タイプは dir、netfs、logical、iscsi、"
"isci、および kimchi-iso です"
msgid "Storage pool path must be a string"
msgstr "ストレージ・プール・パスはストリングでなければなりません"
msgid "Storage pool host must be a IP or hostname"
msgstr "ストレージ・プール・ホストは、IP またはホスト名でなければなりません"
msgid "Storage pool device must be the absolute path to the block device"
msgstr ""
"ストレージ・プール・デバイスはブロック・デバイスへの絶対パスでなければなりま"
"せん"
msgid "Storage pool devices parameter must be a list"
msgstr "ストレージ・プール・デバイス・パラメーターはリストでなければなりません"
msgid "Target IQN of an iSCSI pool must be a string"
msgstr "iSCSI プールのターゲット IQN はストリングでなければなりません"
msgid "Port of a remote storage server must be an integer between 1 and 65535"
msgstr ""
"リモート・ストレージ・サーバーのポートは 1 から 65535 までの整数でなければな"
"りません"
msgid "iSCSI target username must be a string"
msgstr "iSCSI ターゲット・ユーザー名はストリングでなければなりません"
msgid "iSCSI target password must be a string"
msgstr "iSCSI ターゲット・パスワードはストリングでなければなりません"
msgid "Specify name and type to create a storage pool"
msgstr "ストレージ・プールを作成するには、名前とタイプを指定してください"
#, python-format
msgid ""
"%(disk)s is not a valid disk/partition. Could not add it to the pool "
"%(pool)s."
msgstr ""
"%(disk)s は有効なディスク/パーティションではありません。これはプール "
"%(pool)s に追加できませんでした。"
#, python-format
msgid "Unable to extend logical pool %(pool)s. Details: %(err)s"
msgstr "論理プール %(pool)s を拡張できません。詳細: %(err)s"
msgid "The parameter disks only can be updated for logical storage pool."
msgstr ""
"論理ストレージ・プールを対象に更新できるのは、パラメーター・ディスクだけで"
"す。"
msgid "The SCSI host adapter name must be a string."
msgstr "SCSI ホスト・アダプター名はストリングでなければなりません。"
msgid "The storage pool kimchi_isos is reserved for internal use"
msgstr "ストレージ・プール kimchi_isos は、内部使用のために予約されています"
#, python-format
msgid ""
"Unable to activate NFS storage pool %(name)s. NFS server %(server)s is "
"unreachable."
msgstr ""
"NFS ストレージ・プール %(name)s をアクティブにできません。NFS サーバー "
"%(server)s は到達不能です。"
#, python-format
msgid ""
"Unable to deactivate NFS storage pool %(name)s. NFS server %(server)s is "
"unreachable."
msgstr ""
"NFS ストレージ・プール %(name)s を非アクティブにできません。NFS サーバー "
"%(server)s は到達不能です。"
#, python-format
msgid ""
"Unable to deactivate pool %(name)s as it is associated with some templates"
msgstr ""
"プール %(name)s はいくつかのテンプレートに関連付けられているため、非アクティ"
"ブにすることはできません"
#, python-format
msgid "Unable to delete pool %(name)s as it is associated with some templates"
msgstr ""
"プール %(name)s はいくつかのテンプレートに関連付けられているため、削除できま"
"せん"
#, python-format
msgid ""
"A volume group named '%(name)s' already exists. Please, choose another name "
"to create the logical pool."
msgstr ""
"ボリューム・グループ「%(name)s」は既に存在します。論理プールを作成するには、"
"別の名前を選択してください。"
#, python-format
msgid "Unable to update database with deep scan information due error: %(err)s"
msgstr ""
"次のエラーのため、データベースをディープ・スキャン情報で更新できません:"
"%(err)s"
#, python-format
msgid ""
"No volume group '%(name)s' found. Please, specify an existing volume group "
"to create the logical pool from."
msgstr ""
"ボリューム・グループ「%(name)s」が見つかりません。論理プールの作成元となる既"
"存のボリューム・グループを指定してください。"
#, python-format
msgid "Unable to delete pool %(name)s as it is associated with guests: %(vms)s"
msgstr ""
"プール %(name)s はゲスト %(vms)s に関連付けられているため削除できません"
#, python-format
msgid "Storage volume %(name)s already exists"
msgstr "ストレージ・ボリューム %(name)s は既に存在します"
#, python-format
msgid "Storage volume %(name)s does not exist in storage pool %(pool)s"
msgstr ""
"ストレージ・ボリューム %(name)s がストレージ・プール %(pool)s に存在しません"
#, python-format
msgid ""
"Unable to create storage volume %(volume)s because storage pool %(pool)s is "
"not active"
msgstr ""
"ストレージ・プール %(pool)s がアクティブでないため、ストレージ・ボリューム "
"%(volume)s を作成できません"
#, python-format
msgid "Specify %(item)s in order to create storage volume %(volume)s"
msgstr ""
"ストレージ・ボリューム %(volume)s を作成するには、%(item)s を指定してください"
#, python-format
msgid ""
"Unable to list storage volumes because storage pool %(pool)s is not active"
msgstr ""
"ストレージ・プール %(pool)s がアクティブでないため、ストレージ・ボリュームを"
"リストできません"
#, python-format
msgid ""
"Unable to create storage volume %(name)s in storage pool %(pool)s. Details: "
"%(err)s"
msgstr ""
"ストレージ・ボリューム %(name)s をストレージ・プール %(pool)s に作成できませ"
"ん。詳細: %(err)s"
#, python-format
msgid "Unable to wipe storage volumes %(name)s. Details: %(err)s"
msgstr "ストレージ・ボリューム %(name)s をワイプできません。詳細: %(err)s"
#, python-format
msgid "Unable to delete storage volume %(name)s. Details: %(err)s"
msgstr "ストレージ・ボリューム %(name)s を削除できません。詳細: %(err)s"
#, python-format
msgid "Unable to resize storage volume %(name)s. Details: %(err)s"
msgstr "ストレージ・ボリューム %(name)s をサイズ変更できません。詳細: %(err)s"
#, python-format
msgid "Storage type %(type)s does not support volume create and delete"
msgstr ""
"ストレージ・タイプ %(type)s ではボリュームの作成および削除はサポートされてい"
"ません"
msgid "Storage volume name must be a string"
msgstr "ストレージ・ボリューム名はストリングでなければなりません"
msgid "Storage volume allocation must be an integer number"
msgstr "ストレージ・ボリューム割り振りは整数でなければなりません"
msgid ""
"Storage volume format not supported. Valid formats: qcow, qcow2, qed, raw, "
"vmdk, vpc."
msgstr ""
"ストレージ・ボリューム・フォーマットがサポートされていません。有効なフォー"
"マット: qcow、qcow2、qed、raw、vmdk、vpc。"
msgid "Storage volume requires a volume name"
msgstr "ストレージ・ボリュームにはボリューム名が必要です"
#, python-format
msgid ""
"Unable to update database with storage volume information due error: %(err)s"
msgstr ""
"次のエラーのため、データベースをストレージ・ボリューム情報で更新できません:"
"%(err)s"
#, python-format
msgid "Only one of parameter %(param)s can be specified"
msgstr "1 つのパラメーター %(param)s のみを指定できます"
#, python-format
msgid "Create volume from %(param)s is not supported"
msgstr "%(param)s からのボリュームの作成はサポートされていません"
msgid "Storage volume capacity must be an integer number."
msgstr "ストレージ・ボリューム容量は整数値でなければなりません。"
msgid "Storage volume URL must be http://, https://, ftp:// or ftps://."
msgstr ""
"ストレージ・ボリューム URL は http://、https://、ftp://、または ftps:// でな"
"ければなりません。"
#, python-format
msgid "Unable to access file %(url)s. Please, check it."
msgstr "ファイル %(url)s にアクセスできません。確認してください。"
#, python-format
msgid ""
"Unable to clone storage volume '%(name)s' in pool '%(pool)s'. Details: "
"%(err)s"
msgstr ""
"ストレージ・ボリューム「%(name)s」のクローンをプール「%(pool)s」に作成できま"
"せん。詳細: %(err)s"
msgid "Specify chunk data and its size to upload a file."
msgstr ""
"ファイルをアップロードするには、チャンク・データとそのサイズを指定してくださ"
"い。"
msgid "In order to upload a storage volume, specify the 'upload' parameter."
msgstr ""
"ストレージ・ボリュームをアップロードするには、「upload」パラメーターを指定し"
"てください。"
msgid ""
"Unable to upload chunk data as it does not match with requested chunk size."
msgstr ""
"要求されたチャンク・サイズに一致しないため、チャンク・データをアップロードで"
"きません。"
#, python-format
msgid "The storage volume %(vol)s is not under an upload process."
msgstr ""
"ストレージ・ボリューム %(vol)s はアップロード・プロセス中ではありません。"
msgid "The upload chunk data will exceed the storage volume size."
msgstr ""
"アップロード・チャンク・データはストレージ・ボリューム・サイズを超過します。"
#, python-format
msgid "Unable to upload chunk data to storage volume. Details: %(err)s."
msgstr ""
"チャンク・データをストレージ・ボリュームにアップロードできません。詳細: "
"%(err)s。"
#, python-format
msgid "Interface %(name)s does not exist"
msgstr "インターフェース %(name)s は存在しません"
#, python-format
msgid ""
"Failed to list interfaces. Invalid _inuse parameter. Supported options for "
"_inuse are: %(supported_inuse)s"
msgstr ""
"インターフェースをリストできませんでした。_inuse パラメーターが無効です。"
"_inuse に対してサポートされているオプションは次のとおりです: "
"%(supported_inuse)s"
#, python-format
msgid "Network %(name)s already exists"
msgstr "ネットワーク %(name)s は既に存在します"
#, python-format
msgid "Network %(name)s does not exist"
msgstr "ネットワーク %(name)s は存在しません"
#, python-format
msgid "Subnet %(subnet)s specified for network %(network)s is not valid."
msgstr ""
"ネットワーク %(network)s に指定されたサブネット %(subnet)s は無効です。"
msgid "Specify a network interface to create bridged or macvtap networks."
msgstr ""
"ブリッジ・ネットワークまたは macvtap ネットワークを作成するには、ネットワー"
"ク・インターフェースを指定してください。"
#, python-format
msgid "Unable to delete or update active network %(name)s"
msgstr "アクティブ・ネットワーク %(name)s を削除/更新できません"
#, python-format
msgid "Interface %(iface)s specified for network %(network)s is already in use"
msgstr ""
"ネットワーク %(network)s に指定されたインターフェース %(iface)s は既に使用中"
"です"
msgid "Interface should be bare NIC, bonding or bridge device."
msgstr ""
"インターフェースはベア NIC、結合、またはブリッジ・デバイスでなければなりませ"
"ん。"
#, python-format
msgid "Unable to create or update network %(name)s. Details: %(err)s"
msgstr "ネットワーク %(name)s を作成/更新できません。詳細: %(err)s"
#, python-format
msgid "Unable to find a free IP address for network '%(name)s'"
msgstr "ネットワーク「%(name)s」のフリー IP アドレスが見つかりません"
#, python-format
msgid "The interface %(iface)s already exists."
msgstr "インターフェース %(iface)s は既に存在します。"
msgid "Network name must be a string without slashes (/) or quotes (\")"
msgstr ""
"ネットワーク名はスラッシュ (/) または引用符 (\") のないストリングでなければな"
"りません"
msgid ""
"Supported network types are isolated, NAT, macvtap, bridge, vepa and "
"passthrough."
msgstr ""
"サポートされているネットワーク・タイプは isolated、NAT、macvtap、bridge、"
"vepa、および passthrough です。"
msgid "Network subnet must be a string with IP address and prefix or netmask"
msgstr ""
"ネットワーク・サブネットは、IP アドレスとプレフィックスまたはネットマスクのあ"
"るストリングでなければなりません"
msgid "Network interfaces must be an array."
msgstr "ネットワーク・インターフェースは配列でなければなりません。"
msgid "Network VLAN ID must be an integer between 1 and 4094"
msgstr "ネットワーク VLAN ID は、1 から 4094 までの整数でなければなりません"
msgid "Specify name and type to create a Network"
msgstr "ネットワークを作成するには、名前とタイプを指定してください"
#, python-format
msgid ""
"Unable to delete or update network %(name)s as it is linked to some virtual "
"machines (%(vms)s) and/or templates (%(tmpls)s)."
msgstr ""
#, python-format
msgid ""
"Unable to deactivate network %(name)s as it is linked to are some virtual "
"machines (%(vms)s) and/or templates (%(tmpls)s)."
msgstr ""
#, python-format
msgid "Bridge device %(name)s can not be the trunk device of a VLAN."
msgstr ""
"ブリッジ・デバイス %(name)s は VLAN のトランク・デバイスにはできません。"
#, python-format
msgid "Failed to activate interface %(iface)s: %(err)s."
msgstr "インターフェース %(iface)s のアクティブ化に失敗しました: %(err)s。"
#, python-format
msgid ""
"Failed to activate interface %(iface)s. Please check the physical link "
"status."
msgstr ""
"インターフェース %(iface)s のアクティブ化に失敗しました。物理リンク状況を調べ"
"てください。"
#, python-format
msgid "Failed to start network %(name)s. Details: %(err)s"
msgstr "ネットワーク %(name)s の開始に失敗しました。詳細: %(err)s"
#, python-format
msgid "Unable to redefine interface %(name)s. Details: %(err)s"
msgstr "インターフェース %(name)s を再定義できません。詳細: %(err)s"
#, python-format
msgid "Unable to create bridge %(name)s. Details: %(err)s"
msgstr "ブリッジ %(name)s を作成できません。詳細: %(err)s"
msgid ""
"Unable to create bridge with NetworkManager enabled. Disable it and try "
"again."
msgstr ""
"ネットワーク・マネージャーを使用可能にしてブリッジを作成することができませ"
"ん。これを使用不可にして、再試行してください。"
msgid "Interface should be bare NIC or bonding."
msgstr "インターフェースはベア NIC または結合でなければなりません。"
msgid "Network interfaces parameter must contain at least one interface."
msgstr ""
"Network interfaces パラメーターには 1 つ以上のインターフェースが含まれていな"
"ければなりません。"
msgid "Only one interface is allowed for 'bridge' and 'macvtap' networks."
msgstr ""
"「bridge」ネットワークおよび「macvtap」ネットワークに使用できるインターフェー"
"スは 1 つのみです。"
msgid "Subnet is not a valid parameter for this type of virtual network."
msgstr ""
"Subnet は、このタイプの仮想ネットワークには有効なパラメーターではありません。"
msgid ""
"VLAN ID and interfaces are not valid parameters for this type of virtual "
"network."
msgstr ""
"VLAN ID および interfaces は、このタイプの仮想ネットワークには有効なパラメー"
"ターではありません。"
#, python-format
msgid "Storage server %(server)s was not used by Kimchi"
msgstr "ストレージ・サーバー %(server)s は Kimchi で使用されていませんでした"
#, python-format
msgid "Distro '%(name)s' does not exist"
msgstr "Distro「%(name)s」は存在しません"
#, python-format
msgid "Node device '%(name)s' not found"
msgstr "ノード・デバイス「%(name)s」が見つかりません"
msgid "Conflicting flag filters specified."
msgstr "競合するフラグ・フィルターが指定されました。"
msgid "Unable to choose a virtual machine name"
msgstr "仮想マシン名を選択できません"
msgid "Cannot upgrade objectstore data."
msgstr "オブジェクト・ストア・データをアップグレードできません。"
msgid "Invalid storage type. Types supported: 'cdrom', 'disk'"
msgstr ""
"ストレージ・タイプが無効です。サポートされているタイプは「cdrom」および"
"「disk」です"
#, python-format
msgid "The path '%(value)s' is not a valid local/remote path for the device"
msgstr ""
"パス「%(value)s」はデバイスに有効なローカルまたはリモートのパスではありません"
msgid "Only CDROM path can be update."
msgstr "CDROM パスのみが更新可能です。"
#, python-format
msgid ""
"The storage device %(dev_name)s does not exist in the virtual machine "
"%(vm_name)s"
msgstr ""
"ストレージ・デバイス %(dev_name)s は仮想マシン %(vm_name)s には存在していませ"
"ん"
#, python-format
msgid "Error while creating new storage device: %(error)s"
msgstr "新しいストレージ・デバイスの作成中にエラーが発生しました: %(error)s"
#, python-format
msgid "Error while updating storage device: %(error)s"
msgstr "ストレージ・デバイスの更新中にエラーが発生しました: %(error)s"
#, python-format
msgid "Error while removing storage device: %(error)s"
msgstr "ストレージ・デバイスの除去中にエラーが発生しました: %(error)s"
msgid "Do not support IDE device hot plug"
msgstr "IDE デバイス・ホット・プラグはサポートされていません"
msgid ""
"Specify type and path or type and pool/volume to add a new virtual machine "
"disk"
msgstr ""
"新規仮想マシン・ディスクを追加するには、タイプとパス、またはタイプとプール/ボ"
"リュームを指定してください"
msgid "Specify path to update virtual machine disk"
msgstr "仮想マシン・ディスクを更新するには、パスを指定してください"
#, python-format
msgid "Controller type %(type)s limitation of %(limit)s devices reached"
msgstr ""
"コントローラー・タイプ %(type)s のデバイスの制限 %(limit)s に達しました"
#, python-format
msgid "Cannot retrieve disk path information for given pool/volume: %(error)s"
msgstr ""
"指定のプールまたはボリュームのディスク・パス情報を取得できません: %(error)s"
msgid "Volume already in use by other virtual machine."
msgstr "ボリュームは既に他の仮想マシンで使用中です。"
msgid ""
"Only one of path or pool/volume can be specified to add a new virtual "
"machine disk"
msgstr ""
"新規仮想マシン・ディスクを追加するために指定できるパスやプール/ボリュームは "
"1 つのみです"
#, python-format
msgid ""
"Volume chosen with format %(format)s does not fit in the storage type "
"%(type)s"
msgstr ""
"フォーマット %(format)s で選択されたボリュームがストレージ・タイプ%(type)s に"
"適合しません"
msgid "On s390x arch one of pool, path of dir_path must be specified"
msgstr ""
"s390x アーキテクチャーでは、pool、path、または dir_path のいずれかを指定する"
"必要があります"
msgid ""
"On s390x arch 'format' must be specified while attaching disk to virtual "
"machine"
msgstr ""
"s390x アーキテクチャーでは、ディスクを仮想マシンに接続するときに「format」を"
"指定する必要があります"
#, python-format
msgid "Virtual disk already exists on the system: %(disk_path)s"
msgstr "仮想ディスクは既にシステム上に存在しています: %(disk_path)s"
#, python-format
msgid ""
"Unable to create snapshot '%(name)s' on virtual machine '%(vm)s'. Details: "
"%(err)s"
msgstr ""
"仮想マシン「%(vm)s」でスナップショット「%(name)s」を作成できません。詳細: "
"%(err)s"
#, python-format
msgid "Snapshot '%(name)s' does not exist on virtual machine '%(vm)s'."
msgstr "スナップショット「%(name)s」は仮想マシン「%(vm)s」に存在しません。"
#, python-format
msgid ""
"Unable to retrieve snapshot '%(name)s' on virtual machine '%(vm)s'. Details: "
"%(err)s"
msgstr ""
"仮想マシン「%(vm)s」でスナップショット「%(name)s」を取得できません。詳細: "
"%(err)s"
#, python-format
msgid "Unable to list snapshots on virtual machine '%(vm)s'. Details: %(err)s"
msgstr ""
"仮想マシン「%(vm)s」でスナップショットをリストできません。詳細: %(err)s"
#, python-format
msgid ""
"Unable to delete snapshot '%(name)s' on virtual machine '%(vm)s'. Details: "
"%(err)s"
msgstr ""
"仮想マシン「%(vm)s」でスナップショット「%(name)s」を削除できません。詳細: "
"%(err)s"
#, python-format
msgid ""
"Unable to retrieve current snapshot of virtual machine '%(vm)s'. Details: "
"%(err)s"
msgstr ""
"仮想マシン「%(vm)s」の最新スナップショットを取得できません。詳細: %(err)s"
#, python-format
msgid ""
"Unable to revert virtual machine '%(vm)s' to snapshot '%(name)s'. Details: "
"%(err)s"
msgstr ""
"仮想マシン「%(vm)s」をスナップショット「%(name)s」に戻すことができません。詳"
"細: %(err)s"
#, python-format
msgid ""
"Unable to create snapshot of virtual machine '%(vm)s' because it contains a "
"disk with format '%(format)s'; only 'qcow2' is supported."
msgstr ""
"仮想マシン「%(vm)s」にはフォーマット「%(format)s」のディスクが含まれているた"
"め、この仮想マシンのスナップショットを作成できません。「qcow2」のみがサポート"
"されています。"
msgid ""
"The number of vCPUs must be less than or equal the maximum number of vCPUs "
"specified."
msgstr "vCPU の数は、指定された vCPU の最大数以下でなければなりません。"
msgid ""
"When CPU topology is defined, maximum number of vCPUs must be a product of "
"sockets, cores, and threads."
msgstr ""
"CPU トポロジーが定義されている場合、vCPU の最大数はソケット、コア、およびス"
"レッドの積でなければなりません。"
msgid "This host (or current configuration) does not allow CPU topology."
msgstr "このホスト (または現行構成) では CPU トポロジーは許可されていません。"
msgid "The maximum number of vCPUs is too large for this system."
msgstr "vCPU の最大数がこのシステムには大きすぎます。"
msgid ""
"When CPU topology is defined, CPUs must be a multiple of the 'threads' "
"number defined."
msgstr ""
msgid ""
"When CPU topology is specified, sockets, cores and threads are required "
"paramaters."
msgstr ""
"CPU トポロジーが指定される場合、sockets、cores、および threads は必須パラメー"
"ターです。"
msgid ""
"Parameter 'cpu_info' expects an object with fields among: 'vcpus', "
"'maxvcpus', 'topology'."
msgstr ""
"パラメーター「cpu_info」では、「vcpus」、「maxvcpus」、「topology」のいずれか"
"のフィールドでオブジェクトが予想されます。"
msgid ""
"Parameter 'topology' expects an object with fields among: 'sockets', "
"'cores', 'threads'."
msgstr ""
"パラメーター「topology」では、「sockets」、「cores」、「threads」のいずれかの"
"フィールドでオブジェクトが予想されます。"
msgid "Unable to update Max CPU or CPU topology when guest is running."
msgstr ""
#, python-format
msgid "Unable to hot plug/unplug CPUs. Details: %(err)s"
msgstr "ストレージ・プールをリストできません。詳細: %(err)s"
#, python-format
msgid "Invalid volume group name parameter: %(name)s."
msgstr "ボリューム・グループ名パラメーターが無効です: %(name)s。"
msgid ""
"Unable to establish connection with libvirt. Please check your libvirt URI "
"which is often defined in /etc/libvirt/libvirt.conf"
msgstr ""
"libvirt との接続を確立できません。libvirt URI (多くの場合、/etc/libvirt/"
"libvirt.conf に定義されています) を調べてください。"
msgid ""
"Libvirt service is not active. Please start the libvirt service in your host "
"system."
msgstr ""
"Libvirt サービスがアクティブではありません。ご使用のホスト・システムで "
"libvirt サービスを開始してください。"
msgid "Failed to register the default event implementation."
msgstr "デフォルト・イベント実装環境を登録できませんでした。"
msgid "Failed to register timeout event."
msgstr "タイムアウト・イベントを登録できませんでした。"
msgid "Failed to Run the default event implementation."
msgstr "デフォルト・イベント実装を実行できませんでした。"
#, python-format
msgid ""
"I/O error on guest '%(vm)s': storage pool out of space for %(devAlias)s "
"(%(srcPath)s)."
msgstr ""
"ゲスト「%(vm)s」で入出力エラーが発生しました: %(devAlias)s (%(srcPath)s) 用の"
"スペースがストレージ・プールにありません。"
#, python-format
msgid "Create virtual network '%(name)s' type '%(connection)s'"
msgstr "仮想ネットワーク「%(name)s」タイプ「%(connection)s」の作成"
#, python-format
msgid "Remove virtual network '%(ident)s'"
msgstr "仮想ネットワーク「%(ident)s」の除去"
#, python-format
msgid "Update virtual network '%(ident)s'"
msgstr "仮想ネットワーク「%(ident)s」の更新"
#, python-format
msgid "Activate virtual network '%(ident)s'"
msgstr "仮想ネットワーク「%(ident)s」のアクティブ化"
#, python-format
msgid "Deactivate virtual network '%(ident)s'"
msgstr "仮想ネットワーク「%(ident)s」の非アクティブ化"
#, python-format
msgid "Create storage pool '%(name)s' type '%(type)s'"
msgstr "ストレージ・プール「%(name)s」タイプ「%(type)s」の作成"
#, python-format
msgid "Remove storage pool '%(ident)s'"
msgstr "ストレージ・プール「%(ident)s」の除去"
#, python-format
msgid "Update storage pool '%(ident)s'"
msgstr "ストレージ・プール「%(ident)s」の更新"
#, python-format
msgid "Activate storage pool '%(ident)s'"
msgstr "ストレージ・プール「%(ident)s」のアクティブ化"
#, python-format
msgid "Deactivate storage pool '%(ident)s'"
msgstr "ストレージ・プール「%(ident)s」の非アクティブ化"
#, python-format
msgid "Create snapshot '%(name)s' at guest '%(vm)s'"
msgstr "スナップショット「%(name)s」をゲスト「%(vm)s」で作成"
#, python-format
msgid "Remove snapshot '%(ident)s' from guest '%(vm)s'"
msgstr "スナップショット「%(ident)s」をゲスト「%(vm)s」から除去"
#, python-format
msgid "Revert guest '%(vm)s' to snapshot '%(ident)s'"
msgstr "ゲスト「%(vm)s」をスナップショット「%(ident)s」に戻す"
#, python-format
msgid "Create template '%(name)s'"
msgstr "テンプレート「%(name)s」の作成"
#, python-format
msgid "Remove template '%(ident)s'"
msgstr "テンプレート「%(ident)s」の除去"
#, python-format
msgid "Update template '%(ident)s'"
msgstr "テンプレート「%(ident)s」の更新"
#, python-format
msgid "Clone template '%(ident)s'"
msgstr "テンプレート「%(ident)s」のクローンを作成"
#, python-format
msgid "Create guest '%(name)s' from template '%(template)s'"
msgstr "ゲスト「%(name)s」をテンプレート「%(template)s」から作成"
#, python-format
msgid "Remove guest '%(ident)s'"
msgstr "ゲスト「%(ident)s」の除去"
#, python-format
msgid "Edit guest '%(ident)s'"
msgstr "ゲスト「%(ident)s」の編集"
#, python-format
msgid "Start guest '%(ident)s'"
msgstr "ゲスト「%(ident)s」の開始"
#, python-format
msgid "Power off guest '%(ident)s'"
msgstr "ゲスト「%(ident)s」の電源をオフにする"
#, python-format
msgid "Shutdown guest '%(ident)s'"
msgstr "ゲスト「%(ident)s」のシャットダウン"
#, python-format
msgid "Restart guest '%(ident)s'"
msgstr "ゲスト「%(ident)s」の再始動"
#, python-format
msgid "Connect to guest '%(ident)s' through novnc/spice"
msgstr "novnc/spice を使用してゲスト「%(ident)s」に接続"
#, python-format
msgid "Clone guest '%(ident)s'"
msgstr "ゲスト「%(ident)s」のクローンを作成"
#, python-format
msgid "Migrate guest '%(ident)s' to '%(remote_host)s'"
msgstr "ゲスト「%(ident)s」を「%(remote_host)s」にマイグレーション"
#, python-format
msgid "Suspend guest '%(ident)s'"
msgstr "ゲスト「%(ident)s」の中断"
#, python-format
msgid "Resume guest '%(ident)s'"
msgstr "ゲスト「%(ident)s」の再開"
#, python-format
msgid "Connect to guest '%(ident)s' through serial"
msgstr "シリアルを使用してゲスト「%(ident)s」に接続"
#, python-format
msgid "Attach host device '%(name)s' to guest '%(vmid)s'"
msgstr "ホスト・デバイス「%(name)s」をゲスト「%(vmid)s」に接続"
#, python-format
msgid "Detach host device '%(ident)s' from guest '%(vmid)s'"
msgstr "ホスト・デバイス「%(ident)s」をゲスト「%(vmid)s」から切り離す"
#, python-format
msgid "Attach network interface '%(network)s' to guest '%(vm)s'"
msgstr "ネットワーク・インターフェース「%(network)s」をゲスト「%(vm)s」に接続"
#, python-format
msgid "Detach network interface '%(ident)s' from guest '%(vm)s'"
msgstr ""
"ネットワーク・インターフェース「%(ident)s」をゲスト「%(vm)s」から切り離す"
#, python-format
msgid "Update network interface '%(ident)s' at guest '%(vm)s'"
msgstr "ゲスト「%(vm)s」でネットワーク・インターフェース「%(ident)s」を更新"
#, python-format
msgid "Attach %(type)s storage '%(path)s' to guest '%(vm)s'"
msgstr "%(type)s ストレージ「%(path)s」をゲスト「%(vm)s」に接続"
#, python-format
msgid "Remove storage '%(ident)s' from guest '%(vm)s'"
msgstr "ストレージ「%(ident)s」をゲスト「%(vm)s」から除去"
#, python-format
msgid "Update storage '%(ident)s' at guest '%(vm)s'"
msgstr "ゲスト「%(vm)s」でストレージ「%(ident)s」を更新"
#, python-format
msgid "Create storage volume '%(name)s' at pool '%(pool)s'"
msgstr "ストレージ・ボリューム「%(name)s」をプール「%(pool)s」に作成"
#, python-format
msgid "Remove storage volume '%(ident)s' from pool '%(pool)s'"
msgstr "ストレージ・ボリューム「%(ident)s」をプール「%(pool)s」から除去"
#, python-format
msgid "Update storage volume '%(ident)s' at pool '%(pool)s'"
msgstr "プール「%(pool)s」でストレージ・ボリューム「%(ident)s」を更新"
#, python-format
msgid "Wipe storage volume '%(ident)s' off pool '%(pool)s'"
msgstr "ストレージ・ボリューム「%(ident)s」をプール「%(pool)s」からワイプ"
#, python-format
msgid "Resize storage volume '%(ident)s' at pool '%(pool)s' with size %(size)s"
msgstr ""
"プール「%(pool)s」にあるストレージ・ボリューム「%(ident)s」のサイズをサイズ "
"%(size)s で変更"
#, python-format
msgid "Clone storage volume '%(ident)s' at pool '%(pool)s'"
msgstr ""
"ストレージ・ボリューム「%(ident)s」のクローンをプール「%(pool)s」に作成"
msgid "Create a New Virtual Machine"
msgstr "新規仮想マシンの作成"
msgid "Virtual Machine Name"
msgstr "仮想マシン名"
msgid ""
"The name used to identify the virtual machine. If omitted, a name will be "
"chosen based on the template used."
msgstr ""
"この名前は仮想マシンを識別するために使用されます。省略されると、使用している"
"テンプレートを基準に選択されます。"
msgid "Please create a template first."
msgstr "まずテンプレートを作成してください。"
msgid "Create a Template"
msgstr "テンプレートの作成"
msgid "Please choose a template."
msgstr "テンプレートを選択してください。"
msgid "This template has invalid parameters."
msgstr "このテンプレートには、無効なパラメーターがあります。"
msgid "This template has invalid parameters"
msgstr "このテンプレートには、無効なパラメーターがあります"
msgid "OS"
msgstr "OS"
msgid "Version"
msgstr "バージョン"
msgid "Current CPUs"
msgstr "現行 CPU"
msgid "Memory"
msgstr "メモリー"
msgid "Create"
msgstr "作成"
msgid "Creating..."
msgstr "作成中..."
msgid "Cancel"
msgstr "取消"
msgid "Clone a Guest"
msgstr "ゲストのクローンを作成"
msgid ""
"When the target guest has SCSI or iSCSI volumes, they will be cloned on the "
"default storage pool. The same will happen when the target pool does not "
"have enough space to clone the volumes. Do you want to continue?"
msgstr ""
"ターゲット・ゲストに SCSI ボリュームまたは iSCSI ボリュームがある場合は、その"
"ボリュームのクローンがデフォルト・ストレージ・プール上に作成されます。ボ"
"リュームのクローンを作成するだけの十分なスペースがターゲット・プールにない場"
"合も同様です。続行しますか ?"
msgid "Number of times to clone"
msgstr "クローンを作成する回数"
msgid "Continue"
msgstr "続行"
msgid "Edit Guest"
msgstr "ゲストの編集"
msgid "General"
msgstr "一般"
msgid "Storage"
msgstr "ストレージ"
msgid "Interface"
msgstr "インターフェース"
msgid "Permission"
msgstr "許可"
msgid "Pci"
msgstr "Pci"
msgid "Snapshot"
msgstr "スナップショット"
msgid "Processor"
msgstr "プロセッサー"
msgid "Name"
msgstr "名前"
msgid "Memory (MB)"
msgstr "メモリー (MB)"
msgid "More"
msgstr "詳細"
msgid "Max Memory (MB)"
msgstr "最大メモリー (MB)"
msgid "Host does not support memory hotplug"
msgstr "ホストはメモリー・ホット・プラグをサポートしていません"
msgid "Icon"
msgstr "アイコン"
msgid "Console"
msgstr "コンソール"
msgid "Nothing selected"
msgstr "何も選択されていません"
msgid "sclp"
msgstr "sclp"
msgid "virtio"
msgstr "virtio"
msgid ""
"Select which items for boot order and grad them when needed to order them. "
"At least one option must be selected."
msgstr ""
msgid "Add"
msgstr "追加"
msgid "Device"
msgstr "デバイス"
msgid "Path"
msgstr "パス"
msgid "Actions"
msgstr "アクション"
msgid "Network"
msgstr " ネットワーク"
msgid "Type"
msgstr "タイプ"
msgid "MAC Address"
msgstr "MAC アドレス"
msgid "IP Address"
msgstr "IP アドレス"
msgid "Network/Interface"
msgstr "ネットワーク/インターフェース"
msgid "Mode"
msgstr "モード"
msgid "Available system users and groups"
msgstr "使用可能なシステム・ユーザーおよびグループ"
msgid "Users"
msgstr "ユーザー"
msgid "Groups"
msgstr "グループ"
msgid "Selected system users and groups"
msgstr "選択されたシステム・ユーザーおよびグループ"
msgid "User"
msgstr "ユーザー"
msgid "All"
msgstr "すべて"
msgid "To Add"
msgstr "追加予定"
msgid "Added"
msgstr "追加済み"
msgid "Filter"
msgstr "フィルター"
msgid "Status"
msgstr "状況"
msgid "Product"
msgstr "製品"
msgid "Vendor"
msgstr "ベンダー"
msgid "Loading"
msgstr "ロード中"
msgid "Created"
msgstr "作成日"
msgid "Current CPU Number"
msgstr "現行 CPU 数"
msgid ""
"Current CPU must be equal or lower than the Maximum CPU value. If a topology "
"is set, it must be also be a multiple of the 'threads' value."
msgstr ""
msgid "Max CPU"
msgstr "最大 CPU"
msgid ""
"Unable to edit maximum CPU or CPU topology when editing a running or paused "
"virtual machine."
msgstr ""
msgid ""
"If a topology is set, this value will be the product of sockets * times * "
"cores."
msgstr ""
msgid "Manually set CPU topology"
msgstr "CPU トポロジーを手動で設定"
msgid "Sockets"
msgstr ""
msgid "Cores"
msgstr "コア"
msgid "Threads"
msgstr "スレッド"
msgid "Save"
msgstr "保存"
msgid "Replace"
msgstr "置換"
msgid "Detach"
msgstr "切り離し"
msgid "Remove"
msgstr "除去"
msgid "Edit"
msgstr "編集"
msgid "LDAP User ID,e.g.foo@foo.com"
msgstr "LDAP ユーザー ID (例: foo@foo.com)"
msgid "Revert"
msgstr "戻す"
msgid "Running"
msgstr "実行中"
msgid "Disconnected"
msgstr "切断済み"
msgid "Starting"
msgstr "開始中"
msgid "Crashed"
msgstr "異常終了"
msgid "Unknown"
msgstr "不明"
msgid "Paused"
msgstr "一時停止"
msgid "Suspended"
msgstr "中断状態"
msgid "Resetting"
msgstr "リセット中"
msgid "View Console"
msgstr "コンソールの表示"
msgid "View Serial"
msgstr "シリアルの表示"
msgid "Clone"
msgstr "クローン"
msgid "Migrate"
msgstr "マイグレーション"
msgid "Reset"
msgstr "リセット"
msgid "Pause"
msgstr "一時停止"
msgid "Resume"
msgstr "再開"
msgid "Shut Down"
msgstr "シャットダウン"
msgid "Start"
msgstr "開始"
msgid "Power Off"
msgstr "電源オフ"
msgid "Delete"
msgstr "削除"
msgid "No Data Available"
msgstr "使用可能なデータがありません"
msgid "Processors Utilization"
msgstr "プロセッサー使用状況"
msgid "Memory Utilization"
msgstr "メモリー使用状況"
msgid "Storage I/O"
msgstr "ストレージ入出力"
msgid "Network I/O"
msgstr "ネットワーク入出力"
msgid "Migrate a Guest"
msgstr "ゲストのマイグレーション"
msgid ""
"Disclaimer: This process cannot be stopped after started, can take a long "
"time to complete and will turn off the VM on this Hypervisor when it is "
"successfully migrated to the remote destination."
msgstr ""
"特記事項: このプロセスは開始後は停止できません。完了までに長い時間がかかる可"
"能性があります。リモート宛先へのマイグレーションが正常に行われると、このハイ"
"パーバイザー上の VM はオフになります。"
msgid "Remote Server"
msgstr "リモート・サーバー"
msgid "IP Address or Hostname"
msgstr "IP アドレスまたはホスト名"
msgid ""
"The following fields are optional. Fill them if you want Kimchi to setup a "
"password-less ssh session between the localhost and the remote host. The "
"setup process will only be successful if the user has 'SUDO ALL' permission "
"in the remote machine."
msgstr ""
"次のフィールドはオプションです。ローカル・ホストとリモート・ホストの間でパス"
"ワードなしの ssh セッションを Kimchi にセットアップさせたい場合は、これらの"
"フィールドに値を入力してください。リモート・マシンにおいてユーザーに「SUDO "
"ALL」許可がある場合に限り、セットアップ・プロセスは正常に行われます。"
msgid "Username of the remote host"
msgstr "リモート・ホストのユーザー名"
msgid "Password"
msgstr "パスワード"
msgid "Password of the user in the remote host"
msgstr "リモート・ホストのユーザーのパスワード"
msgid "Use RDMA transport"
msgstr ""
msgid ""
"Check this option only if RDMA is properly configured in both source and "
"destination hosts, otherwise migration will fail."
msgstr ""
msgid "Delete this VM when the migration is completed"
msgstr "マイグレーションが完了したときに、この VM を削除"
msgid "Add a Storage Device to VM"
msgstr "VM にストレージ・デバイスを追加"
msgid "Device Type"
msgstr "デバイス・タイプ"
msgid ""
"The device type. Currently, \"cdrom\" and \"disk\" are supported. If the "
"guest is running, only \"disk\" is supported."
msgstr ""
"デバイス・タイプを示します。現在、「cdrom」と「disk」がサポート対象です。ゲス"
"トで実行している場合は、「disk」のみがサポートされます。"
msgid "Create a new disk"
msgstr "新規ディスクの作成"
msgid "Select an existing disk"
msgstr "既存ディスクの選択"
msgid "Source"
msgstr "ソース"
msgid "Storage based on Libvirt pool or direct block device"
msgstr "Libvirt プールまたは直接ブロック・デバイスに基づくストレージ"
msgid "Storage Pool"
msgstr "ストレージ・プール"
msgid "Storage pool to create the volume in"
msgstr "ボリュームの作成先のストレージ・プール"
msgid "Disk Size (GB)"
msgstr "ディスク・サイズ (GB)"
msgid "New disk size to be created"
msgstr "作成される新規ディスクのサイズ"
msgid "Format"
msgstr "フォーマット"
msgid "Format of the new disk to be created"
msgstr "作成される新規ディスクのフォーマット"
msgid "Directory Path"
msgstr "ディレクトリー・パス"
msgid "Provide a directory path"
msgstr "ディレクトリー・パスの指定"
msgid "Storage pool in which the volume is located in"
msgstr "当該ボリュームがあるストレージ・プール"
msgid "Storage Volume"
msgstr "ストレージ・ボリューム"
msgid "Storage volume to be attached"
msgstr "接続されるストレージ・ボリューム"
msgid "Disk Path"
msgstr "ディスク・パス"
msgid "Provide a block device"
msgstr "ブロック・デバイスの指定"
msgid "File Path"
msgstr "ファイル・パス"
msgid "The ISO file path in the server for CDROM."
msgstr "サーバー内での CDROM の ISO ファイル・パス。"
msgid "Attach"
msgstr "接続"
msgid "Host"
msgstr "ホスト"
msgid "Guests"
msgstr "ゲスト"
msgid "Templates"
msgstr "テンプレート"
msgid "This is not a valid Linux path"
msgstr "有効な Linux パスではありません"
msgid "Unable to read file."
msgstr "ファイルを読み取ることができません。"
msgid "Error while uploading file."
msgstr "ファイルのアップロード中にエラーが発生しました。"
msgid "Delete Confirmation"
msgstr "削除の確認"
msgid "OK"
msgstr "OK"
msgid "Confirm"
msgstr "確認"
msgid "Warning"
msgstr "警告"
msgid "Cloning..."
msgstr "クローン作成中..."
msgid "Saving..."
msgstr "保存中..."
msgid "Migrating..."
msgstr "マイグレーション中..."
msgid "No ISO found"
msgstr "ISO が見つかりません"
msgid "Add Template"
msgstr "テンプレートの追加"
msgid "This may take a long time. Do you want to continue?"
msgstr "これには時間がかかることがあります。続行しますか ?"
msgid ""
"This will permanently delete the %1 template. Would you like to continue?"
msgstr "これにより %1 テンプレートは完全に削除されます。続行しますか?"
msgid "View Table"
msgstr "テーブルの表示"
msgid "View Gallery"
msgstr "ギャラリーの表示"
msgid "Not Available"
msgstr "使用不可"
msgid "Please check the invalid Storage Pools"
msgstr "無効なストレージ・プールを確認してください"
msgid "Please check the invalid Storage Pools or Paths"
msgstr "無効なストレージ・プールまたはパスを確認してください"
msgid "macvtap"
msgstr "macvtap"
msgid "ovs"
msgstr "ovs"
msgid "network"
msgstr "ネットワーク"
msgid ""
"This will delete the %1 virtual machine and its virtual disks. This "
"operation cannot be undone. Would you like to continue?"
msgstr ""
"これにより、%1 仮想マシンとその仮想ディスクが削除されます。この操作は元に戻す"
"ことができません。続行しますか?"
msgid "Power off Confirmation"
msgstr "電源オフの確認"
msgid ""
"This action may produce undesirable results, for example unflushed disk "
"cache in the %1 guest. Would you like to continue?"
msgstr ""
"このアクションでは、望ましくない結果 (例えば、ゲストにおいて %1 ディスク・"
"キャッシュがフラッシュされないなど) になる可能性があります。続行しますか?"
msgid "Reset Confirmation"
msgstr "リセットの確認"
msgid ""
"There is a risk of data loss caused by reset without the %1 guest OS "
"shutdown. Would you like to continue?"
msgstr ""
"%1 ゲスト OS をシャットダウンせずにリセットするとデータが失われる危険性があり"
"ます。続行しますか?"
msgid "Shut Down Confirmation"
msgstr "シャットダウンの確認"
msgid ""
"Note the %1 guest OS may ignore this request. Would you like to continue?"
msgstr ""
"%1 ゲスト OS ではこの要求が無視される可能性があることに注意してください。続行"
"しますか?"
msgid "Virtual Machine delete Confirmation"
msgstr "仮想マシンの削除確認"
msgid ""
"The %1 virtual machine is not persistent. Power Off will delete it. Continue?"
msgstr ""
"%1 仮想マシンは永続的ではありません。電源オフにより削除されます。続行します"
"か?"
msgid "Add Guest"
msgstr ""
msgid "Input is not a number"
msgstr "入力が数値ではありません"
msgid "Memory value cannot be higher than Max Memory value"
msgstr "メモリー値は最大メモリー値よりも大きくすることはできません"
msgid ""
"For better performance it is recommended a threads per core value not "
"greater than %1."
msgstr ""
msgid ""
"This CDROM will be detached permanently and you can re-attach it. Continue "
"to detach it?"
msgstr ""
"この CDROM は永続的に切り離されますが、再接続できます。切り離しを続行します"
"か?"
msgid "Attaching..."
msgstr "接続中..."
msgid ""
"This disk will be detached permanently and you can re-attach it. Continue to "
"detach it?"
msgstr ""
"このディスクは完全に切り離されますが、再接続できます。切り離しを続行しますか?"
msgid "interface:"
msgstr "インターフェース:"
msgid "address:"
msgstr "アドレス:"
msgid "link_type:"
msgstr "link_type:"
msgid "block:"
msgstr "ブロック:"
msgid "drive_type:"
msgstr "drive_type:"
msgid "model:"
msgstr "モデル:"
msgid "Affected devices:"
msgstr "影響を受けるデバイス:"
msgid "Less"
msgstr "省略"
msgid "Successfully attached device to VM"
msgstr "デバイスは VM に正常に接続されました"
msgid "Successfully detached device from VM"
msgstr "デバイスは正常に VM から切り離されました"
msgid "Following devices will be affected, confirm?"
msgstr "次のデバイスが影響を受けます。確認しますか?"
msgid "Bridge"
msgstr "ブリッジ"
msgid "Vepa"
msgstr "Vepa"
msgid "None"
msgstr "なし"
msgid "unavailable"
msgstr "使用不可"
msgid ""
"This action will interrupt network connectivity for any virtual machine that "
"depend on the %1 network."
msgstr ""
"このアクションを実行すると、%1 ネットワークに依存するすべての仮想マシンのネッ"
"トワーク接続が中断されます。"
msgid "Add Network"
msgstr ""
msgid ""
"The %1 network is not persistent. Instead of stop, this action will "
"permanently delete it. Would you like to continue?"
msgstr ""
"%1 ネットワークは永続的ではありません。このアクションを実行すると、停止ではな"
"く完全削除が行われます。続行しますか?"
msgid ""
"The bridged VLAN tag may not work well with NetworkManager enabled. You "
"should consider disabling it."
msgstr ""
"ブリッジ VLAN タグは NetworkManager が使用可能になっている場合は正しく機能し"
"ない可能性があります。使用不可にすることを検討してください。"
msgid ""
"This will permanently delete the %1 storage pool. Would you like to continue?"
msgstr "これにより、%1 ストレージ・プールは完全に削除されます。続行しますか?"
msgid "This storage pool is empty."
msgstr "このストレージ・プールは空です。"
msgid ""
"It will format your disk and you will loose any data in there, are you sure "
"to continue? "
msgstr ""
"ディスクはフォーマットされ、その中のデータはすべて失われます。続行しますか?"
msgid "SCSI Fibre Channel"
msgstr "SCSI ファイバー・チャネル"
msgid "No SCSI adapters found."
msgstr "SCSI アダプターが見つかりません。"
msgid "Loading iSCSI targets..."
msgstr "iSCSI ターゲットをロード中..."
msgid "No iSCSI found. Please input one."
msgstr "iSCSI が見つかりません。入力してください。"
msgid "Failed to load iSCSI targets."
msgstr "iSCSI ターゲットのロードに失敗しました。"
msgid "Would you like to continue?"
msgstr "続行しますか?"
msgid "This will permanently delete the following storage volumes: %1"
msgstr "これにより、次のストレージ・ボリュームは完全に削除されます: %1"
msgid "No available partitions found."
msgstr "使用可能なパーティションが見つかりません。"
msgid ""
"The %1 storage pool is not persistent. Instead of deactivate, this action "
"will permanently delete it. Would you like to continue?"
msgstr ""
"%1 ストレージ・プールは永続的ではありません。このアクションを実行すると、非ア"
"クティブ化ではなく完全削除が行われます。続行しますか?"
msgid "Unable to retrieve partitions information."
msgstr "パーティション情報を取得できません。"
msgid "In progress..."
msgstr "進行中..."
msgid "Failed!"
msgstr "失敗しました"
msgid "No LVM found in the system."
msgstr "LVM がシステムに見つかりません。"
msgid "This will permanently wipe the following storage volumes: %1"
msgstr "これにより、次のストレージ・プールは完全にワイプされます: %1"
msgid "Wipe Confirmation"
msgstr "ワイプ確認"
msgid "Select one or more partitions to be added to the logical pool %1:"
msgstr "論理プール %1 に追加する 1 つ以上のパーティションを選択してください:"
msgid "Add Storage"
msgstr ""
msgid "DIR"
msgstr "DIR"
msgid "NFS"
msgstr "NFS"
msgid "iSCSI"
msgstr "iSCSI"
msgid "LOGICAL"
msgstr "論理"
msgid "device"
msgstr "デバイス"
msgid "path"
msgstr "パス"
msgid "size (GiB)"
msgstr "サイズ (GiB)"
msgid "free size (GiB)"
msgstr "フリー・サイズ (GiB)"
msgid "Invalid NFS mount path."
msgstr "NFS マウント・パスが無効です。"
msgid "No logical device selected."
msgstr "論理デバイスが選択されていません。"
msgid "This is not a valid Server Name or IP. Please, modify it."
msgstr "これは有効なサーバー名または IP ではありません。変更してください。"
msgid "CDROM path needs to be a valid local/remote path and cannot be blank."
msgstr ""
"CDROM パスは有効なローカル/リモート・パスでなければならず、ブランクにはできま"
"せん。"
msgid "Disk pool or volume cannot be blank."
msgstr "ディスク・プールまたはボリュームはブランクにはできません。"
msgid ""
"Disk size or Format or Directory path cannot be blank and Directory path "
"needs to be a valid local/remote path."
msgstr ""
"ディスク・サイズ、フォーマット、ディレクトリー・パスはブランクにできません。"
"ディレクトリー・パスは有効なローカル/リモート・パスでなければなりません。"
msgid "Disk path needs to be a valid local/remote path and cannot be blank."
msgstr ""
"ディスク・パスは有効なローカル/リモート・パスでなければならず、ブランクにはで"
"きません。"
msgid "Storage pool or Disk size or Format cannot be blank."
msgstr ""
"ストレージ・プール、ディスク・サイズ、フォーマットはブランクにはできません。"
msgid "cdrom"
msgstr "cdrom"
msgid "disk"
msgstr "プール/ボリュームを指定してください"
msgid "Pool"
msgstr "プール"
msgid "qcow"
msgstr "qcow"
msgid "qcow2"
msgstr "qcow2"
msgid "qed"
msgstr "qed"
msgid "raw"
msgstr "raw"
msgid "vmdk"
msgstr "vmdk"
msgid "vpc"
msgstr "vpc"
msgid "Create a network"
msgstr "ネットワークの作成"
msgid "Network Name"
msgstr "ネットワーク名"
msgid "Name should not contain '/' and '\"'."
msgstr "「/」や「\"」は名前に使用しないでください。"
msgid "Network Type"
msgstr "ネットワーク・タイプ"
msgid "Isolated: no external network connection"
msgstr "隔離: 外部ネットワーク接続がありません"
msgid "NAT: outbound physical network connection only"
msgstr "NAT: アウトバウンド物理ネットワーク接続のみ"
msgid "Macvtap: Virtual machines are connected to physical network directly"
msgstr "Macvtap: 仮想マシンは物理ネットワークに直接接続されます"
msgid ""
"Passthrough: Virtual machines are connected using a macvtap connection in "
"passthrough mode."
msgstr ""
"パススルー: 仮想マシンは macvtap 接続を使用してパススルー・モードで接続されま"
"す。"
msgid ""
"VEPA: special mode where virtual machines are connected to a VEPA-enabled "
"switch"
msgstr "VEPA: 仮想マシンが VEPA 対応スイッチに接続される特殊なモード"
msgid "Bridged: Virtual machines are connected through a network bridge"
msgstr "ブリッジ: 仮想マシンはネットワーク・ブリッジを使用して接続されます"
msgid "Destination"
msgstr "宛先"
msgid "Select an Interface"
msgstr "インターフェースの選択"
msgid "Enable VLAN"
msgstr "VLAN を使用可能にしてください"
msgid "VLAN ID"
msgstr "VLAN ID"
msgid "Edit Network"
msgstr "ネットワークの編集"
msgid "Address Space"
msgstr "アドレス・スペース"
msgid "Define a New Storage Pool"
msgstr "新規ストレージ・プールの定義"
msgid "Storage Pool Name"
msgstr "ストレージ・プール名"
msgid ""
"The name used to identify the storage pools, and it should not be empty."
msgstr ""
"名前はストレージ・プールを識別するために使用されます。空にすることはできませ"
"ん。"
msgid "Storage Pool Type"
msgstr "ストレージ・プール・タイプ"
msgid "Storage Path"
msgstr "ストレージ・パス"
msgid ""
"The path of the Storage Pool. Each Storage Pool must have a unique path."
msgstr ""
"ストレージ・プールのパス。各ストレージ・プールには固有のパスが必要です。"
msgid ""
"Kimchi will try to create the directory when it does not already exist in "
"your system."
msgstr ""
"ディレクトリーがシステムにまだ存在していない場合は、Kimchi がディレクトリーを"
"作成しようとします。"
msgid "NFS Server IP"
msgstr "NFS サーバー IP"
msgid "NFS server IP or hostname. It can be input or chosen from history."
msgstr "NFS サーバー IP またはホスト名。入力するか、履歴から選択できます。"
msgid "NFS Path"
msgstr "NFS パス"
msgid "The NFS exported path on NFS server."
msgstr "NFS がパスを NFS サーバーにエクスポートしました。"
msgid "Create from existing LVM"
msgstr "既存の LVM から作成"
msgid "Create from raw disk"
msgstr "ロー・ディスクから作成"
msgid "Looking for existing lvms ..."
msgstr "既存の lvm を検索しています..."
msgid "Looking for available partitions ..."
msgstr "愛用可能なパーティションを検索中..."
msgid "iSCSI Server"
msgstr "iSCSI サーバー"
msgid "Server"
msgstr "サーバー"
msgid "Port"
msgstr "ポート"
msgid "iSCSI server IP or hostname. It should not be empty."
msgstr "iSCSI サーバー IP またはホスト名。空にすることはできません。"
msgid "Target"
msgstr "ターゲット"
msgid "The iSCSI target on iSCSI server"
msgstr "iSCSI サーバー上の iSCSI ターゲット"
msgid "Add iSCSI Authentication"
msgstr "iSCSI 認証の追加"
msgid "User Name"
msgstr "ユーザー名"
msgid "SCSI Adapter"
msgstr "SCSI アダプター"
msgid "Please, wait..."
msgstr "お待ちください..."
msgid "Add a Volume to Storage Pool"
msgstr "ボリュームをストレージ・プールに追加"
msgid "Fetch from remote URL"
msgstr "リモート URL からフェッチ"
msgid "Enter the remote URL here."
msgstr "ここにリモート URL を入力してください。"
msgid "Upload a file"
msgstr "ファイルのアップロード"
msgid "Choose the file you want to upload."
msgstr "アップロードするファイルを選択してください。"
msgid "Resize Volume"
msgstr "ボリューム・サイズの変更"
msgid "Size"
msgstr "サイズ"
msgid "The total space which can be used to store data. The unit is megabytes."
msgstr "データの保管に使用できる合計スペース。単位はメガバイトです。"
msgid "Ok"
msgstr "OK"
msgid "Template Name"
msgstr "テンプレート"
msgid ""
"The name used to identify the template. If omitted, a name will be "
"automatically chosen."
msgstr ""
"名前は仮想マシンを識別するために使用されます。省略すると、使用されているテン"
"プレートに基づいて選択されます。"
msgid ""
"When selecting more than one Image Template, a name will be automatically "
"chosen for each Image Template selected."
msgstr ""
msgid "Where is the source media for this template? "
msgstr "このテンプレートのソース・メディアを指定してください。"
msgid "Image Template"
msgstr "イメージ・テンプレート"
msgid "Netboot Template"
msgstr "Netboot テンプレート"
msgid "File Path:"
msgstr "ファイル・パス:"
msgid "Search ISOs"
msgstr "ISO の検索"
msgid "The following ISOs are available:"
msgstr "次の ISO が使用可能です:"
msgid "QEMU does not have enough permission to work with this file"
msgstr "QEMU には、このファイルを操作するだけの十分な許可がありません"
msgid "Search more ISOs"
msgstr "ISO をさらに検索"
msgid "Loading..."
msgstr "ロード中..."
msgid "Edit Template"
msgstr "テンプレートの編集"
msgid "CDROM"
msgstr "CDROM"
msgid "Image File"
msgstr "イメージ・ファイル"
msgid "Graphics"
msgstr "グラフィックス"
msgid "Disk(GB)"
msgstr "ディスク (GB)"
msgid "Disk Format"
msgstr "ディスク・フォーマット"
msgid "Add Interface"
msgstr "インターフェースの追加"
msgid "pool"
msgstr "プール"
msgid "bridge"
msgstr "ブリッジ"
msgid "vepa"
msgstr "vepa"
msgid "State"
msgstr "状態"
msgid "Guest Name ID"
msgstr "ゲスト名 ID"
msgid "OS Type"
msgstr "OS タイプ"
msgid "VNC"
msgstr "VNC"
msgid "No guests found."
msgstr "ゲストが見つかりません。"
msgid "Stop"
msgstr "停止"
msgid "Location"
msgstr "ロケーション"
msgid "%Used"
msgstr "使用率 (%)"
msgid "Allocated"
msgstr "割り当て済み"
msgid "Capacity"
msgstr "容量"
msgid "Disks"
msgstr "ディスク"
msgid "Extending logical pool"
msgstr "論理プールの拡張中"
msgid "%"
msgstr "%"
msgid "Deactivate"
msgstr "非アクティブ化"
msgid "Activate"
msgstr "アクティブ化"
msgid "Extend"
msgstr "拡張"
msgid "Undefine"
msgstr "定義の解除"
msgid "Add Volume"
msgstr "ボリュームの追加"
msgid "Resize"
msgstr "サイズ変更"
msgid "Wipe"
msgstr "ワイプ"
msgid "Filter:"
msgstr "フィルター:"
msgid "Used By"
msgstr "使用元"
msgid "Used"
msgstr "使用"
msgid "Progress"
msgstr "進捗状況"
msgid "Used by the following VMs:"
msgstr "次の VM で使用:"
msgid "Allocation"
msgstr "割り振り"
msgid "Template Name (ID)"
msgstr "テンプレート名 (ID)"
msgid "No templates found."
msgstr "テンプレートが見つかりません。"
msgid "M"
msgstr "M"
#~ msgid "Peers"
#~ msgstr "ピア"
================================================
FILE: po/kimchi.pot
================================================
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR , YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2017-06-30 10:27-0300\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME \n"
"Language-Team: LANGUAGE \n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=CHARSET\n"
"Content-Transfer-Encoding: 8bit\n"
#, python-format
msgid "Unknown parameter %(value)s"
msgstr ""
#, python-format
msgid "User %(user_id)s not found with given LDAP settings."
msgstr ""
#, python-format
msgid "Partition %(name)s does not exist in the host"
msgstr ""
#, python-format
msgid "Error while accessing dev mapper device, %(err)s"
msgstr ""
msgid "Block device not found."
msgstr ""
#, python-format
msgid "Block device %(device)s not found."
msgstr ""
#, python-format
msgid "Unable to retrieve LVM information. Details: %(err)s"
msgstr ""
msgid "Unknown \"_cap\" specified"
msgstr ""
msgid "\"_passthrough\" should be \"true\" or \"false\""
msgstr ""
msgid "\"_passthrough_affected_by\" should be a device name string"
msgstr ""
msgid "\"_available_only\" should be \"true\" or \"false\""
msgstr ""
#, python-format
msgid "Unable to find distro file: %(filename)s"
msgstr ""
#, python-format
msgid ""
"Unable to parse distro file: %(filename)s. Make sure, it is a JSON file."
msgstr ""
#, python-format
msgid "Unable to login to iSCSI host target %(portal)s. Details: %(err)s"
msgstr ""
#, python-format
msgid "Unable to login to iSCSI host %(host)s target %(target)s"
msgstr ""
#, python-format
msgid "Unable to find ISO file %(filename)s"
msgstr ""
#, python-format
msgid "The ISO file %(filename)s is not bootable"
msgstr ""
#, python-format
msgid "The ISO file %(filename)s does not have a valid El Torito boot record"
msgstr ""
#, python-format
msgid "Invalid El Torito validation entry in ISO %(filename)s"
msgstr ""
#, python-format
msgid "Invalid El Torito boot indicator in ISO %(filename)s"
msgstr ""
#, python-format
msgid "Unexpected volume type for primary volume in ISO %(filename)s"
msgstr ""
#, python-format
msgid "Bad format while reading volume descriptor in ISO %(filename)s"
msgstr ""
#, python-format
msgid ""
"The hypervisor doesn't have permission to use this ISO %(filename)s. "
"Consider moving it under /var/lib/libvirt, or set the search permission to "
"file access control lists for '%(user)s' user if possible, or add the "
"'%(user)s' to the ISO path group, or (not recommended) 'chmod -R o+x "
"'path_to_iso'.Details: %(err)s"
msgstr ""
#, python-format
msgid "Unable to access remote ISO. Details: %(err)s"
msgstr ""
#, python-format
msgid "Error probing image OS information: %(err)s"
msgstr ""
#, python-format
msgid "Unable to read image file %(filename)s"
msgstr ""
#, python-format
msgid ""
"Image file must be an existing file on system. %(filename)s is not a valid "
"input."
msgstr ""
#, python-format
msgid "Virtual machine %(name)s already exists"
msgstr ""
#, python-format
msgid "Virtual machine %(name)s does not exist"
msgstr ""
#, python-format
msgid "Unable to retrieve screenshot for stopped virtual machine %(name)s"
msgstr ""
msgid "Remote ISO image is not supported by this server."
msgstr ""
#, python-format
msgid "Screenshot is not supported on virtual machine %(name)s"
msgstr ""
#, python-format
msgid "Unable to create virtual machine %(name)s. Details: %(err)s"
msgstr ""
#, python-format
msgid "Unable to update virtual machine %(name)s. Details: %(err)s"
msgstr ""
#, python-format
msgid "Unable to retrieve virtual machine %(name)s. Details: %(err)s"
msgstr ""
#, python-format
msgid "Unable to connect to powered off virtual machine %(name)s."
msgstr ""
msgid "Virtual machine name must be a string without slashes (/)"
msgstr ""
#, python-format
msgid "Invalid template URI %(value)s specified for virtual machine"
msgstr ""
#, python-format
msgid "Invalid storage pool URI %(value)s specified for virtual machine"
msgstr ""
msgid "Supported virtual machine graphics are Spice or VNC"
msgstr ""
msgid "Graphics address to listen on must be IPv4 or IPv6"
msgstr ""
msgid "Specify a template to create a virtual machine from"
msgstr ""
#, python-format
msgid "Unable to start virtual machine %(name)s. Details: %(err)s"
msgstr ""
#, python-format
msgid "Unable to power off virtual machine %(name)s. Details: %(err)s"
msgstr ""
#, python-format
msgid "Unable to delete virtual machine %(name)s. Details: %(err)s"
msgstr ""
#, python-format
msgid "Unable to reset virtual machine %(name)s. Details: %(err)s"
msgstr ""
msgid "User name list must be an array"
msgstr ""
msgid "User name must be a string"
msgstr ""
msgid "Group name list must be an array"
msgstr ""
msgid "Group name must be a string"
msgstr ""
#, python-format
msgid "User(s) '%(users)s' do not exist"
msgstr ""
#, python-format
msgid "Group(s) '%(groups)s' do not exist"
msgstr ""
#, python-format
msgid "Unable to shutdown virtual machine %(name)s. Details: %(err)s"
msgstr ""
msgid "The guest console password must be a string."
msgstr ""
msgid "The life time for the guest console password must be a number."
msgstr ""
#, python-format
msgid "Virtual machine '%(name)s' must be stopped before cloning it."
msgstr ""
#, python-format
msgid "Insufficient disk space to clone virtual machine '%(name)s'"
msgstr ""
#, python-format
msgid "Unable to clone VM '%(name)s'. Details: %(err)s"
msgstr ""
#, python-format
msgid "Invalid operation for non-persistent virtual machine %(name)s"
msgstr ""
#, python-format
msgid "Cannot suspend VM '%(name)s' because it is not running."
msgstr ""
#, python-format
msgid "Unable to suspend VM '%(name)s'. Details: %(err)s"
msgstr ""
#, python-format
msgid "Cannot resume VM '%(name)s' because it is not paused."
msgstr ""
#, python-format
msgid "Unable to resume VM '%(name)s'. Details: %(err)s"
msgstr ""
#, python-format
msgid ""
"Memory assigned is higher then the maximum allowed in the host: "
"%(maxmem)sMib."
msgstr ""
#, python-format
msgid ""
"Guest '%(name)s' does not support live memory update. Please, with the guest "
"offline, set Maximum Memory with a value greater then Memory to enable this "
"feature."
msgstr ""
msgid "Only increase memory is allowed in active VMs"
msgstr ""
msgid "There are not enough free slots to add a new memory device."
msgstr ""
msgid ""
"Host's libvirt or qemu version does not support memory devices and memory "
"hotplug. Libvirt must be >= 1.2.14 and QEMU must be >= 2.1."
msgstr ""
#, python-format
msgid "Error attaching memory device. Details: %(error)s"
msgstr ""
#, python-format
msgid "Cannot start %(name)s. Virtual machine is already running."
msgstr ""
#, python-format
msgid "Cannot power off %(name)s. Virtual machine is shut off."
msgstr ""
#, python-format
msgid "Cannot shutdown %(name)s. Virtual machine is shut off."
msgstr ""
#, python-format
msgid "Cannot reset %(name)s. Virtual machine is already shut off."
msgstr ""
msgid "Boot order must be a list. Devices accepted: hd, cdrom, fd or network."
msgstr ""
msgid "Bootmenu must be boolean. Values accepted: true of false."
msgstr ""
msgid "Graphic type not valid. Values accepted: vnc or spice."
msgstr ""
#, python-format
msgid "Migrate to localhost %(host)s is not allowed."
msgstr ""
#, python-format
msgid ""
"To migrate a virtual machine to the remote host %(host)s the user %(user)s "
"must have password-less login to the remote host."
msgstr ""
#, python-format
msgid "Can not migrate virtual machine %(name)s when its in %(state)s state."
msgstr ""
#, python-format
msgid "Failed to migrate virtual machine %(name)s due error: %(err)s"
msgstr ""
msgid "User name of the remote server must be a string."
msgstr ""
msgid "Destination host of the migration must be a string."
msgstr ""
#, python-format
msgid "Unable to create file %(path)s at %(host)s using user %(user)s."
msgstr ""
#, python-format
msgid "Unable to read disk size of %(path)s, error: %(error)s"
msgstr ""
#, python-format
msgid ""
"Unable to create disk image %(path)s at %(host)s using user %(user)s. Error: "
"%(error)s"
msgstr ""
#, python-format
msgid ""
"Unable to migrate virtual machine to remote host %(host)s with arch "
"%(destarch)s using localhost with arch %(srcarch)s."
msgstr ""
#, python-format
msgid ""
"Unable to migrate virtual machine to remote host %(host)s with hypervisor "
"%(desthyp)s because localhost uses hypervisor %(srchyp)s."
msgstr ""
#, python-format
msgid ""
"Unable to determine remote host hypervisor and architecture. Error: %(error)s"
msgstr ""
#, python-format
msgid ""
"Unable to migrate virtual machine: subcores per core setting from "
"localhostand remote host %(host)s differs."
msgstr ""
#, python-format
msgid ""
"Unable to setup password-less login at remote host %(host)s using user "
"%(user)s. Error: %(error)s"
msgstr ""
msgid "Password field must be a string."
msgstr ""
msgid "Error creating local host ssh rsa key of user 'root'."
msgstr ""
#, python-format
msgid "%(param)s value (%(mem)sMiB) must be aligned to %(alignment)sMiB."
msgstr ""
#, python-format
msgid ""
"Unable to update the following parameters while the VM is offline: %(params)s"
msgstr ""
#, python-format
msgid ""
"Unable to update the following parameters while the VM is online: %(params)s"
msgstr ""
#, python-format
msgid ""
"VM %(name)s must have serial and console defined to open a web serial console"
msgstr ""
#, python-format
msgid "Impossible to get the serial console of %(name)s"
msgstr ""
#, python-format
msgid ""
"Memory or Maximum Memory value is higher than amount supported by the host: "
"%(memHost)sMiB."
msgstr ""
#, python-format
msgid ""
"Memory or Maximum Memory value is higher than maximum amount recommended: "
"%(value)sTiB"
msgstr ""
msgid "Cannot update Maximum Memory when guest is running."
msgstr ""
#, python-format
msgid "Impossible to create %(dir)s directory."
msgstr ""
#, python-format
msgid ""
"Either the guest %(name)s did not start to listen to the serial or it is not "
"configured to use the serial console."
msgstr ""
#, python-format
msgid ""
"Unable to retrieve Virt Viewer file for stopped virtual machine %(name)s"
msgstr ""
#, python-format
msgid ""
"Error occured while retrieving the Virt Viewer file for virtual machine "
"%(name)s : %(err)s"
msgstr ""
msgid "Virtual machine title must be a string"
msgstr ""
msgid "Virtual machine description must be a string"
msgstr ""
msgid "console parameter is only supported for s390x/s390 architecture."
msgstr ""
msgid "invalid console type, supported types are sclp/virtio."
msgstr ""
#, python-format
msgid ""
"Unable to setup password-less login at remote host %(host)s using user "
"%(user)s: remote directory %(sshdir)s does not exist."
msgstr ""
#, python-format
msgid ""
"Unable to create a password-less libvirt connection to the remote libvirt "
"daemon at host %(host)s with the user %(user)s. Please verify the remote "
"server libvirt configuration. More information: http://libvirt.org/auth."
"html ."
msgstr ""
msgid "'enable_rdma' must be of type boolean (true or false)."
msgstr ""
#, python-format
msgid ""
"VM %(vmid)s does not contain directly assigned host device %(dev_name)s."
msgstr ""
#, python-format
msgid "The host device %(dev_name)s is not allowed to directly assign to VM."
msgstr ""
msgid ""
"No IOMMU groups found. Host PCI pass through needs IOMMU group to function "
"correctly. Please enable Intel VT-d or AMD IOMMU in your BIOS, then verify "
"the Kernel is compiled with IOMMU support. For Intel CPU, add "
"'intel_iommu=on' to GRUB_CMDLINE_LINUX parameter in /etc/default/grub file. "
"For AMD CPU, add 'iommu=pt iommu=1'."
msgstr ""
msgid "\"name\" should be a device name string"
msgstr ""
#, python-format
msgid ""
"The device %(name)s is probably in use by the host. Unable to attach it to "
"the guest."
msgstr ""
#, python-format
msgid "Hot-(un)plug of device %(name)s is not supported."
msgstr ""
#, python-format
msgid "Failed to attach %(device)s to %(vm)s"
msgstr ""
#, python-format
msgid "VM %(vmid)s does not have a USB controller to accept PCI hotplug."
msgstr ""
#, python-format
msgid "Interface %(iface)s does not exist in virtual machine %(name)s"
msgstr ""
#, python-format
msgid ""
"Network %(network)s specified for virtual machine %(name)s does not exist"
msgstr ""
msgid ""
"Supported virtual machine interfaces type are network, ovs and macvtap.Type "
"ovs and macvtap are only supported for s390x/s390 architecture."
msgstr ""
msgid "Network name for virtual machine interface must be a string"
msgstr ""
msgid "Invalid network model card specified for virtual machine interface"
msgstr ""
msgid "Specify type and network to add a new virtual machine interface"
msgstr ""
msgid "MAC Address must respect this format FF:FF:FF:FF:FF:FF"
msgstr ""
#, python-format
msgid "MAC Address %(mac)s already exists in virtual machine %(name)s"
msgstr ""
msgid "Invalid MAC Address"
msgstr ""
msgid "Cannot change MAC address of a running virtual machine"
msgstr ""
msgid "Type macvtap and ovs are only supported on s390x/s390 architecture."
msgstr ""
msgid "Source attribute is only supported on s390x/s390 architecture."
msgstr ""
msgid "If source is provided, only type supported are macvtap and ovs."
msgstr ""
msgid "For type macvtap and ovs, source has to be provided"
msgstr ""
msgid "Source name for virtual machine interface must be string"
msgstr ""
msgid "Invalid source mode. Valid options are: bridge or vepa."
msgstr ""
#, python-format
msgid "Template %(name)s already exists"
msgstr ""
#, python-format
msgid "Source media %(path)s not found"
msgstr ""
#, python-format
msgid ""
"Network '%(network)s' specified for template %(template)s does not exist"
msgstr ""
#, python-format
msgid ""
"Storage pool %(pool)s specified for template %(template)s does not exist"
msgstr ""
#, python-format
msgid "Invalid parameter '%(param)s' specified for CDROM."
msgstr ""
#, python-format
msgid "Network %(network)s specified for template %(template)s is not active"
msgstr ""
msgid "Template name must be a string"
msgstr ""
msgid "Template icon must be a path to the image"
msgstr ""
msgid "Template distribution must be a string"
msgstr ""
msgid "Template distribution version must be a string"
msgstr ""
msgid "The number of CPUs must be an integer greater than 0"
msgstr ""
msgid ""
"Amount of memory and maximum memory (MB) must be an integer greater than 512"
msgstr ""
msgid "Template CDROM must be a local or remote ISO file"
msgstr ""
#, python-format
msgid "Invalid storage pool URI %(value)s specified for template"
msgstr ""
msgid ""
"Specify a path to source media (ISO, disk or remote ISO) to create a template"
msgstr ""
msgid "All networks for the template must be specified in a list."
msgstr ""
msgid "Specify a volume to a template when storage pool is iSCSI or SCSI"
msgstr ""
#, python-format
msgid "The volume %(volume)s is not in storage pool %(pool)s"
msgstr ""
#, python-format
msgid "Unable to create template due error: %(err)s"
msgstr ""
#, python-format
msgid "Unable to delete template due error: %(err)s"
msgstr ""
msgid "Disk size must be an integer greater than 1GB."
msgstr ""
#, python-format
msgid "Cannot identify base image %(path)s format"
msgstr ""
msgid ""
"When specifying CPU topology, each element must be an integer greater than "
"zero."
msgstr ""
msgid ""
"Invalid disk image format. Valid formats: qcow, qcow2, qed, raw, vmdk, vpc."
msgstr ""
msgid ""
"When setting template disks, following parameters are required: 'index', "
"'pool name', 'format', 'size' or 'volume' (for scsi/iscsi pools)"
msgstr ""
msgid "Disk format must be 'raw', for logical, iscsi, and scsi pools."
msgstr ""
msgid ""
"Memory expects an object with one or both parameters: 'current' and "
"'maxmemory'"
msgstr ""
#, python-format
msgid ""
"Memory value (%(mem)sMiB) must be equal or lesser than maximum memory value "
"(%(maxmem)sMiB)"
msgstr ""
#, python-format
msgid "Unable to update template due error: %(err)s"
msgstr ""
msgid "Parameter 'disks' requires at least one disk object"
msgstr ""
msgid ""
"Invalid interface type. Type should be 'macvtap' for host network interface "
"(Ethernet, Bond, VLAN) to be connected as direct MacVTap or 'ovs' for "
"openvswitch host network interface to be connected as virtual switch to a VM."
msgstr ""
msgid "Interface name should be string."
msgstr ""
msgid "Invalid interface mode. Valid options are: bridge or vepa."
msgstr ""
msgid ""
"Interfaces should be list of interfaces. Each interface should have name, "
"type and mode(optional, only applicable for interfcae type 'macvtap'."
msgstr ""
msgid ""
"Interface expects an object with parameters: 'name', 'type' and 'mode'. Name "
"should be name of host network interface (Ethernet, Bond, VLAN) for type "
"'macvtap' or the name of host openvswitch bridge interface for type 'ovs'. "
"Mode (optional) is only applicable for interface type 'macvtap' to indicates "
"whether packets will be delivered directly to target device (bridge) or to "
"the external bridge (vepa-capable bridge)."
msgstr ""
msgid "Interfaces parameter only supported on s390x or s390 architecture."
msgstr ""
msgid "Storage without libvirt pool is not supported on this architecture"
msgstr ""
#, python-format
msgid "Error while creating the virtual disk for the guest. Details: %(err)s"
msgstr ""
msgid ""
"When setting template disks without libvirt, following parameters are "
"required: 'index', 'format', 'path', 'size'"
msgstr ""
#, python-format
msgid "Storage pool %(name)s already exists"
msgstr ""
#, python-format
msgid "Storage pool %(name)s does not exist"
msgstr ""
#, python-format
msgid "Specify %(item)s in order to create the storage pool %(name)s"
msgstr ""
#, python-format
msgid "Unable to delete active storage pool %(name)s"
msgstr ""
#, python-format
msgid "Unable to list storage pools. Details: %(err)s"
msgstr ""
#, python-format
msgid "Unable to create storage pool %(name)s. Details: %(err)s"
msgstr ""
#, python-format
msgid "Unable to activate storage pool %(name)s. Details: %(err)s"
msgstr ""
#, python-format
msgid "Unable to deactivate storage pool %(name)s. Details: %(err)s"
msgstr ""
#, python-format
msgid "Unable to delete storage pool %(name)s. Details: %(err)s"
msgstr ""
#, python-format
msgid ""
"Unable to create NFS Pool as export path %(path)s may block during mount"
msgstr ""
#, python-format
msgid "Unable to create NFS Pool as export path %(path)s mount failed"
msgstr ""
#, python-format
msgid "Unsupported storage pool type: %(type)s"
msgstr ""
#, python-format
msgid "Error while retrieving storage pool XML to %(pool)s"
msgstr ""
msgid "Storage pool name must be a string without slashes (/)"
msgstr ""
msgid ""
"Supported storage pool types are dir, netfs, logical, iscsi, isci and kimchi-"
"iso"
msgstr ""
msgid "Storage pool path must be a string"
msgstr ""
msgid "Storage pool host must be a IP or hostname"
msgstr ""
msgid "Storage pool device must be the absolute path to the block device"
msgstr ""
msgid "Storage pool devices parameter must be a list"
msgstr ""
msgid "Target IQN of an iSCSI pool must be a string"
msgstr ""
msgid "Port of a remote storage server must be an integer between 1 and 65535"
msgstr ""
msgid "iSCSI target username must be a string"
msgstr ""
msgid "iSCSI target password must be a string"
msgstr ""
msgid "Specify name and type to create a storage pool"
msgstr ""
#, python-format
msgid ""
"%(disk)s is not a valid disk/partition. Could not add it to the pool "
"%(pool)s."
msgstr ""
#, python-format
msgid "Unable to extend logical pool %(pool)s. Details: %(err)s"
msgstr ""
msgid "The parameter disks only can be updated for logical storage pool."
msgstr ""
msgid "The SCSI host adapter name must be a string."
msgstr ""
msgid "The storage pool kimchi_isos is reserved for internal use"
msgstr ""
#, python-format
msgid ""
"Unable to activate NFS storage pool %(name)s. NFS server %(server)s is "
"unreachable."
msgstr ""
#, python-format
msgid ""
"Unable to deactivate NFS storage pool %(name)s. NFS server %(server)s is "
"unreachable."
msgstr ""
#, python-format
msgid ""
"Unable to deactivate pool %(name)s as it is associated with some templates"
msgstr ""
#, python-format
msgid "Unable to delete pool %(name)s as it is associated with some templates"
msgstr ""
#, python-format
msgid ""
"A volume group named '%(name)s' already exists. Please, choose another name "
"to create the logical pool."
msgstr ""
#, python-format
msgid "Unable to update database with deep scan information due error: %(err)s"
msgstr ""
#, python-format
msgid ""
"No volume group '%(name)s' found. Please, specify an existing volume group "
"to create the logical pool from."
msgstr ""
#, python-format
msgid "Unable to delete pool %(name)s as it is associated with guests: %(vms)s"
msgstr ""
#, python-format
msgid "Storage volume %(name)s already exists"
msgstr ""
#, python-format
msgid "Storage volume %(name)s does not exist in storage pool %(pool)s"
msgstr ""
#, python-format
msgid ""
"Unable to create storage volume %(volume)s because storage pool %(pool)s is "
"not active"
msgstr ""
#, python-format
msgid "Specify %(item)s in order to create storage volume %(volume)s"
msgstr ""
#, python-format
msgid ""
"Unable to list storage volumes because storage pool %(pool)s is not active"
msgstr ""
#, python-format
msgid ""
"Unable to create storage volume %(name)s in storage pool %(pool)s. Details: "
"%(err)s"
msgstr ""
#, python-format
msgid "Unable to wipe storage volumes %(name)s. Details: %(err)s"
msgstr ""
#, python-format
msgid "Unable to delete storage volume %(name)s. Details: %(err)s"
msgstr ""
#, python-format
msgid "Unable to resize storage volume %(name)s. Details: %(err)s"
msgstr ""
#, python-format
msgid "Storage type %(type)s does not support volume create and delete"
msgstr ""
msgid "Storage volume name must be a string"
msgstr ""
msgid "Storage volume allocation must be an integer number"
msgstr ""
msgid ""
"Storage volume format not supported. Valid formats: qcow, qcow2, qed, raw, "
"vmdk, vpc."
msgstr ""
msgid "Storage volume requires a volume name"
msgstr ""
#, python-format
msgid ""
"Unable to update database with storage volume information due error: %(err)s"
msgstr ""
#, python-format
msgid "Only one of parameter %(param)s can be specified"
msgstr ""
#, python-format
msgid "Create volume from %(param)s is not supported"
msgstr ""
msgid "Storage volume capacity must be an integer number."
msgstr ""
msgid "Storage volume URL must be http://, https://, ftp:// or ftps://."
msgstr ""
#, python-format
msgid "Unable to access file %(url)s. Please, check it."
msgstr ""
#, python-format
msgid ""
"Unable to clone storage volume '%(name)s' in pool '%(pool)s'. Details: "
"%(err)s"
msgstr ""
msgid "Specify chunk data and its size to upload a file."
msgstr ""
msgid "In order to upload a storage volume, specify the 'upload' parameter."
msgstr ""
msgid ""
"Unable to upload chunk data as it does not match with requested chunk size."
msgstr ""
#, python-format
msgid "The storage volume %(vol)s is not under an upload process."
msgstr ""
msgid "The upload chunk data will exceed the storage volume size."
msgstr ""
#, python-format
msgid "Unable to upload chunk data to storage volume. Details: %(err)s."
msgstr ""
#, python-format
msgid "Interface %(name)s does not exist"
msgstr ""
#, python-format
msgid ""
"Failed to list interfaces. Invalid _inuse parameter. Supported options for "
"_inuse are: %(supported_inuse)s"
msgstr ""
#, python-format
msgid "Network %(name)s already exists"
msgstr ""
#, python-format
msgid "Network %(name)s does not exist"
msgstr ""
#, python-format
msgid "Subnet %(subnet)s specified for network %(network)s is not valid."
msgstr ""
msgid "Specify a network interface to create bridged or macvtap networks."
msgstr ""
#, python-format
msgid "Unable to delete or update active network %(name)s"
msgstr ""
#, python-format
msgid "Interface %(iface)s specified for network %(network)s is already in use"
msgstr ""
msgid "Interface should be bare NIC, bonding or bridge device."
msgstr ""
#, python-format
msgid "Unable to create or update network %(name)s. Details: %(err)s"
msgstr ""
#, python-format
msgid "Unable to find a free IP address for network '%(name)s'"
msgstr ""
#, python-format
msgid "The interface %(iface)s already exists."
msgstr ""
msgid "Network name must be a string without slashes (/) or quotes (\")"
msgstr ""
msgid ""
"Supported network types are isolated, NAT, macvtap, bridge, vepa and "
"passthrough."
msgstr ""
msgid "Network subnet must be a string with IP address and prefix or netmask"
msgstr ""
msgid "Network interfaces must be an array."
msgstr ""
msgid "Network VLAN ID must be an integer between 1 and 4094"
msgstr ""
msgid "Specify name and type to create a Network"
msgstr ""
#, python-format
msgid ""
"Unable to delete or update network %(name)s as it is linked to some virtual "
"machines (%(vms)s) and/or templates (%(tmpls)s)."
msgstr ""
#, python-format
msgid ""
"Unable to deactivate network %(name)s as it is linked to are some virtual "
"machines (%(vms)s) and/or templates (%(tmpls)s)."
msgstr ""
#, python-format
msgid "Bridge device %(name)s can not be the trunk device of a VLAN."
msgstr ""
#, python-format
msgid "Failed to activate interface %(iface)s: %(err)s."
msgstr ""
#, python-format
msgid ""
"Failed to activate interface %(iface)s. Please check the physical link "
"status."
msgstr ""
#, python-format
msgid "Failed to start network %(name)s. Details: %(err)s"
msgstr ""
#, python-format
msgid "Unable to redefine interface %(name)s. Details: %(err)s"
msgstr ""
#, python-format
msgid "Unable to create bridge %(name)s. Details: %(err)s"
msgstr ""
msgid ""
"Unable to create bridge with NetworkManager enabled. Disable it and try "
"again."
msgstr ""
msgid "Interface should be bare NIC or bonding."
msgstr ""
msgid "Network interfaces parameter must contain at least one interface."
msgstr ""
msgid "Only one interface is allowed for 'bridge' and 'macvtap' networks."
msgstr ""
msgid "Subnet is not a valid parameter for this type of virtual network."
msgstr ""
msgid ""
"VLAN ID and interfaces are not valid parameters for this type of virtual "
"network."
msgstr ""
#, python-format
msgid "Storage server %(server)s was not used by Kimchi"
msgstr ""
#, python-format
msgid "Distro '%(name)s' does not exist"
msgstr ""
#, python-format
msgid "Node device '%(name)s' not found"
msgstr ""
msgid "Conflicting flag filters specified."
msgstr ""
msgid "Unable to choose a virtual machine name"
msgstr ""
msgid "Cannot upgrade objectstore data."
msgstr ""
msgid "Invalid storage type. Types supported: 'cdrom', 'disk'"
msgstr ""
#, python-format
msgid "The path '%(value)s' is not a valid local/remote path for the device"
msgstr ""
msgid "Only CDROM path can be update."
msgstr ""
#, python-format
msgid ""
"The storage device %(dev_name)s does not exist in the virtual machine "
"%(vm_name)s"
msgstr ""
#, python-format
msgid "Error while creating new storage device: %(error)s"
msgstr ""
#, python-format
msgid "Error while updating storage device: %(error)s"
msgstr ""
#, python-format
msgid "Error while removing storage device: %(error)s"
msgstr ""
msgid "Do not support IDE device hot plug"
msgstr ""
msgid ""
"Specify type and path or type and pool/volume to add a new virtual machine "
"disk"
msgstr ""
msgid "Specify path to update virtual machine disk"
msgstr ""
#, python-format
msgid "Controller type %(type)s limitation of %(limit)s devices reached"
msgstr ""
#, python-format
msgid "Cannot retrieve disk path information for given pool/volume: %(error)s"
msgstr ""
msgid "Volume already in use by other virtual machine."
msgstr ""
msgid ""
"Only one of path or pool/volume can be specified to add a new virtual "
"machine disk"
msgstr ""
#, python-format
msgid ""
"Volume chosen with format %(format)s does not fit in the storage type "
"%(type)s"
msgstr ""
msgid "On s390x arch one of pool, path of dir_path must be specified"
msgstr ""
msgid ""
"On s390x arch 'format' must be specified while attaching disk to virtual "
"machine"
msgstr ""
#, python-format
msgid "Virtual disk already exists on the system: %(disk_path)s"
msgstr ""
#, python-format
msgid ""
"Unable to create snapshot '%(name)s' on virtual machine '%(vm)s'. Details: "
"%(err)s"
msgstr ""
#, python-format
msgid "Snapshot '%(name)s' does not exist on virtual machine '%(vm)s'."
msgstr ""
#, python-format
msgid ""
"Unable to retrieve snapshot '%(name)s' on virtual machine '%(vm)s'. Details: "
"%(err)s"
msgstr ""
#, python-format
msgid "Unable to list snapshots on virtual machine '%(vm)s'. Details: %(err)s"
msgstr ""
#, python-format
msgid ""
"Unable to delete snapshot '%(name)s' on virtual machine '%(vm)s'. Details: "
"%(err)s"
msgstr ""
#, python-format
msgid ""
"Unable to retrieve current snapshot of virtual machine '%(vm)s'. Details: "
"%(err)s"
msgstr ""
#, python-format
msgid ""
"Unable to revert virtual machine '%(vm)s' to snapshot '%(name)s'. Details: "
"%(err)s"
msgstr ""
#, python-format
msgid ""
"Unable to create snapshot of virtual machine '%(vm)s' because it contains a "
"disk with format '%(format)s'; only 'qcow2' is supported."
msgstr ""
msgid ""
"The number of vCPUs must be less than or equal the maximum number of vCPUs "
"specified."
msgstr ""
msgid ""
"When CPU topology is defined, maximum number of vCPUs must be a product of "
"sockets, cores, and threads."
msgstr ""
msgid "This host (or current configuration) does not allow CPU topology."
msgstr ""
msgid "The maximum number of vCPUs is too large for this system."
msgstr ""
msgid ""
"When CPU topology is defined, CPUs must be a multiple of the 'threads' "
"number defined."
msgstr ""
msgid ""
"When CPU topology is specified, sockets, cores and threads are required "
"paramaters."
msgstr ""
msgid ""
"Parameter 'cpu_info' expects an object with fields among: 'vcpus', "
"'maxvcpus', 'topology'."
msgstr ""
msgid ""
"Parameter 'topology' expects an object with fields among: 'sockets', "
"'cores', 'threads'."
msgstr ""
msgid "Unable to update Max CPU or CPU topology when guest is running."
msgstr ""
#, python-format
msgid "Unable to hot plug/unplug CPUs. Details: %(err)s"
msgstr ""
#, python-format
msgid "Invalid volume group name parameter: %(name)s."
msgstr ""
msgid ""
"Unable to establish connection with libvirt. Please check your libvirt URI "
"which is often defined in /etc/libvirt/libvirt.conf"
msgstr ""
msgid ""
"Libvirt service is not active. Please start the libvirt service in your host "
"system."
msgstr ""
msgid "Failed to register the default event implementation."
msgstr ""
msgid "Failed to register timeout event."
msgstr ""
msgid "Failed to Run the default event implementation."
msgstr ""
#, python-format
msgid ""
"I/O error on guest '%(vm)s': storage pool out of space for %(devAlias)s "
"(%(srcPath)s)."
msgstr ""
#, python-format
msgid "Create virtual network '%(name)s' type '%(connection)s'"
msgstr ""
#, python-format
msgid "Remove virtual network '%(ident)s'"
msgstr ""
#, python-format
msgid "Update virtual network '%(ident)s'"
msgstr ""
#, python-format
msgid "Activate virtual network '%(ident)s'"
msgstr ""
#, python-format
msgid "Deactivate virtual network '%(ident)s'"
msgstr ""
#, python-format
msgid "Create storage pool '%(name)s' type '%(type)s'"
msgstr ""
#, python-format
msgid "Remove storage pool '%(ident)s'"
msgstr ""
#, python-format
msgid "Update storage pool '%(ident)s'"
msgstr ""
#, python-format
msgid "Activate storage pool '%(ident)s'"
msgstr ""
#, python-format
msgid "Deactivate storage pool '%(ident)s'"
msgstr ""
#, python-format
msgid "Create snapshot '%(name)s' at guest '%(vm)s'"
msgstr ""
#, python-format
msgid "Remove snapshot '%(ident)s' from guest '%(vm)s'"
msgstr ""
#, python-format
msgid "Revert guest '%(vm)s' to snapshot '%(ident)s'"
msgstr ""
#, python-format
msgid "Create template '%(name)s'"
msgstr ""
#, python-format
msgid "Remove template '%(ident)s'"
msgstr ""
#, python-format
msgid "Update template '%(ident)s'"
msgstr ""
#, python-format
msgid "Clone template '%(ident)s'"
msgstr ""
#, python-format
msgid "Create guest '%(name)s' from template '%(template)s'"
msgstr ""
#, python-format
msgid "Remove guest '%(ident)s'"
msgstr ""
#, python-format
msgid "Edit guest '%(ident)s'"
msgstr ""
#, python-format
msgid "Start guest '%(ident)s'"
msgstr ""
#, python-format
msgid "Power off guest '%(ident)s'"
msgstr ""
#, python-format
msgid "Shutdown guest '%(ident)s'"
msgstr ""
#, python-format
msgid "Restart guest '%(ident)s'"
msgstr ""
#, python-format
msgid "Connect to guest '%(ident)s' through novnc/spice"
msgstr ""
#, python-format
msgid "Clone guest '%(ident)s'"
msgstr ""
#, python-format
msgid "Migrate guest '%(ident)s' to '%(remote_host)s'"
msgstr ""
#, python-format
msgid "Suspend guest '%(ident)s'"
msgstr ""
#, python-format
msgid "Resume guest '%(ident)s'"
msgstr ""
#, python-format
msgid "Connect to guest '%(ident)s' through serial"
msgstr ""
#, python-format
msgid "Attach host device '%(name)s' to guest '%(vmid)s'"
msgstr ""
#, python-format
msgid "Detach host device '%(ident)s' from guest '%(vmid)s'"
msgstr ""
#, python-format
msgid "Attach network interface '%(network)s' to guest '%(vm)s'"
msgstr ""
#, python-format
msgid "Detach network interface '%(ident)s' from guest '%(vm)s'"
msgstr ""
#, python-format
msgid "Update network interface '%(ident)s' at guest '%(vm)s'"
msgstr ""
#, python-format
msgid "Attach %(type)s storage '%(path)s' to guest '%(vm)s'"
msgstr ""
#, python-format
msgid "Remove storage '%(ident)s' from guest '%(vm)s'"
msgstr ""
#, python-format
msgid "Update storage '%(ident)s' at guest '%(vm)s'"
msgstr ""
#, python-format
msgid "Create storage volume '%(name)s' at pool '%(pool)s'"
msgstr ""
#, python-format
msgid "Remove storage volume '%(ident)s' from pool '%(pool)s'"
msgstr ""
#, python-format
msgid "Update storage volume '%(ident)s' at pool '%(pool)s'"
msgstr ""
#, python-format
msgid "Wipe storage volume '%(ident)s' off pool '%(pool)s'"
msgstr ""
#, python-format
msgid "Resize storage volume '%(ident)s' at pool '%(pool)s' with size %(size)s"
msgstr ""
#, python-format
msgid "Clone storage volume '%(ident)s' at pool '%(pool)s'"
msgstr ""
msgid "Create a New Virtual Machine"
msgstr ""
msgid "Virtual Machine Name"
msgstr ""
msgid ""
"The name used to identify the virtual machine. If omitted, a name will be "
"chosen based on the template used."
msgstr ""
msgid "Please create a template first."
msgstr ""
msgid "Create a Template"
msgstr ""
msgid "Please choose a template."
msgstr ""
msgid "This template has invalid parameters."
msgstr ""
msgid "This template has invalid parameters"
msgstr ""
msgid "OS"
msgstr ""
msgid "Version"
msgstr ""
msgid "Current CPUs"
msgstr ""
msgid "Memory"
msgstr ""
msgid "Create"
msgstr ""
msgid "Creating..."
msgstr ""
msgid "Cancel"
msgstr ""
msgid "Clone a Guest"
msgstr ""
msgid ""
"When the target guest has SCSI or iSCSI volumes, they will be cloned on the "
"default storage pool. The same will happen when the target pool does not "
"have enough space to clone the volumes. Do you want to continue?"
msgstr ""
msgid "Number of times to clone"
msgstr ""
msgid "Continue"
msgstr ""
msgid "Edit Guest"
msgstr ""
msgid "General"
msgstr ""
msgid "Storage"
msgstr ""
msgid "Interface"
msgstr ""
msgid "Permission"
msgstr ""
msgid "Pci"
msgstr ""
msgid "Snapshot"
msgstr ""
msgid "Processor"
msgstr ""
msgid "Name"
msgstr ""
msgid "Memory (MB)"
msgstr ""
msgid "More"
msgstr ""
msgid "Max Memory (MB)"
msgstr ""
msgid "Host does not support memory hotplug"
msgstr ""
msgid "Icon"
msgstr ""
msgid "Console"
msgstr ""
msgid "Nothing selected"
msgstr ""
msgid "sclp"
msgstr ""
msgid "virtio"
msgstr ""
msgid ""
"Select which items for boot order and grad them when needed to order them. "
"At least one option must be selected."
msgstr ""
msgid "Add"
msgstr ""
msgid "Device"
msgstr ""
msgid "Path"
msgstr ""
msgid "Actions"
msgstr ""
msgid "Network"
msgstr ""
msgid "Type"
msgstr ""
msgid "MAC Address"
msgstr ""
msgid "IP Address"
msgstr ""
msgid "Network/Interface"
msgstr ""
msgid "Mode"
msgstr ""
msgid "Available system users and groups"
msgstr ""
msgid "Users"
msgstr ""
msgid "Groups"
msgstr ""
msgid "Selected system users and groups"
msgstr ""
msgid "User"
msgstr ""
msgid "All"
msgstr ""
msgid "To Add"
msgstr ""
msgid "Added"
msgstr ""
msgid "Filter"
msgstr ""
msgid "Status"
msgstr ""
msgid "Product"
msgstr ""
msgid "Vendor"
msgstr ""
msgid "Loading"
msgstr ""
msgid "Created"
msgstr ""
msgid "Current CPU Number"
msgstr ""
msgid ""
"Current CPU must be equal or lower than the Maximum CPU value. If a topology "
"is set, it must be also be a multiple of the 'threads' value."
msgstr ""
msgid "Max CPU"
msgstr ""
msgid ""
"Unable to edit maximum CPU or CPU topology when editing a running or paused "
"virtual machine."
msgstr ""
msgid ""
"If a topology is set, this value will be the product of sockets * times * "
"cores."
msgstr ""
msgid "Manually set CPU topology"
msgstr ""
msgid "Sockets"
msgstr ""
msgid "Cores"
msgstr ""
msgid "Threads"
msgstr ""
msgid "Save"
msgstr ""
msgid "Replace"
msgstr ""
msgid "Detach"
msgstr ""
msgid "Remove"
msgstr ""
msgid "Edit"
msgstr ""
msgid "LDAP User ID,e.g.foo@foo.com"
msgstr ""
msgid "Revert"
msgstr ""
msgid "Running"
msgstr ""
msgid "Disconnected"
msgstr ""
msgid "Starting"
msgstr ""
msgid "Crashed"
msgstr ""
msgid "Unknown"
msgstr ""
msgid "Paused"
msgstr ""
msgid "Suspended"
msgstr ""
msgid "Resetting"
msgstr ""
msgid "View Console"
msgstr ""
msgid "View Serial"
msgstr ""
msgid "Clone"
msgstr ""
msgid "Migrate"
msgstr ""
msgid "Reset"
msgstr ""
msgid "Pause"
msgstr ""
msgid "Resume"
msgstr ""
msgid "Shut Down"
msgstr ""
msgid "Start"
msgstr ""
msgid "Power Off"
msgstr ""
msgid "Delete"
msgstr ""
msgid "No Data Available"
msgstr ""
msgid "Processors Utilization"
msgstr ""
msgid "Memory Utilization"
msgstr ""
msgid "Storage I/O"
msgstr ""
msgid "Network I/O"
msgstr ""
msgid "Migrate a Guest"
msgstr ""
msgid ""
"Disclaimer: This process cannot be stopped after started, can take a long "
"time to complete and will turn off the VM on this Hypervisor when it is "
"successfully migrated to the remote destination."
msgstr ""
msgid "Remote Server"
msgstr ""
msgid "IP Address or Hostname"
msgstr ""
msgid ""
"The following fields are optional. Fill them if you want Kimchi to setup a "
"password-less ssh session between the localhost and the remote host. The "
"setup process will only be successful if the user has 'SUDO ALL' permission "
"in the remote machine."
msgstr ""
msgid "Username of the remote host"
msgstr ""
msgid "Password"
msgstr ""
msgid "Password of the user in the remote host"
msgstr ""
msgid "Use RDMA transport"
msgstr ""
msgid ""
"Check this option only if RDMA is properly configured in both source and "
"destination hosts, otherwise migration will fail."
msgstr ""
msgid "Delete this VM when the migration is completed"
msgstr ""
msgid "Add a Storage Device to VM"
msgstr ""
msgid "Device Type"
msgstr ""
msgid ""
"The device type. Currently, \"cdrom\" and \"disk\" are supported. If the "
"guest is running, only \"disk\" is supported."
msgstr ""
msgid "Create a new disk"
msgstr ""
msgid "Select an existing disk"
msgstr ""
msgid "Source"
msgstr ""
msgid "Storage based on Libvirt pool or direct block device"
msgstr ""
msgid "Storage Pool"
msgstr ""
msgid "Storage pool to create the volume in"
msgstr ""
msgid "Disk Size (GB)"
msgstr ""
msgid "New disk size to be created"
msgstr ""
msgid "Format"
msgstr ""
msgid "Format of the new disk to be created"
msgstr ""
msgid "Directory Path"
msgstr ""
msgid "Provide a directory path"
msgstr ""
msgid "Storage pool in which the volume is located in"
msgstr ""
msgid "Storage Volume"
msgstr ""
msgid "Storage volume to be attached"
msgstr ""
msgid "Disk Path"
msgstr ""
msgid "Provide a block device"
msgstr ""
msgid "File Path"
msgstr ""
msgid "The ISO file path in the server for CDROM."
msgstr ""
msgid "Attach"
msgstr ""
msgid "Host"
msgstr ""
msgid "Guests"
msgstr ""
msgid "Templates"
msgstr ""
msgid "This is not a valid Linux path"
msgstr ""
msgid "Unable to read file."
msgstr ""
msgid "Error while uploading file."
msgstr ""
msgid "Delete Confirmation"
msgstr ""
msgid "OK"
msgstr ""
msgid "Confirm"
msgstr ""
msgid "Warning"
msgstr ""
msgid "Cloning..."
msgstr ""
msgid "Saving..."
msgstr ""
msgid "Migrating..."
msgstr ""
msgid "No ISO found"
msgstr ""
msgid "Add Template"
msgstr ""
msgid "This may take a long time. Do you want to continue?"
msgstr ""
msgid ""
"This will permanently delete the %1 template. Would you like to continue?"
msgstr ""
msgid "View Table"
msgstr ""
msgid "View Gallery"
msgstr ""
msgid "Not Available"
msgstr ""
msgid "Please check the invalid Storage Pools"
msgstr ""
msgid "Please check the invalid Storage Pools or Paths"
msgstr ""
msgid "macvtap"
msgstr ""
msgid "ovs"
msgstr ""
msgid "network"
msgstr ""
msgid ""
"This will delete the %1 virtual machine and its virtual disks. This "
"operation cannot be undone. Would you like to continue?"
msgstr ""
msgid "Power off Confirmation"
msgstr ""
msgid ""
"This action may produce undesirable results, for example unflushed disk "
"cache in the %1 guest. Would you like to continue?"
msgstr ""
msgid "Reset Confirmation"
msgstr ""
msgid ""
"There is a risk of data loss caused by reset without the %1 guest OS "
"shutdown. Would you like to continue?"
msgstr ""
msgid "Shut Down Confirmation"
msgstr ""
msgid ""
"Note the %1 guest OS may ignore this request. Would you like to continue?"
msgstr ""
msgid "Virtual Machine delete Confirmation"
msgstr ""
msgid ""
"The %1 virtual machine is not persistent. Power Off will delete it. Continue?"
msgstr ""
msgid "Add Guest"
msgstr ""
msgid "Input is not a number"
msgstr ""
msgid "Memory value cannot be higher than Max Memory value"
msgstr ""
msgid ""
"For better performance it is recommended a threads per core value not "
"greater than %1."
msgstr ""
msgid ""
"This CDROM will be detached permanently and you can re-attach it. Continue "
"to detach it?"
msgstr ""
msgid "Attaching..."
msgstr ""
msgid ""
"This disk will be detached permanently and you can re-attach it. Continue to "
"detach it?"
msgstr ""
msgid "interface:"
msgstr ""
msgid "address:"
msgstr ""
msgid "link_type:"
msgstr ""
msgid "block:"
msgstr ""
msgid "drive_type:"
msgstr ""
msgid "model:"
msgstr ""
msgid "Affected devices:"
msgstr ""
msgid "Less"
msgstr ""
msgid "Successfully attached device to VM"
msgstr ""
msgid "Successfully detached device from VM"
msgstr ""
msgid "Following devices will be affected, confirm?"
msgstr ""
msgid "Bridge"
msgstr ""
msgid "Vepa"
msgstr ""
msgid "None"
msgstr ""
msgid "unavailable"
msgstr ""
msgid ""
"This action will interrupt network connectivity for any virtual machine that "
"depend on the %1 network."
msgstr ""
msgid "Add Network"
msgstr ""
msgid ""
"The %1 network is not persistent. Instead of stop, this action will "
"permanently delete it. Would you like to continue?"
msgstr ""
msgid ""
"The bridged VLAN tag may not work well with NetworkManager enabled. You "
"should consider disabling it."
msgstr ""
msgid ""
"This will permanently delete the %1 storage pool. Would you like to continue?"
msgstr ""
msgid "This storage pool is empty."
msgstr ""
msgid ""
"It will format your disk and you will loose any data in there, are you sure "
"to continue? "
msgstr ""
msgid "SCSI Fibre Channel"
msgstr ""
msgid "No SCSI adapters found."
msgstr ""
msgid "Loading iSCSI targets..."
msgstr ""
msgid "No iSCSI found. Please input one."
msgstr ""
msgid "Failed to load iSCSI targets."
msgstr ""
msgid "Would you like to continue?"
msgstr ""
msgid "This will permanently delete the following storage volumes: %1"
msgstr ""
msgid "No available partitions found."
msgstr ""
msgid ""
"The %1 storage pool is not persistent. Instead of deactivate, this action "
"will permanently delete it. Would you like to continue?"
msgstr ""
msgid "Unable to retrieve partitions information."
msgstr ""
msgid "In progress..."
msgstr ""
msgid "Failed!"
msgstr ""
msgid "No LVM found in the system."
msgstr ""
msgid "This will permanently wipe the following storage volumes: %1"
msgstr ""
msgid "Wipe Confirmation"
msgstr ""
msgid "Select one or more partitions to be added to the logical pool %1:"
msgstr ""
msgid "Add Storage"
msgstr ""
msgid "DIR"
msgstr ""
msgid "NFS"
msgstr ""
msgid "iSCSI"
msgstr ""
msgid "LOGICAL"
msgstr ""
msgid "device"
msgstr ""
msgid "path"
msgstr ""
msgid "size (GiB)"
msgstr ""
msgid "free size (GiB)"
msgstr ""
msgid "Invalid NFS mount path."
msgstr ""
msgid "No logical device selected."
msgstr ""
msgid "This is not a valid Server Name or IP. Please, modify it."
msgstr ""
msgid "CDROM path needs to be a valid local/remote path and cannot be blank."
msgstr ""
msgid "Disk pool or volume cannot be blank."
msgstr ""
msgid ""
"Disk size or Format or Directory path cannot be blank and Directory path "
"needs to be a valid local/remote path."
msgstr ""
msgid "Disk path needs to be a valid local/remote path and cannot be blank."
msgstr ""
msgid "Storage pool or Disk size or Format cannot be blank."
msgstr ""
msgid "cdrom"
msgstr ""
msgid "disk"
msgstr ""
msgid "Pool"
msgstr ""
msgid "qcow"
msgstr ""
msgid "qcow2"
msgstr ""
msgid "qed"
msgstr ""
msgid "raw"
msgstr ""
msgid "vmdk"
msgstr ""
msgid "vpc"
msgstr ""
msgid "Create a network"
msgstr ""
msgid "Network Name"
msgstr ""
msgid "Name should not contain '/' and '\"'."
msgstr ""
msgid "Network Type"
msgstr ""
msgid "Isolated: no external network connection"
msgstr ""
msgid "NAT: outbound physical network connection only"
msgstr ""
msgid "Macvtap: Virtual machines are connected to physical network directly"
msgstr ""
msgid ""
"Passthrough: Virtual machines are connected using a macvtap connection in "
"passthrough mode."
msgstr ""
msgid ""
"VEPA: special mode where virtual machines are connected to a VEPA-enabled "
"switch"
msgstr ""
msgid "Bridged: Virtual machines are connected through a network bridge"
msgstr ""
msgid "Destination"
msgstr ""
msgid "Select an Interface"
msgstr ""
msgid "Enable VLAN"
msgstr ""
msgid "VLAN ID"
msgstr ""
msgid "Edit Network"
msgstr ""
msgid "Address Space"
msgstr ""
msgid "Define a New Storage Pool"
msgstr ""
msgid "Storage Pool Name"
msgstr ""
msgid ""
"The name used to identify the storage pools, and it should not be empty."
msgstr ""
msgid "Storage Pool Type"
msgstr ""
msgid "Storage Path"
msgstr ""
msgid ""
"The path of the Storage Pool. Each Storage Pool must have a unique path."
msgstr ""
msgid ""
"Kimchi will try to create the directory when it does not already exist in "
"your system."
msgstr ""
msgid "NFS Server IP"
msgstr ""
msgid "NFS server IP or hostname. It can be input or chosen from history."
msgstr ""
msgid "NFS Path"
msgstr ""
msgid "The NFS exported path on NFS server."
msgstr ""
msgid "Create from existing LVM"
msgstr ""
msgid "Create from raw disk"
msgstr ""
msgid "Looking for existing lvms ..."
msgstr ""
msgid "Looking for available partitions ..."
msgstr ""
msgid "iSCSI Server"
msgstr ""
msgid "Server"
msgstr ""
msgid "Port"
msgstr ""
msgid "iSCSI server IP or hostname. It should not be empty."
msgstr ""
msgid "Target"
msgstr ""
msgid "The iSCSI target on iSCSI server"
msgstr ""
msgid "Add iSCSI Authentication"
msgstr ""
msgid "User Name"
msgstr ""
msgid "SCSI Adapter"
msgstr ""
msgid "Please, wait..."
msgstr ""
msgid "Add a Volume to Storage Pool"
msgstr ""
msgid "Fetch from remote URL"
msgstr ""
msgid "Enter the remote URL here."
msgstr ""
msgid "Upload a file"
msgstr ""
msgid "Choose the file you want to upload."
msgstr ""
msgid "Resize Volume"
msgstr ""
msgid "Size"
msgstr ""
msgid "The total space which can be used to store data. The unit is megabytes."
msgstr ""
msgid "Ok"
msgstr ""
msgid "Template Name"
msgstr ""
msgid ""
"The name used to identify the template. If omitted, a name will be "
"automatically chosen."
msgstr ""
msgid ""
"When selecting more than one Image Template, a name will be automatically "
"chosen for each Image Template selected."
msgstr ""
msgid "Where is the source media for this template? "
msgstr ""
msgid "Image Template"
msgstr ""
msgid "Netboot Template"
msgstr ""
msgid "File Path:"
msgstr ""
msgid "Search ISOs"
msgstr ""
msgid "The following ISOs are available:"
msgstr ""
msgid "QEMU does not have enough permission to work with this file"
msgstr ""
msgid "Search more ISOs"
msgstr ""
msgid "Loading..."
msgstr ""
msgid "Edit Template"
msgstr ""
msgid "CDROM"
msgstr ""
msgid "Image File"
msgstr ""
msgid "Graphics"
msgstr ""
msgid "Disk(GB)"
msgstr ""
msgid "Disk Format"
msgstr ""
msgid "Add Interface"
msgstr ""
msgid "pool"
msgstr ""
msgid "bridge"
msgstr ""
msgid "vepa"
msgstr ""
msgid "State"
msgstr ""
msgid "Guest Name ID"
msgstr ""
msgid "OS Type"
msgstr ""
msgid "VNC"
msgstr ""
msgid "No guests found."
msgstr ""
msgid "Stop"
msgstr ""
msgid "Location"
msgstr ""
msgid "%Used"
msgstr ""
msgid "Allocated"
msgstr ""
msgid "Capacity"
msgstr ""
msgid "Disks"
msgstr ""
msgid "Extending logical pool"
msgstr ""
msgid "%"
msgstr ""
msgid "Deactivate"
msgstr ""
msgid "Activate"
msgstr ""
msgid "Extend"
msgstr ""
msgid "Undefine"
msgstr ""
msgid "Add Volume"
msgstr ""
msgid "Resize"
msgstr ""
msgid "Wipe"
msgstr ""
msgid "Filter:"
msgstr ""
msgid "Used By"
msgstr ""
msgid "Used"
msgstr ""
msgid "Progress"
msgstr ""
msgid "Used by the following VMs:"
msgstr ""
msgid "Allocation"
msgstr ""
msgid "Template Name (ID)"
msgstr ""
msgid "No templates found."
msgstr ""
msgid "M"
msgstr ""
================================================
FILE: po/ko_KR.po
================================================
# Korean translations for kimchi package.
# Copyright IBM Corp, 2014-2017
# Adam Litke , 2013.
#
msgid ""
msgstr ""
"Project-Id-Version: kimchi 0.1\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2017-06-30 10:27-0300\n"
"PO-Revision-Date: 2013-07-11 17:32-0400\n"
"Last-Translator: Crístian Viana \n"
"Language-Team: English\n"
"Language: ko_KR\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: pygettext.py 1.5\n"
"Plural-Forms: nplurals=1; plural=0;\n"
#, python-format
msgid "Unknown parameter %(value)s"
msgstr "Unknown parameter %(value)s"
#, python-format
msgid "User %(user_id)s not found with given LDAP settings."
msgstr "지정한 LDAP 설정에서 %(user_id)s 사용자를 찾지 못했습니다."
#, python-format
msgid "Partition %(name)s does not exist in the host"
msgstr "파티션 %(name)s이(가) 호스트에 없습니다."
msgid "Error while accessing dev mapper device, %(err)s"
msgstr ""
msgid "Block device not found."
msgstr ""
msgid "Block device %(device)s not found."
msgstr ""
msgid "Unable to retrieve LVM information. Details: %(err)s"
msgstr ""
msgid "Unknown \"_cap\" specified"
msgstr "알 수 없는 \"_cap\"이 지정되었습니다."
msgid "\"_passthrough\" should be \"true\" or \"false\""
msgstr "\"_passthrough\"는 \"true\" 또는 \"false\"여야 합니다."
msgid "\"_passthrough_affected_by\" should be a device name string"
msgstr "\"_passthrough_affected_by\"는 장치 이름 문자열이어야 합니다."
msgid "\"_available_only\" should be \"true\" or \"false\""
msgstr "\"_available_only\"는 \"true\" 또는 \"false\"여야 합니다."
#, python-format
msgid "Unable to find distro file: %(filename)s"
msgstr "distro 파일을 찾을 수 없음: %(filename)s"
#, python-format
msgid ""
"Unable to parse distro file: %(filename)s. Make sure, it is a JSON file."
msgstr ""
"distro 파일을 구문 분석할 수 없음: %(filename)s. JSON 파일인지 확인하십시오."
#, python-format
msgid "Unable to login to iSCSI host target %(portal)s. Details: %(err)s"
msgstr "iSCSI 호스트 대상 %(portal)s에 로그인할 수 없습니다. 세부사항: %(err)s"
#, python-format
msgid "Unable to login to iSCSI host %(host)s target %(target)s"
msgstr "iSCSI 호스트 %(host)s 대상 %(target)s에 로그인할 수 없습니다."
#, python-format
msgid "Unable to find ISO file %(filename)s"
msgstr "ISO 파일 %(filename)s을(를) 찾을 수 없습니다."
#, python-format
msgid "The ISO file %(filename)s is not bootable"
msgstr "ISO 파일 %(filename)s은(는) 부트 가능하지 않습니다."
#, python-format
msgid "The ISO file %(filename)s does not have a valid El Torito boot record"
msgstr "ISO 파일 %(filename)s에 유효한 El Torito 부트 레코드가 없습니다."
#, python-format
msgid "Invalid El Torito validation entry in ISO %(filename)s"
msgstr ""
"ISO %(filename)s에 올바르지 않은 El Torito 유효성 검증 항목이 있습니다."
#, python-format
msgid "Invalid El Torito boot indicator in ISO %(filename)s"
msgstr "ISO %(filename)s에 올바르지 않은 El Torito 부트 표시기가 있습니다."
#, python-format
msgid "Unexpected volume type for primary volume in ISO %(filename)s"
msgstr "ISO %(filename)s에서 기본 볼륨이 예상치 않은 볼륨 유형입니다."
#, python-format
msgid "Bad format while reading volume descriptor in ISO %(filename)s"
msgstr ""
"ISO %(filename)s에서 볼륨 디스크립터를 읽는 중에 잘못된 형식이 발견되었습니"
"다."
#, python-format
msgid ""
"The hypervisor doesn't have permission to use this ISO %(filename)s. "
"Consider moving it under /var/lib/libvirt, or set the search permission to "
"file access control lists for '%(user)s' user if possible, or add the "
"'%(user)s' to the ISO path group, or (not recommended) 'chmod -R o+x "
"'path_to_iso'.Details: %(err)s"
msgstr ""
"하이퍼바이저가 이 ISO %(filename)s을(를) 사용할 권한이 없습니다. 이를 /var/"
"lib/libvirt 아래로 이동시키거나 (가능한 경우) 검색 권한을 '%(user)s' 사용자"
"의 파일 액세스 제어 목록에 설정하거나 '%(user)s'을(를) ISO 경로 그룹 또는 (권"
"장하지 않음) 'chmod -R o+x 'path_to_iso'(권장되지 않음)에 추가하십시오. 세부"
"사항: %(err)s"
#, python-format
msgid "Unable to access remote ISO. Details: %(err)s"
msgstr ""
#, python-format
msgid "Error probing image OS information: %(err)s"
msgstr ""
#, python-format
msgid "Unable to read image file %(filename)s"
msgstr "이미지 파일 %(filename)s을(를) 읽을 수 없습니다."
#, python-format
msgid ""
"Image file must be an existing file on system. %(filename)s is not a valid "
"input."
msgstr ""
"이미지 파일은 시스템에 있는 기존 파일이여야 합니다. %(filename)s은(는) 유효하"
"지 않은 입력입니다."
#, python-format
msgid "Virtual machine %(name)s already exists"
msgstr "가상 머신 %(name)s이(가) 이미 존재합니다."
#, python-format
msgid "Virtual machine %(name)s does not exist"
msgstr "가상 머신 %(name)s이(가) 없습니다."
#, python-format
msgid "Unable to retrieve screenshot for stopped virtual machine %(name)s"
msgstr "중지된 가상 머신 %(name)s에 대한 스크린샷을 검색할 수 없습니다."
msgid "Remote ISO image is not supported by this server."
msgstr "원격 ISO 이미지는 이 서버에서 지원하지 않습니다."
#, python-format
msgid "Screenshot is not supported on virtual machine %(name)s"
msgstr "스크린샷이 가상 머신 %(name)s에서 지원되지 않습니다."
#, python-format
msgid "Unable to create virtual machine %(name)s. Details: %(err)s"
msgstr "가상 머신 %(name)s을(를) 작성할 수 없습니다. 세부사항: %(err)s"
#, python-format
msgid "Unable to update virtual machine %(name)s. Details: %(err)s"
msgstr "가상 머신 %(name)s을(를) 업데이트할 수 없습니다. 세부사항: %(err)s"
#, python-format
msgid "Unable to retrieve virtual machine %(name)s. Details: %(err)s"
msgstr "가상 머신 %(name)s을(를) 검색할 수 없습니다. 세부사항: %(err)s"
#, python-format
msgid "Unable to connect to powered off virtual machine %(name)s."
msgstr "전원이 꺼진 가상 머신 %(name)s에 연결할 수 없습니다."
msgid "Virtual machine name must be a string without slashes (/)"
msgstr "가상 머신 이름은 슬래시(/)를 포함하지 않는 문자열이어야 합니다."
#, python-format
msgid "Invalid template URI %(value)s specified for virtual machine"
msgstr ""
"가상 머신에 대해 올바르지 않은 템플리트 URI %(value)s이(가) 지정되었습니다."
#, python-format
msgid "Invalid storage pool URI %(value)s specified for virtual machine"
msgstr ""
"가상 머신에 대해 올바르지 않은 스토리지 URI %(value)s이(가) 지정되었습니다."
msgid "Supported virtual machine graphics are Spice or VNC"
msgstr "지원되는 가상 머신 그래픽은 Spice 또는 VNC입니다."
msgid "Graphics address to listen on must be IPv4 or IPv6"
msgstr "청취 대상 그래픽 주소는 IPv4 또는 IPv6여야 합니다."
msgid "Specify a template to create a virtual machine from"
msgstr "가상 머신을 작성하기 위한 템플리트를 지정하십시오."
#, python-format
msgid "Unable to start virtual machine %(name)s. Details: %(err)s"
msgstr "가상 머신 %(name)s을(를) 시작할 수 없습니다. 세부사항: %(err)s"
#, python-format
msgid "Unable to power off virtual machine %(name)s. Details: %(err)s"
msgstr "가상 머신 %(name)s의 전원을 끌 수 없습니다. 세부사항: %(err)s"
#, python-format
msgid "Unable to delete virtual machine %(name)s. Details: %(err)s"
msgstr "가상 머신 %(name)s을(를) 삭제할 수 없습니다. 세부사항: %(err)s"
#, python-format
msgid "Unable to reset virtual machine %(name)s. Details: %(err)s"
msgstr "가상 머신 %(name)s을(를) 다시 설정할 수 없습니다. 세부사항: %(err)s"
msgid "User name list must be an array"
msgstr "사용자 이름 목록은 배열이어야 합니다."
msgid "User name must be a string"
msgstr "사용자 이름은 문자열이어야 합니다."
msgid "Group name list must be an array"
msgstr "그룹 이름 목록은 배열이어야 합니다."
msgid "Group name must be a string"
msgstr "그룹 이름은 문자열이어야 합니다."
#, python-format
msgid "User(s) '%(users)s' do not exist"
msgstr "사용자 '%(users)s'이(가) 없습니다."
#, python-format
msgid "Group(s) '%(groups)s' do not exist"
msgstr "그룹 '%(groups)s'이(가) 없습니다."
#, python-format
msgid "Unable to shutdown virtual machine %(name)s. Details: %(err)s"
msgstr "가상 머신 %(name)s을(를) 종료할 수 없습니다. 세부사항: %(err)s"
msgid "The guest console password must be a string."
msgstr "게스트 콘솔 비밀번호는 문자열이어야 합니다."
msgid "The life time for the guest console password must be a number."
msgstr "게스트 콘솔 비밀번호의 지속 시간은 숫자여야 합니다."
#, python-format
msgid "Virtual machine '%(name)s' must be stopped before cloning it."
msgstr "가상 머신 '%(name)s'은(는) 복제하기 전에 중지해야 합니다."
#, python-format
msgid "Insufficient disk space to clone virtual machine '%(name)s'"
msgstr ""
"가상 머신 '%(name)s'을(를) 복제하기에는 디스크 공간이 충분하지 않습니다."
#, python-format
msgid "Unable to clone VM '%(name)s'. Details: %(err)s"
msgstr "VM '%(name)s'을(를) 복제할 수 없습니다. 세부사항: %(err)s"
#, python-format
msgid "Invalid operation for non-persistent virtual machine %(name)s"
msgstr "비지속적 가상 머신 %(name)s에 대해 올바르지 않은 조작입니다."
#, python-format
msgid "Cannot suspend VM '%(name)s' because it is not running."
msgstr "VM '%(name)s'이(가) 실행 중이 아니므로 일시중단할 수 없습니다."
#, python-format
msgid "Unable to suspend VM '%(name)s'. Details: %(err)s"
msgstr "VM %(name)s을(를) 일시중단할 수 없습니다. 세부사항: %(err)s"
#, python-format
msgid "Cannot resume VM '%(name)s' because it is not paused."
msgstr "VM '%(name)s'이(가) 일시정지되지 않았기 때문에 재개할 수 없습니다."
#, python-format
msgid "Unable to resume VM '%(name)s'. Details: %(err)s"
msgstr "VM '%(name)s'을(를) 재개할 수 없습니다. 세부사항: %(err)s"
#, python-format
msgid ""
"Memory assigned is higher then the maximum allowed in the host: "
"%(maxmem)sMib."
msgstr ""
#, python-format
msgid ""
"Guest '%(name)s' does not support live memory update. Please, with the guest "
"offline, set Maximum Memory with a value greater then Memory to enable this "
"feature."
msgstr ""
msgid "Only increase memory is allowed in active VMs"
msgstr "활성 VM에서는 메모리 늘리기만 허용됩니다."
msgid "There are not enough free slots to add a new memory device."
msgstr ""
msgid ""
"Host's libvirt or qemu version does not support memory devices and memory "
"hotplug. Libvirt must be >= 1.2.14 and QEMU must be >= 2.1."
msgstr ""
#, python-format
msgid "Error attaching memory device. Details: %(error)s"
msgstr "메모리 장치를 연결하는 중 오류가 발생했습니다. 세부사항: %(error)s"
#, python-format
msgid "Cannot start %(name)s. Virtual machine is already running."
msgstr "%(name)s을(를) 시작할 수 없습니다. 가상 머신이 이미 실행 중입니다."
#, python-format
msgid "Cannot power off %(name)s. Virtual machine is shut off."
msgstr "%(name)s의 전원을 끌 수 없습니다. 가상 머신이 꺼진 상태입니다."
#, python-format
msgid "Cannot shutdown %(name)s. Virtual machine is shut off."
msgstr "%(name)s을(를) 종료할 수 없습니다. 가상 머신이 꺼진 상태입니다."
#, python-format
msgid "Cannot reset %(name)s. Virtual machine is already shut off."
msgstr ""
"%(name)s을(를) 다시 설정할 수 없습니다. 가상 머신이 이미 꺼진 상태입니다."
msgid "Boot order must be a list. Devices accepted: hd, cdrom, fd or network."
msgstr ""
msgid "Bootmenu must be boolean. Values accepted: true of false."
msgstr ""
msgid "Graphic type not valid. Values accepted: vnc or spice."
msgstr ""
#, python-format
msgid "Migrate to localhost %(host)s is not allowed."
msgstr ""
#, python-format
msgid ""
"To migrate a virtual machine to the remote host %(host)s the user %(user)s "
"must have password-less login to the remote host."
msgstr ""
#, python-format
msgid "Can not migrate virtual machine %(name)s when its in %(state)s state."
msgstr ""
#, python-format
msgid "Failed to migrate virtual machine %(name)s due error: %(err)s"
msgstr ""
msgid "User name of the remote server must be a string."
msgstr ""
msgid "Destination host of the migration must be a string."
msgstr ""
#, python-format
msgid "Unable to create file %(path)s at %(host)s using user %(user)s."
msgstr ""
#, python-format
msgid "Unable to read disk size of %(path)s, error: %(error)s"
msgstr ""
#, python-format
msgid ""
"Unable to create disk image %(path)s at %(host)s using user %(user)s. Error: "
"%(error)s"
msgstr ""
#, python-format
msgid ""
"Unable to migrate virtual machine to remote host %(host)s with arch "
"%(destarch)s using localhost with arch %(srcarch)s."
msgstr ""
#, python-format
msgid ""
"Unable to migrate virtual machine to remote host %(host)s with hypervisor "
"%(desthyp)s because localhost uses hypervisor %(srchyp)s."
msgstr ""
#, python-format
msgid ""
"Unable to determine remote host hypervisor and architecture. Error: %(error)s"
msgstr ""
#, python-format
msgid ""
"Unable to migrate virtual machine: subcores per core setting from "
"localhostand remote host %(host)s differs."
msgstr ""
#, python-format
msgid ""
"Unable to setup password-less login at remote host %(host)s using user "
"%(user)s. Error: %(error)s"
msgstr ""
msgid "Password field must be a string."
msgstr ""
msgid "Error creating local host ssh rsa key of user 'root'."
msgstr ""
#, python-format
msgid "%(param)s value (%(mem)sMiB) must be aligned to %(alignment)sMiB."
msgstr ""
#, python-format
msgid ""
"Unable to update the following parameters while the VM is offline: %(params)s"
msgstr ""
#, python-format
msgid ""
"Unable to update the following parameters while the VM is online: %(params)s"
msgstr ""
#, python-format
msgid ""
"VM %(name)s must have serial and console defined to open a web serial console"
msgstr ""
#, python-format
msgid "Impossible to get the serial console of %(name)s"
msgstr ""
#, python-format
msgid ""
"Memory or Maximum Memory value is higher than amount supported by the host: "
"%(memHost)sMiB."
msgstr ""
#, python-format
msgid ""
"Memory or Maximum Memory value is higher than maximum amount recommended: "
"%(value)sTiB"
msgstr ""
msgid "Cannot update Maximum Memory when guest is running."
msgstr ""
#, python-format
msgid "Impossible to create %(dir)s directory."
msgstr ""
#, python-format
msgid ""
"Either the guest %(name)s did not start to listen to the serial or it is not "
"configured to use the serial console."
msgstr ""
#, python-format
msgid ""
"Unable to retrieve Virt Viewer file for stopped virtual machine %(name)s"
msgstr ""
#, python-format
msgid ""
"Error occured while retrieving the Virt Viewer file for virtual machine "
"%(name)s : %(err)s"
msgstr ""
msgid "Virtual machine title must be a string"
msgstr ""
msgid "Virtual machine description must be a string"
msgstr ""
msgid "console parameter is only supported for s390x/s390 architecture."
msgstr ""
msgid "invalid console type, supported types are sclp/virtio."
msgstr ""
#, python-format
msgid ""
"Unable to setup password-less login at remote host %(host)s using user "
"%(user)s: remote directory %(sshdir)s does not exist."
msgstr ""
#, python-format
msgid ""
"Unable to create a password-less libvirt connection to the remote libvirt "
"daemon at host %(host)s with the user %(user)s. Please verify the remote "
"server libvirt configuration. More information: http://libvirt.org/auth."
"html ."
msgstr ""
msgid "'enable_rdma' must be of type boolean (true or false)."
msgstr ""
#, python-format
msgid ""
"VM %(vmid)s does not contain directly assigned host device %(dev_name)s."
msgstr ""
"VM %(vmid)s이(가) 직접 지정된 호스트 장치 %(dev_name)s을(를) 포함하고 있지 않"
"습니다."
#, python-format
msgid "The host device %(dev_name)s is not allowed to directly assign to VM."
msgstr "호스트 장치 %(dev_name)s을(를) 직접 VM에 지정할 수 없습니다."
msgid ""
"No IOMMU groups found. Host PCI pass through needs IOMMU group to function "
"correctly. Please enable Intel VT-d or AMD IOMMU in your BIOS, then verify "
"the Kernel is compiled with IOMMU support. For Intel CPU, add "
"'intel_iommu=on' to GRUB_CMDLINE_LINUX parameter in /etc/default/grub file. "
"For AMD CPU, add 'iommu=pt iommu=1'."
msgstr ""
msgid "\"name\" should be a device name string"
msgstr "\"name\"은(는) 장치 이름 문자열이어야 합니다."
#, python-format
msgid ""
"The device %(name)s is probably in use by the host. Unable to attach it to "
"the guest."
msgstr ""
"%(name)s 장치는 호스트에서 사용 중일 수 있습니다. 게스트에 연결할 수없습니다."
#, python-format
msgid "Hot-(un)plug of device %(name)s is not supported."
msgstr ""
#, python-format
msgid "Failed to attach %(device)s to %(vm)s"
msgstr ""
#, python-format
msgid "VM %(vmid)s does not have a USB controller to accept PCI hotplug."
msgstr ""
#, python-format
msgid "Interface %(iface)s does not exist in virtual machine %(name)s"
msgstr "가상 머신 %(name)s에 %(iface)s 인터페이스가 없습니다."
#, python-format
msgid ""
"Network %(network)s specified for virtual machine %(name)s does not exist"
msgstr "가상 머신 %(name)s에 대해 지정된 %(network)s 네트워크가 없습니다."
msgid ""
"Supported virtual machine interfaces type are network, ovs and macvtap.Type "
"ovs and macvtap are only supported for s390x/s390 architecture."
msgstr ""
msgid "Network name for virtual machine interface must be a string"
msgstr "가상 머신 인터페이스의 네트워크 이름은 문자열이어야 합니다."
msgid "Invalid network model card specified for virtual machine interface"
msgstr ""
"가상 머신 인터페이스에 대해 올바르지 않은 네트워크 모델 카드가 지정되었습니"
"다."
msgid "Specify type and network to add a new virtual machine interface"
msgstr "새 가상 머신 인터페이스를 추가할 유형 및 네트워크를 지정하십시오."
msgid "MAC Address must respect this format FF:FF:FF:FF:FF:FF"
msgstr "MAC 주소는 FF:FF:FF:FF:FF:FF 형식을 준수해야 합니다."
#, python-format
msgid "MAC Address %(mac)s already exists in virtual machine %(name)s"
msgstr "MAC 주소 %(mac)s이(가) 가상 머신 %(name)s에 이미 존재합니다."
msgid "Invalid MAC Address"
msgstr "올바르지 않은 MAC 주소입니다."
msgid "Cannot change MAC address of a running virtual machine"
msgstr "실행 중인 가상 머신의 MAC 주소를 변경할 수 없습니다."
msgid "Type macvtap and ovs are only supported on s390x/s390 architecture."
msgstr ""
msgid "Source attribute is only supported on s390x/s390 architecture."
msgstr ""
msgid "If source is provided, only type supported are macvtap and ovs."
msgstr ""
msgid "For type macvtap and ovs, source has to be provided"
msgstr ""
msgid "Source name for virtual machine interface must be string"
msgstr ""
msgid "Invalid source mode. Valid options are: bridge or vepa."
msgstr ""
#, python-format
msgid "Template %(name)s already exists"
msgstr "템플리트 %(name)s이(가) 이미 존재합니다."
#, python-format
msgid "Source media %(path)s not found"
msgstr ""
#, python-format
msgid ""
"Network '%(network)s' specified for template %(template)s does not exist"
msgstr "%(template)s 템플리트에 지정된 '%(network)s' 네트워크가 없습니다."
#, python-format
msgid ""
"Storage pool %(pool)s specified for template %(template)s does not exist"
msgstr "%(template)s 템플리트에 지정된 스토리지 풀 %(pool)s이(가) 없습니다."
#, python-format
msgid "Invalid parameter '%(param)s' specified for CDROM."
msgstr "CDROM에 대해 올바르지 않은 매개변수 '%(param)s' 이(가) 지정되었습니다."
#, python-format
msgid "Network %(network)s specified for template %(template)s is not active"
msgstr ""
"템플리트 %(template)s에 대해 지정된 %(network)s 네트워크가 활성이 아닙니다."
msgid "Template name must be a string"
msgstr "템플리트 이름은 문자열이어야 합니다."
msgid "Template icon must be a path to the image"
msgstr "템플리트 아이콘은 이미지의 경로여야 합니다."
msgid "Template distribution must be a string"
msgstr "템플리트 배포는 문자열이어야 합니다."
msgid "Template distribution version must be a string"
msgstr "템플리트 배포 버전은 문자열이어야 합니다."
msgid "The number of CPUs must be an integer greater than 0"
msgstr "CPU 수는 0보다 큰 정수여야 합니다."
msgid ""
"Amount of memory and maximum memory (MB) must be an integer greater than 512"
msgstr ""
msgid "Template CDROM must be a local or remote ISO file"
msgstr "템플리트 CDROM은 로컬 또는 원격 ISO 파일이어야 합니다."
#, python-format
msgid "Invalid storage pool URI %(value)s specified for template"
msgstr ""
"템플리트에 대해 올바르지 않은 스토리지 풀 URI %(value)s이(가) 지정되었습니다."
msgid ""
"Specify a path to source media (ISO, disk or remote ISO) to create a template"
msgstr ""
msgid "All networks for the template must be specified in a list."
msgstr "템플리트의 모든 네트워크가 목록에 지정되어야 합니다."
msgid "Specify a volume to a template when storage pool is iSCSI or SCSI"
msgstr "스토리지 풀이 iSCSI 또는 SCSI인 경우 볼륨을 템플리트에 지정하십시오."
#, python-format
msgid "The volume %(volume)s is not in storage pool %(pool)s"
msgstr "%(volume)s 볼륨이 스토리지 풀 %(pool)s에 없습니다."
#, python-format
msgid "Unable to create template due error: %(err)s"
msgstr "오류 때문에 템플리트를 작성할 수 없음: %(err)s"
#, python-format
msgid "Unable to delete template due error: %(err)s"
msgstr "오류 때문에 템플리트를 삭제할 수 없음: %(err)s"
msgid "Disk size must be an integer greater than 1GB."
msgstr "디스크 크기는 1GB보다 큰 정수여야 합니다."
#, python-format
msgid "Cannot identify base image %(path)s format"
msgstr "기본 이미지 %(path)s 형식을 식별할 수 없습니다."
msgid ""
"When specifying CPU topology, each element must be an integer greater than "
"zero."
msgstr "CPU 토폴로지를 지정할 때 각 요소는 0보다 큰 정수여야합니다."
msgid ""
"Invalid disk image format. Valid formats: qcow, qcow2, qed, raw, vmdk, vpc."
msgstr ""
msgid ""
"When setting template disks, following parameters are required: 'index', "
"'pool name', 'format', 'size' or 'volume' (for scsi/iscsi pools)"
msgstr ""
msgid "Disk format must be 'raw', for logical, iscsi, and scsi pools."
msgstr ""
msgid ""
"Memory expects an object with one or both parameters: 'current' and "
"'maxmemory'"
msgstr ""
#, python-format
msgid ""
"Memory value (%(mem)sMiB) must be equal or lesser than maximum memory value "
"(%(maxmem)sMiB)"
msgstr ""
#, python-format
msgid "Unable to update template due error: %(err)s"
msgstr ""
msgid "Parameter 'disks' requires at least one disk object"
msgstr ""
msgid ""
"Invalid interface type. Type should be 'macvtap' for host network interface "
"(Ethernet, Bond, VLAN) to be connected as direct MacVTap or 'ovs' for "
"openvswitch host network interface to be connected as virtual switch to a VM."
msgstr ""
msgid "Interface name should be string."
msgstr ""
msgid "Invalid interface mode. Valid options are: bridge or vepa."
msgstr ""
msgid ""
"Interfaces should be list of interfaces. Each interface should have name, "
"type and mode(optional, only applicable for interfcae type 'macvtap'."
msgstr ""
msgid ""
"Interface expects an object with parameters: 'name', 'type' and 'mode'. Name "
"should be name of host network interface (Ethernet, Bond, VLAN) for type "
"'macvtap' or the name of host openvswitch bridge interface for type 'ovs'. "
"Mode (optional) is only applicable for interface type 'macvtap' to indicates "
"whether packets will be delivered directly to target device (bridge) or to "
"the external bridge (vepa-capable bridge)."
msgstr ""
msgid "Interfaces parameter only supported on s390x or s390 architecture."
msgstr ""
msgid "Storage without libvirt pool is not supported on this architecture"
msgstr ""
#, python-format
msgid "Error while creating the virtual disk for the guest. Details: %(err)s"
msgstr ""
msgid ""
"When setting template disks without libvirt, following parameters are "
"required: 'index', 'format', 'path', 'size'"
msgstr ""
#, python-format
msgid "Storage pool %(name)s already exists"
msgstr "스토리지 풀 %(name)s이(가) 이미 존재합니다."
#, python-format
msgid "Storage pool %(name)s does not exist"
msgstr "스토리지 풀 %(name)s이(가) 없습니다."
#, python-format
msgid "Specify %(item)s in order to create the storage pool %(name)s"
msgstr "스토리지 풀 %(name)s을(를) 작성하려면 %(item)s을(를) 지정하십시오."
#, python-format
msgid "Unable to delete active storage pool %(name)s"
msgstr "활성 스토리지 풀 %(name)s을(를) 삭제할 수 없습니다."
#, python-format
msgid "Unable to list storage pools. Details: %(err)s"
msgstr "스토리지 풀을 나열할 수 없습니다. 세부사항: %(err)s"
#, python-format
msgid "Unable to create storage pool %(name)s. Details: %(err)s"
msgstr "스토리지 풀 %(name)s을(를) 작성할 수 없습니다. 세부사항: %(err)s"
#, python-format
msgid "Unable to activate storage pool %(name)s. Details: %(err)s"
msgstr "스토리지 풀 %(name)s을(를) 활성화할 수 없습니다. 세부사항: %(err)s"
#, python-format
msgid "Unable to deactivate storage pool %(name)s. Details: %(err)s"
msgstr "스토리지 풀 %(name)s을(를) 비활성화할 수 없습니다. 세부사항: %(err)s"
#, python-format
msgid "Unable to delete storage pool %(name)s. Details: %(err)s"
msgstr "스토리지 풀 %(name)s을(를) 삭제할 수 없습니다. 세부사항: %(err)s"
#, python-format
msgid ""
"Unable to create NFS Pool as export path %(path)s may block during mount"
msgstr ""
"내보내기 경로 %(path)s이(가) 마운트 중에 차단될 수 있으므로 NFS 풀을 작성할 "
"수 없습니다."
#, python-format
msgid "Unable to create NFS Pool as export path %(path)s mount failed"
msgstr ""
"내보내기 경로 %(path)s 마운트가 실패했으므로 NFS 풀을 작성할 수 없습니다."
#, python-format
msgid "Unsupported storage pool type: %(type)s"
msgstr "지원되지 않는 스토리지 풀 유형: %(type)s"
#, python-format
msgid "Error while retrieving storage pool XML to %(pool)s"
msgstr "%(pool)s에 대해 스토리지 풀 XML을 검색하는 중에 오류가 발생했습니다."
msgid "Storage pool name must be a string without slashes (/)"
msgstr "스토리지 풀 이름은 슬래시(/)를 포함하지 않는 문자열이어야 합니다."
msgid ""
"Supported storage pool types are dir, netfs, logical, iscsi, isci and kimchi-"
"iso"
msgstr ""
"지원되는 스토리지 풀 유형은 dir, netfs, logical, iscsi, isci 및 kimchi-iso입"
"니다."
msgid "Storage pool path must be a string"
msgstr "스토리지 풀 경로는 문자열이어야 합니다."
msgid "Storage pool host must be a IP or hostname"
msgstr "스토리지 풀 호스트는 IP 또는 호스트 이름이어야 합니다."
msgid "Storage pool device must be the absolute path to the block device"
msgstr "스토리지 풀 장치는 블록 장치에 대한 절대 경로여야 합니다."
msgid "Storage pool devices parameter must be a list"
msgstr "스토리지 풀 장치는 목록이어야 합니다."
msgid "Target IQN of an iSCSI pool must be a string"
msgstr "iSCSI 풀의 대상 IQN은 문자열이어야 합니다."
msgid "Port of a remote storage server must be an integer between 1 and 65535"
msgstr "원격 스토리지 서버의 포트는 1과 65535 사이의 정수여야 합니다."
msgid "iSCSI target username must be a string"
msgstr "iSCSI 대상 사용자 이름은 문자열이어야 합니다."
msgid "iSCSI target password must be a string"
msgstr "iSCSI 대상 비밀번호는 문자열이어야 합니다."
msgid "Specify name and type to create a storage pool"
msgstr "스토리지 풀을 작성하려면 이름 및 유형을 지정하십시오."
#, python-format
msgid ""
"%(disk)s is not a valid disk/partition. Could not add it to the pool "
"%(pool)s."
msgstr "%(disk)s은(는) 유효한 디스크/파티션이 아닙니다. 이를 풀%(pool)s."
#, python-format
msgid "Unable to extend logical pool %(pool)s. Details: %(err)s"
msgstr "논리 풀 %(pool)s을(를) 확장할 수 없습니다. 세부사항: %(err)s"
msgid "The parameter disks only can be updated for logical storage pool."
msgstr "논리 스토리지 풀의 매개변수 디스크만 업데이트할 수 있습니다."
msgid "The SCSI host adapter name must be a string."
msgstr "SCSI 호스트 어댑터 이름은 문자열이어야 합니다."
msgid "The storage pool kimchi_isos is reserved for internal use"
msgstr "스토리지 풀 kimchi_isos는 내부 용도로 예약되었습니다."
#, python-format
msgid ""
"Unable to activate NFS storage pool %(name)s. NFS server %(server)s is "
"unreachable."
msgstr ""
"NFS 스토리지 풀 %(name)s을(를) 활성화할 수 없습니다. NFS 서버 %(server)s은"
"(는)연결할 수 없습니다."
#, python-format
msgid ""
"Unable to deactivate NFS storage pool %(name)s. NFS server %(server)s is "
"unreachable."
msgstr ""
"NFS 스토리지 풀 %(name)s을(를) 비활성화할 수 없습니다. NFS 서버 %(server)s은"
"(는)연결할 수 없습니다."
#, python-format
msgid ""
"Unable to deactivate pool %(name)s as it is associated with some templates"
msgstr ""
"일부 템플리트와 연관되어 있으므로 %(name)s 풀을 비활성화할 수 없습니다."
#, python-format
msgid "Unable to delete pool %(name)s as it is associated with some templates"
msgstr "일부 템플리트와 연관되어 있으므로 %(name)s 풀을 삭제할 수 없습니다."
#, python-format
msgid ""
"A volume group named '%(name)s' already exists. Please, choose another name "
"to create the logical pool."
msgstr ""
"이름이 '%(name)s'인 볼륨 그룹이 이미 존재합니다. 논리 풀을 작성하려면다른 이"
"름을 선택하십시오."
#, python-format
msgid "Unable to update database with deep scan information due error: %(err)s"
msgstr ""
"오류 때문에 자세한 스캔 정보로 데이터베이스를 업데이트할 수 없음: %(err)s"
#, python-format
msgid ""
"No volume group '%(name)s' found. Please, specify an existing volume group "
"to create the logical pool from."
msgstr ""
#, python-format
msgid "Unable to delete pool %(name)s as it is associated with guests: %(vms)s"
msgstr ""
#, python-format
msgid "Storage volume %(name)s already exists"
msgstr "스토리지 볼륨 %(name)s이(가) 이미 존재합니다."
#, python-format
msgid "Storage volume %(name)s does not exist in storage pool %(pool)s"
msgstr "스토리지 볼륨 %(name)s이(가) 스토리지 풀 %(pool)s에 없습니다."
#, python-format
msgid ""
"Unable to create storage volume %(volume)s because storage pool %(pool)s is "
"not active"
msgstr ""
"스토리지 풀 %(pool)s이(가) 활성이 아니므로 스토리지 볼륨 %(volume)s을(를)작성"
"할 수 없습니다."
#, python-format
msgid "Specify %(item)s in order to create storage volume %(volume)s"
msgstr "스토리지 볼륨 %(volume)s을(를) 작성하려면 %(item)s을(를) 지정하십시오."
#, python-format
msgid ""
"Unable to list storage volumes because storage pool %(pool)s is not active"
msgstr ""
"스토리지 풀 %(pool)s이(가) 활성이 아니므로 스토리지 볼륨을 나열할 수 없습니"
"다."
#, python-format
msgid ""
"Unable to create storage volume %(name)s in storage pool %(pool)s. Details: "
"%(err)s"
msgstr ""
"스토리지 볼륨 %(name)s을(를) 스토리지 풀 %(pool)s에 작성할 수 없습니다. 세부"
"사항: %(err)s"
#, python-format
msgid "Unable to wipe storage volumes %(name)s. Details: %(err)s"
msgstr "스토리지 볼륨 %(name)s을(를) 삭제할 수 없습니다. 세부사항: %(err)s"
#, python-format
msgid "Unable to delete storage volume %(name)s. Details: %(err)s"
msgstr "스토리지 볼륨 %(name)s을(를) 삭제할 수 없습니다. 세부사항: %(err)s"
#, python-format
msgid "Unable to resize storage volume %(name)s. Details: %(err)s"
msgstr "스토리지 볼륨 %(name)s의 크기를 조정할 수 없습니다. 세부사항: %(err)s"
#, python-format
msgid "Storage type %(type)s does not support volume create and delete"
msgstr "스토리지 유형 %(type)s은(는) 볼륨 작성 및 삭제를 지원하지 않습니다."
msgid "Storage volume name must be a string"
msgstr "스토리지 볼륨 이름은 문자열이어야 합니다."
msgid "Storage volume allocation must be an integer number"
msgstr "스토리지 볼륨 할당은 정수여야 합니다."
msgid ""
"Storage volume format not supported. Valid formats: qcow, qcow2, qed, raw, "
"vmdk, vpc."
msgstr ""
msgid "Storage volume requires a volume name"
msgstr "스토리지 볼륨은 볼륨 이름이 필요합니다."
#, python-format
msgid ""
"Unable to update database with storage volume information due error: %(err)s"
msgstr ""
"오류 때문에 스토리지 볼륨 정보로 데이터베이스를 업데이트할 수 없음: %(err)s"
#, python-format
msgid "Only one of parameter %(param)s can be specified"
msgstr "하나의 매개변수 %(param)s만 지정할 수 있습니다."
#, python-format
msgid "Create volume from %(param)s is not supported"
msgstr "%(param)s에서의 볼륨 작성은 지원되지 않습니다."
msgid "Storage volume capacity must be an integer number."
msgstr "스토리지 볼륨 용량은 정수여야 합니다."
msgid "Storage volume URL must be http://, https://, ftp:// or ftps://."
msgstr "스토리지 볼륨 URL은 http://, https://, ftp:// 또는 ftps://여야 합니다."
#, python-format
msgid "Unable to access file %(url)s. Please, check it."
msgstr "파일 %(url)s에 액세스할 수 없습니다. 확인하십시오."
#, python-format
msgid ""
"Unable to clone storage volume '%(name)s' in pool '%(pool)s'. Details: "
"%(err)s"
msgstr ""
"'%(pool)s' 풀에 스토리지 볼륨 '%(name)s'을(를) 복제할 수 없습니다. 세부사항: "
"%(err)s"
msgid "Specify chunk data and its size to upload a file."
msgstr "파일을 업로드하려면 청크 데이터 및 해당 크기를 지정하십시오."
msgid "In order to upload a storage volume, specify the 'upload' parameter."
msgstr "스토리지 볼륨을 업로드하기 위해 '업로드' 매개변수를 지정하십시오."
msgid ""
"Unable to upload chunk data as it does not match with requested chunk size."
msgstr ""
"요청한 청크 크기와 일치하지 않기 때문에 청크 데이터를 업로드할 수 없습니다."
#, python-format
msgid "The storage volume %(vol)s is not under an upload process."
msgstr "스토리지 볼륨 %(vol)s은(는) 업로드 프로세스의 영향을 받지 않습니다."
msgid "The upload chunk data will exceed the storage volume size."
msgstr "업로드 청크 데이터는 스토리지 볼륨 크기를 초과합니다."
#, python-format
msgid "Unable to upload chunk data to storage volume. Details: %(err)s."
msgstr "스토리지 볼륨에 청크 데이터를 업로드할 수 없습니다. 세부사항: %(err)s."
#, python-format
msgid "Interface %(name)s does not exist"
msgstr "%(name)s 인터페이스가 없습니다."
#, python-format
msgid ""
"Failed to list interfaces. Invalid _inuse parameter. Supported options for "
"_inuse are: %(supported_inuse)s"
msgstr ""
#, python-format
msgid "Network %(name)s already exists"
msgstr "%(name)s 네트워크가 이미 존재합니다."
#, python-format
msgid "Network %(name)s does not exist"
msgstr "%(name)s 네트워크가 없습니다."
#, python-format
msgid "Subnet %(subnet)s specified for network %(network)s is not valid."
msgstr ""
msgid "Specify a network interface to create bridged or macvtap networks."
msgstr ""
#, python-format
msgid "Unable to delete or update active network %(name)s"
msgstr ""
#, python-format
msgid "Interface %(iface)s specified for network %(network)s is already in use"
msgstr ""
"네트워크 %(network)s에 대해 지정된 인터페이스 %(iface)s이(가) 이미 사용 중입"
"니다."
msgid "Interface should be bare NIC, bonding or bridge device."
msgstr "인터페이스는 순수 NIC, 본딩 또는 브릿지 장치여야 합니다."
#, python-format
msgid "Unable to create or update network %(name)s. Details: %(err)s"
msgstr ""
#, python-format
msgid "Unable to find a free IP address for network '%(name)s'"
msgstr "네트워크 '%(name)s'에 대한 여유 IP 주소를 찾을 수 없습니다."
#, python-format
msgid "The interface %(iface)s already exists."
msgstr "%(iface)s 인터페이스가 이미 존재합니다."
msgid "Network name must be a string without slashes (/) or quotes (\")"
msgstr ""
"네트워크 이름은 슬래시(/) 또는 따옴표(\")를 포함하지 않는 문자열이어야 합니"
"다."
msgid ""
"Supported network types are isolated, NAT, macvtap, bridge, vepa and "
"passthrough."
msgstr ""
msgid "Network subnet must be a string with IP address and prefix or netmask"
msgstr ""
"네트워크 서브넷은 IP 주소 및 접두부 또는 넷마스크가 있는 문자열이어야 합니다."
msgid "Network interfaces must be an array."
msgstr ""
msgid "Network VLAN ID must be an integer between 1 and 4094"
msgstr "네트워크 VLAN ID는 1과 4094 사이의 정수여야 합니다."
msgid "Specify name and type to create a Network"
msgstr "네트워크를 작성하려면 이름 및 유형을 지정하십시오."
#, python-format
msgid ""
"Unable to delete or update network %(name)s as it is linked to some virtual "
"machines (%(vms)s) and/or templates (%(tmpls)s)."
msgstr ""
#, python-format
msgid ""
"Unable to deactivate network %(name)s as it is linked to are some virtual "
"machines (%(vms)s) and/or templates (%(tmpls)s)."
msgstr ""
#, python-format
msgid "Bridge device %(name)s can not be the trunk device of a VLAN."
msgstr "브릿지 장치 %(name)s은(는) VLAN의 트렁크 장치가 될 수 없습니다."
#, python-format
msgid "Failed to activate interface %(iface)s: %(err)s."
msgstr "%(iface)s 인터페이스를 활성화하지 못함: %(err)s."
#, python-format
msgid ""
"Failed to activate interface %(iface)s. Please check the physical link "
"status."
msgstr ""
"%(iface)s 인터페이스를 활성화할 수 없습니다. 물리적 링크 상태를확인하십시오."
#, python-format
msgid "Failed to start network %(name)s. Details: %(err)s"
msgstr "%(name)s 네트워크를 시작할 수 없습니다. 세부사항: %(err)s"
#, python-format
msgid "Unable to redefine interface %(name)s. Details: %(err)s"
msgstr ""
#, python-format
msgid "Unable to create bridge %(name)s. Details: %(err)s"
msgstr ""
msgid ""
"Unable to create bridge with NetworkManager enabled. Disable it and try "
"again."
msgstr ""
msgid "Interface should be bare NIC or bonding."
msgstr ""
msgid "Network interfaces parameter must contain at least one interface."
msgstr ""
msgid "Only one interface is allowed for 'bridge' and 'macvtap' networks."
msgstr ""
msgid "Subnet is not a valid parameter for this type of virtual network."
msgstr ""
msgid ""
"VLAN ID and interfaces are not valid parameters for this type of virtual "
"network."
msgstr ""
#, python-format
msgid "Storage server %(server)s was not used by Kimchi"
msgstr "스토리지 서버 %(server)s은(는) Kimchi에서 사용되지 않았습니다."
#, python-format
msgid "Distro '%(name)s' does not exist"
msgstr "Distro '%(name)s'이(가) 없습니다."
#, python-format
msgid "Node device '%(name)s' not found"
msgstr "노드 장치 '%(name)s'이(가) 없습니다."
msgid "Conflicting flag filters specified."
msgstr "충돌하는 플래그 필터를 지정했습니다."
msgid "Unable to choose a virtual machine name"
msgstr "가상 머신 이름을 선택할 수 없습니다."
msgid "Cannot upgrade objectstore data."
msgstr ""
msgid "Invalid storage type. Types supported: 'cdrom', 'disk'"
msgstr "올바르지 않은 스토리지 유형입니다. 지원되는 유형: 'cdrom', 'disk'"
#, python-format
msgid "The path '%(value)s' is not a valid local/remote path for the device"
msgstr "'%(value)s' 경로는 장치의 유효한 로컬/원격 경로가 아닙니다."
msgid "Only CDROM path can be update."
msgstr "CDROM 경로만 업데이트할 수 있습니다."
#, python-format
msgid ""
"The storage device %(dev_name)s does not exist in the virtual machine "
"%(vm_name)s"
msgstr "스토리지 장치 %(dev_name)s이(가) 가상 머신%(vm_name)s"
#, python-format
msgid "Error while creating new storage device: %(error)s"
msgstr "새 스토리지 장치를 작성하는 중에 오류 발생: %(error)s"
#, python-format
msgid "Error while updating storage device: %(error)s"
msgstr "스토리지 장치를 업데이트하는 중에 오류 발생: %(error)s"
#, python-format
msgid "Error while removing storage device: %(error)s"
msgstr "스토리지 장치를 제거하는 중에 오류 발생: %(error)s"
msgid "Do not support IDE device hot plug"
msgstr "IDE 장치 핫 플러그를 지원하지 않습니다."
msgid ""
"Specify type and path or type and pool/volume to add a new virtual machine "
"disk"
msgstr ""
"새 가상 머신 디스크를 추가할 유형 및 경로 또는 유형 및 풀/볼륨을 지정하십시"
"오."
msgid "Specify path to update virtual machine disk"
msgstr "가상 머신 디스크를 업데이트할 경로를 지정하십시오."
#, python-format
msgid "Controller type %(type)s limitation of %(limit)s devices reached"
msgstr " %(limit)s 장치의 제어기 유형 %(type)s 한계에 도달했습니다."
#, python-format
msgid "Cannot retrieve disk path information for given pool/volume: %(error)s"
msgstr "지정한 풀/볼륨에 대한 디스크 경로를 검색할 수 없음: %(error)s"
msgid "Volume already in use by other virtual machine."
msgstr "볼륨이 이미 다른 가상 머신에서 사용 중입니다."
msgid ""
"Only one of path or pool/volume can be specified to add a new virtual "
"machine disk"
msgstr ""
"경로 또는 풀/볼륨 중 하나만 새로운 가상 머신 디스크에 지정할 수 있습니다."
#, python-format
msgid ""
"Volume chosen with format %(format)s does not fit in the storage type "
"%(type)s"
msgstr "%(format)s 형식으로 선택한 볼륨이 스토리지 유형%(type)s"
msgid "On s390x arch one of pool, path of dir_path must be specified"
msgstr ""
msgid ""
"On s390x arch 'format' must be specified while attaching disk to virtual "
"machine"
msgstr ""
#, python-format
msgid "Virtual disk already exists on the system: %(disk_path)s"
msgstr ""
#, python-format
msgid ""
"Unable to create snapshot '%(name)s' on virtual machine '%(vm)s'. Details: "
"%(err)s"
msgstr ""
"가상 머신 '%(vm)s'에 '%(name)s' 스냅샷을 작성할 수 없습니다. 세부사항: "
"%(err)s"
#, python-format
msgid "Snapshot '%(name)s' does not exist on virtual machine '%(vm)s'."
msgstr "가상 머신 '%(vm)s'에 '%(name)s' 스냅샷이 없습니다."
#, python-format
msgid ""
"Unable to retrieve snapshot '%(name)s' on virtual machine '%(vm)s'. Details: "
"%(err)s"
msgstr ""
"가상 머신 '%(vm)s'에서 '%(name)s' 스냅샷을 검색할 수 없습니다. 세부사항: "
"%(err)s"
#, python-format
msgid "Unable to list snapshots on virtual machine '%(vm)s'. Details: %(err)s"
msgstr "가상 머신 '%(vm)s'에 스냅샷을 나열할 수 없습니다. 세부사항: %(err)s"
#, python-format
msgid ""
"Unable to delete snapshot '%(name)s' on virtual machine '%(vm)s'. Details: "
"%(err)s"
msgstr ""
"가상 머신 '%(vm)s'에서 '%(name)s' 스냅샷을 삭제할 수 없습니다. 세부사항: "
"%(err)s"
#, python-format
msgid ""
"Unable to retrieve current snapshot of virtual machine '%(vm)s'. Details: "
"%(err)s"
msgstr ""
"가상 머신 '%(vm)s'의 현재 스냅샷을 검색할 수 없습니다. 세부사항: %(err)s"
#, python-format
msgid ""
"Unable to revert virtual machine '%(vm)s' to snapshot '%(name)s'. Details: "
"%(err)s"
msgstr ""
"'%(name)s' 스냅샷에 대한 가상 머신 '%(vm)s'을(를) 검색할 수 없습니다. 세부사"
"항: %(err)s"
#, python-format
msgid ""
"Unable to create snapshot of virtual machine '%(vm)s' because it contains a "
"disk with format '%(format)s'; only 'qcow2' is supported."
msgstr ""
"'%(format)s' 형식의 디스크가 포함되어 있기 때문에가상 머신 '%(vm)s'의 스냅샷"
"을 작성할 수 없습니다. 'qcow2'만 지원됩니다."
msgid ""
"The number of vCPUs must be less than or equal the maximum number of vCPUs "
"specified."
msgstr ""
msgid ""
"When CPU topology is defined, maximum number of vCPUs must be a product of "
"sockets, cores, and threads."
msgstr ""
msgid "This host (or current configuration) does not allow CPU topology."
msgstr "이 호스트(또는 현재 구성)에서는 CPU 토폴로지가 허용되지 않습니다."
msgid "The maximum number of vCPUs is too large for this system."
msgstr ""
msgid ""
"When CPU topology is defined, CPUs must be a multiple of the 'threads' "
"number defined."
msgstr ""
msgid ""
"When CPU topology is specified, sockets, cores and threads are required "
"paramaters."
msgstr ""
msgid ""
"Parameter 'cpu_info' expects an object with fields among: 'vcpus', "
"'maxvcpus', 'topology'."
msgstr ""
msgid ""
"Parameter 'topology' expects an object with fields among: 'sockets', "
"'cores', 'threads'."
msgstr ""
msgid "Unable to update Max CPU or CPU topology when guest is running."
msgstr ""
#, python-format
msgid "Unable to hot plug/unplug CPUs. Details: %(err)s"
msgstr ""
#, python-format
msgid "Invalid volume group name parameter: %(name)s."
msgstr ""
msgid ""
"Unable to establish connection with libvirt. Please check your libvirt URI "
"which is often defined in /etc/libvirt/libvirt.conf"
msgstr ""
msgid ""
"Libvirt service is not active. Please start the libvirt service in your host "
"system."
msgstr ""
msgid "Failed to register the default event implementation."
msgstr ""
msgid "Failed to register timeout event."
msgstr ""
msgid "Failed to Run the default event implementation."
msgstr ""
#, python-format
msgid ""
"I/O error on guest '%(vm)s': storage pool out of space for %(devAlias)s "
"(%(srcPath)s)."
msgstr ""
#, python-format
msgid "Create virtual network '%(name)s' type '%(connection)s'"
msgstr ""
#, python-format
msgid "Remove virtual network '%(ident)s'"
msgstr ""
#, python-format
msgid "Update virtual network '%(ident)s'"
msgstr ""
#, python-format
msgid "Activate virtual network '%(ident)s'"
msgstr ""
#, python-format
msgid "Deactivate virtual network '%(ident)s'"
msgstr ""
#, python-format
msgid "Create storage pool '%(name)s' type '%(type)s'"
msgstr ""
#, python-format
msgid "Remove storage pool '%(ident)s'"
msgstr ""
#, python-format
msgid "Update storage pool '%(ident)s'"
msgstr ""
#, python-format
msgid "Activate storage pool '%(ident)s'"
msgstr ""
#, python-format
msgid "Deactivate storage pool '%(ident)s'"
msgstr ""
#, python-format
msgid "Create snapshot '%(name)s' at guest '%(vm)s'"
msgstr ""
#, python-format
msgid "Remove snapshot '%(ident)s' from guest '%(vm)s'"
msgstr ""
#, python-format
msgid "Revert guest '%(vm)s' to snapshot '%(ident)s'"
msgstr ""
#, python-format
msgid "Create template '%(name)s'"
msgstr ""
#, python-format
msgid "Remove template '%(ident)s'"
msgstr ""
#, python-format
msgid "Update template '%(ident)s'"
msgstr ""
#, python-format
msgid "Clone template '%(ident)s'"
msgstr ""
#, python-format
msgid "Create guest '%(name)s' from template '%(template)s'"
msgstr ""
#, python-format
msgid "Remove guest '%(ident)s'"
msgstr ""
#, python-format
msgid "Edit guest '%(ident)s'"
msgstr ""
#, python-format
msgid "Start guest '%(ident)s'"
msgstr ""
#, python-format
msgid "Power off guest '%(ident)s'"
msgstr ""
#, python-format
msgid "Shutdown guest '%(ident)s'"
msgstr ""
#, python-format
msgid "Restart guest '%(ident)s'"
msgstr ""
#, python-format
msgid "Connect to guest '%(ident)s' through novnc/spice"
msgstr ""
#, python-format
msgid "Clone guest '%(ident)s'"
msgstr ""
#, python-format
msgid "Migrate guest '%(ident)s' to '%(remote_host)s'"
msgstr ""
#, python-format
msgid "Suspend guest '%(ident)s'"
msgstr ""
#, python-format
msgid "Resume guest '%(ident)s'"
msgstr ""
#, python-format
msgid "Connect to guest '%(ident)s' through serial"
msgstr ""
#, python-format
msgid "Attach host device '%(name)s' to guest '%(vmid)s'"
msgstr ""
#, python-format
msgid "Detach host device '%(ident)s' from guest '%(vmid)s'"
msgstr ""
#, python-format
msgid "Attach network interface '%(network)s' to guest '%(vm)s'"
msgstr ""
#, python-format
msgid "Detach network interface '%(ident)s' from guest '%(vm)s'"
msgstr ""
#, python-format
msgid "Update network interface '%(ident)s' at guest '%(vm)s'"
msgstr ""
#, python-format
msgid "Attach %(type)s storage '%(path)s' to guest '%(vm)s'"
msgstr ""
#, python-format
msgid "Remove storage '%(ident)s' from guest '%(vm)s'"
msgstr ""
#, python-format
msgid "Update storage '%(ident)s' at guest '%(vm)s'"
msgstr ""
#, python-format
msgid "Create storage volume '%(name)s' at pool '%(pool)s'"
msgstr ""
#, python-format
msgid "Remove storage volume '%(ident)s' from pool '%(pool)s'"
msgstr ""
#, python-format
msgid "Update storage volume '%(ident)s' at pool '%(pool)s'"
msgstr ""
#, python-format
msgid "Wipe storage volume '%(ident)s' off pool '%(pool)s'"
msgstr ""
#, python-format
msgid "Resize storage volume '%(ident)s' at pool '%(pool)s' with size %(size)s"
msgstr ""
#, python-format
msgid "Clone storage volume '%(ident)s' at pool '%(pool)s'"
msgstr ""
msgid "Create a New Virtual Machine"
msgstr "새 가상 머신 작성"
msgid "Virtual Machine Name"
msgstr "가상 머신 이름"
msgid ""
"The name used to identify the virtual machine. If omitted, a name will be "
"chosen based on the template used."
msgstr ""
"가상 머신을 식별하는 데 사용되는 이름입니다. 생략되면 이름은 사용된 템플리트"
"를 기반으로 선택됩니다."
msgid "Please create a template first."
msgstr "템플리트를 먼저 작성하십시오."
msgid "Create a Template"
msgstr "템플리트 작성"
msgid "Please choose a template."
msgstr "템플리트를 선택하십시오."
msgid "This template has invalid parameters."
msgstr ""
msgid "This template has invalid parameters"
msgstr ""
msgid "OS"
msgstr "OS"
msgid "Version"
msgstr "버전"
msgid "Current CPUs"
msgstr ""
msgid "Memory"
msgstr "메모리"
msgid "Create"
msgstr "작성"
msgid "Creating..."
msgstr "작성 중..."
msgid "Cancel"
msgstr "취소"
msgid "Clone a Guest"
msgstr ""
msgid ""
"When the target guest has SCSI or iSCSI volumes, they will be cloned on the "
"default storage pool. The same will happen when the target pool does not "
"have enough space to clone the volumes. Do you want to continue?"
msgstr ""
msgid "Number of times to clone"
msgstr ""
msgid "Continue"
msgstr ""
msgid "Edit Guest"
msgstr "게스트 편집"
msgid "General"
msgstr "일반"
msgid "Storage"
msgstr "스토리지"
msgid "Interface"
msgstr "인터페이스"
msgid "Permission"
msgstr ""
msgid "Pci"
msgstr ""
msgid "Snapshot"
msgstr ""
msgid "Processor"
msgstr "프로세서"
msgid "Name"
msgstr "이름"
msgid "Memory (MB)"
msgstr "메모리(MB)"
msgid "More"
msgstr ""
msgid "Max Memory (MB)"
msgstr ""
msgid "Host does not support memory hotplug"
msgstr ""
msgid "Icon"
msgstr "아이콘"
msgid "Console"
msgstr ""
msgid "Nothing selected"
msgstr ""
msgid "sclp"
msgstr ""
msgid "virtio"
msgstr ""
msgid ""
"Select which items for boot order and grad them when needed to order them. "
"At least one option must be selected."
msgstr ""
msgid "Add"
msgstr "추가"
msgid "Device"
msgstr "장치"
msgid "Path"
msgstr "경로"
msgid "Actions"
msgstr "조치"
msgid "Network"
msgstr "네트워크"
msgid "Type"
msgstr "유형"
msgid "MAC Address"
msgstr "MAC 주소"
msgid "IP Address"
msgstr ""
msgid "Network/Interface"
msgstr ""
msgid "Mode"
msgstr ""
msgid "Available system users and groups"
msgstr "사용 가능한 시스템 사용자 및 그룹"
msgid "Users"
msgstr "사용자"
msgid "Groups"
msgstr "그룹"
msgid "Selected system users and groups"
msgstr "선택한 시스템 사용자 및 그룹"
msgid "User"
msgstr "사용자"
msgid "All"
msgstr "모두"
msgid "To Add"
msgstr "추가 대상"
msgid "Added"
msgstr "추가됨"
msgid "Filter"
msgstr ""
msgid "Status"
msgstr ""
msgid "Product"
msgstr "제품"
msgid "Vendor"
msgstr "공급업체"
msgid "Loading"
msgstr ""
msgid "Created"
msgstr "작성됨"
msgid "Current CPU Number"
msgstr ""
msgid ""
"Current CPU must be equal or lower than the Maximum CPU value. If a topology "
"is set, it must be also be a multiple of the 'threads' value."
msgstr ""
msgid "Max CPU"
msgstr ""
msgid ""
"Unable to edit maximum CPU or CPU topology when editing a running or paused "
"virtual machine."
msgstr ""
msgid ""
"If a topology is set, this value will be the product of sockets * times * "
"cores."
msgstr ""
msgid "Manually set CPU topology"
msgstr "CPU 토폴로지 수동 설정"
msgid "Sockets"
msgstr ""
msgid "Cores"
msgstr "코어"
msgid "Threads"
msgstr "스레드"
msgid "Save"
msgstr "저장"
msgid "Replace"
msgstr "교체"
msgid "Detach"
msgstr "분리"
msgid "Remove"
msgstr "제거"
msgid "Edit"
msgstr "편집"
msgid "LDAP User ID,e.g.foo@foo.com"
msgstr "LDAP 사용자 ID, 예: foo@foo.com"
msgid "Revert"
msgstr ""
msgid "Running"
msgstr ""
msgid "Disconnected"
msgstr ""
msgid "Starting"
msgstr ""
msgid "Crashed"
msgstr ""
msgid "Unknown"
msgstr ""
msgid "Paused"
msgstr ""
msgid "Suspended"
msgstr ""
msgid "Resetting"
msgstr ""
msgid "View Console"
msgstr ""
msgid "View Serial"
msgstr ""
msgid "Clone"
msgstr "복제"
msgid "Migrate"
msgstr ""
msgid "Reset"
msgstr "다시 설정"
msgid "Pause"
msgstr "일시정지"
msgid "Resume"
msgstr "재개"
msgid "Shut Down"
msgstr "종료"
msgid "Start"
msgstr "시작"
msgid "Power Off"
msgstr "전원 끄기"
msgid "Delete"
msgstr "삭제"
msgid "No Data Available"
msgstr ""
msgid "Processors Utilization"
msgstr ""
msgid "Memory Utilization"
msgstr ""
msgid "Storage I/O"
msgstr ""
msgid "Network I/O"
msgstr "네트워크 I/O"
msgid "Migrate a Guest"
msgstr ""
msgid ""
"Disclaimer: This process cannot be stopped after started, can take a long "
"time to complete and will turn off the VM on this Hypervisor when it is "
"successfully migrated to the remote destination."
msgstr ""
msgid "Remote Server"
msgstr ""
msgid "IP Address or Hostname"
msgstr ""
msgid ""
"The following fields are optional. Fill them if you want Kimchi to setup a "
"password-less ssh session between the localhost and the remote host. The "
"setup process will only be successful if the user has 'SUDO ALL' permission "
"in the remote machine."
msgstr ""
msgid "Username of the remote host"
msgstr ""
msgid "Password"
msgstr "비밀번호"
msgid "Password of the user in the remote host"
msgstr ""
msgid "Use RDMA transport"
msgstr ""
msgid ""
"Check this option only if RDMA is properly configured in both source and "
"destination hosts, otherwise migration will fail."
msgstr ""
msgid "Delete this VM when the migration is completed"
msgstr ""
msgid "Add a Storage Device to VM"
msgstr "스토리지 장치를 VM에 추가"
msgid "Device Type"
msgstr "장치 유형"
msgid ""
"The device type. Currently, \"cdrom\" and \"disk\" are supported. If the "
"guest is running, only \"disk\" is supported."
msgstr ""
msgid "Create a new disk"
msgstr ""
msgid "Select an existing disk"
msgstr ""
msgid "Source"
msgstr ""
msgid "Storage based on Libvirt pool or direct block device"
msgstr ""
msgid "Storage Pool"
msgstr "스토리지 풀"
msgid "Storage pool to create the volume in"
msgstr ""
msgid "Disk Size (GB)"
msgstr ""
msgid "New disk size to be created"
msgstr ""
msgid "Format"
msgstr ""
msgid "Format of the new disk to be created"
msgstr ""
msgid "Directory Path"
msgstr ""
msgid "Provide a directory path"
msgstr ""
msgid "Storage pool in which the volume is located in"
msgstr ""
msgid "Storage Volume"
msgstr "스토리지 볼륨"
msgid "Storage volume to be attached"
msgstr "연결될 스토리지 볼륨"
msgid "Disk Path"
msgstr ""
msgid "Provide a block device"
msgstr ""
msgid "File Path"
msgstr "파일 경로"
msgid "The ISO file path in the server for CDROM."
msgstr "CDROM을 위한 서버의 ISO 파일 경로입니다."
msgid "Attach"
msgstr "연결"
msgid "Host"
msgstr "호스트"
msgid "Guests"
msgstr "게스트"
msgid "Templates"
msgstr "템플리트"
msgid "This is not a valid Linux path"
msgstr "올바른 Linux 경로가 아닙니다."
msgid "Unable to read file."
msgstr "파일을 읽을 수 없습니다. "
msgid "Error while uploading file."
msgstr "파일을 업로드하는 중에 오류가 발생했습니다."
msgid "Delete Confirmation"
msgstr "삭제 확인"
msgid "OK"
msgstr "확인"
msgid "Confirm"
msgstr "확인"
msgid "Warning"
msgstr "경고"
msgid "Cloning..."
msgstr "복제 중..."
msgid "Saving..."
msgstr ""
msgid "Migrating..."
msgstr ""
msgid "No ISO found"
msgstr "ISO가 없습니다."
msgid "Add Template"
msgstr "템플리트 추가"
msgid "This may take a long time. Do you want to continue?"
msgstr "시간이 오래 걸릴 수 있습니다. 계속하시겠습니까?"
msgid ""
"This will permanently delete the %1 template. Would you like to continue?"
msgstr ""
msgid "View Table"
msgstr ""
msgid "View Gallery"
msgstr ""
msgid "Not Available"
msgstr ""
msgid "Please check the invalid Storage Pools"
msgstr ""
msgid "Please check the invalid Storage Pools or Paths"
msgstr ""
msgid "macvtap"
msgstr ""
msgid "ovs"
msgstr ""
msgid "network"
msgstr ""
msgid ""
"This will delete the %1 virtual machine and its virtual disks. This "
"operation cannot be undone. Would you like to continue?"
msgstr ""
msgid "Power off Confirmation"
msgstr "전원 끄기 확인"
msgid ""
"This action may produce undesirable results, for example unflushed disk "
"cache in the %1 guest. Would you like to continue?"
msgstr ""
msgid "Reset Confirmation"
msgstr "다시 설정 확인"
msgid ""
"There is a risk of data loss caused by reset without the %1 guest OS "
"shutdown. Would you like to continue?"
msgstr ""
msgid "Shut Down Confirmation"
msgstr "종료 확인"
msgid ""
"Note the %1 guest OS may ignore this request. Would you like to continue?"
msgstr ""
msgid "Virtual Machine delete Confirmation"
msgstr "가상 머신 삭제 확인"
msgid ""
"The %1 virtual machine is not persistent. Power Off will delete it. Continue?"
msgstr ""
msgid "Add Guest"
msgstr ""
msgid "Input is not a number"
msgstr ""
msgid "Memory value cannot be higher than Max Memory value"
msgstr ""
msgid ""
"For better performance it is recommended a threads per core value not "
"greater than %1."
msgstr ""
msgid ""
"This CDROM will be detached permanently and you can re-attach it. Continue "
"to detach it?"
msgstr ""
"이 CDROM은 영구적으로 분리되며 다시 연결할 수 있습니다. 분리를 계속하시겠습니"
"까?"
msgid "Attaching..."
msgstr "연결 중..."
msgid ""
"This disk will be detached permanently and you can re-attach it. Continue to "
"detach it?"
msgstr ""
"이 디스크는 영구적으로 분리되고 다시 연결할 수 있습니다. 분리를 계속하시겠습"
"니까?"
msgid "interface:"
msgstr "인터페이스:"
msgid "address:"
msgstr "주소:"
msgid "link_type:"
msgstr "link_type:"
msgid "block:"
msgstr "블록:"
msgid "drive_type:"
msgstr "drive_type:"
msgid "model:"
msgstr "모델:"
msgid "Affected devices:"
msgstr "관련 장치:"
msgid "Less"
msgstr ""
msgid "Successfully attached device to VM"
msgstr ""
msgid "Successfully detached device from VM"
msgstr ""
msgid "Following devices will be affected, confirm?"
msgstr ""
msgid "Bridge"
msgstr ""
msgid "Vepa"
msgstr ""
msgid "None"
msgstr ""
msgid "unavailable"
msgstr "사용 불가능"
msgid ""
"This action will interrupt network connectivity for any virtual machine that "
"depend on the %1 network."
msgstr ""
msgid "Add Network"
msgstr ""
msgid ""
"The %1 network is not persistent. Instead of stop, this action will "
"permanently delete it. Would you like to continue?"
msgstr ""
msgid ""
"The bridged VLAN tag may not work well with NetworkManager enabled. You "
"should consider disabling it."
msgstr ""
"NetworkManager를 사용으로 설정하여 브릿지된 VLAN 태그가 잘 작동하지 않을 수 "
"있습니다. 사용 안함으로설정하는 것이 좋습니다."
msgid ""
"This will permanently delete the %1 storage pool. Would you like to continue?"
msgstr ""
msgid "This storage pool is empty."
msgstr "이 스토리지 풀은 비어 있습니다."
msgid ""
"It will format your disk and you will loose any data in there, are you sure "
"to continue? "
msgstr "디스크가 포맷되고 데이터가 손실됩니다. 계속하시겠습니까? "
msgid "SCSI Fibre Channel"
msgstr "SCSI 파이버 채널"
msgid "No SCSI adapters found."
msgstr "SCSI 어댑터가 없습니다."
msgid "Loading iSCSI targets..."
msgstr "iSCSI 대상 로드 중..."
msgid "No iSCSI found. Please input one."
msgstr "iSCSI가 없습니다. 입력하십시오."
msgid "Failed to load iSCSI targets."
msgstr "iSCSI 대상을 로드하지 못했습니다."
msgid "Would you like to continue?"
msgstr ""
msgid "This will permanently delete the following storage volumes: %1"
msgstr ""
msgid "No available partitions found."
msgstr "사용 가능한 파티션이 없습니다."
msgid ""
"The %1 storage pool is not persistent. Instead of deactivate, this action "
"will permanently delete it. Would you like to continue?"
msgstr ""
msgid "Unable to retrieve partitions information."
msgstr "파티션 정보를 검색할 수 없습니다. "
msgid "In progress..."
msgstr "처리 중..."
msgid "Failed!"
msgstr "실패함!"
msgid "No LVM found in the system."
msgstr ""
msgid "This will permanently wipe the following storage volumes: %1"
msgstr ""
msgid "Wipe Confirmation"
msgstr ""
msgid "Select one or more partitions to be added to the logical pool %1:"
msgstr ""
msgid "Add Storage"
msgstr ""
msgid "DIR"
msgstr ""
msgid "NFS"
msgstr ""
msgid "iSCSI"
msgstr ""
msgid "LOGICAL"
msgstr ""
msgid "device"
msgstr ""
msgid "path"
msgstr ""
msgid "size (GiB)"
msgstr ""
msgid "free size (GiB)"
msgstr ""
msgid "Invalid NFS mount path."
msgstr "올바르지 않은 NFS 마운트 경로입니다."
msgid "No logical device selected."
msgstr "논리 장치가 선택되지 않았습니다."
msgid "This is not a valid Server Name or IP. Please, modify it."
msgstr "유효한 서버 이름 또는 IP가 아닙니다. 수정하십시오."
msgid "CDROM path needs to be a valid local/remote path and cannot be blank."
msgstr "CDROM 경로는 올바른 로컬/원격 경로여야 하며 비워둘 수 없습니다."
msgid "Disk pool or volume cannot be blank."
msgstr "디스크 풀 또는 볼륨은 비워둘 수 없습니다."
msgid ""
"Disk size or Format or Directory path cannot be blank and Directory path "
"needs to be a valid local/remote path."
msgstr ""
msgid "Disk path needs to be a valid local/remote path and cannot be blank."
msgstr ""
msgid "Storage pool or Disk size or Format cannot be blank."
msgstr ""
msgid "cdrom"
msgstr ""
msgid "disk"
msgstr ""
msgid "Pool"
msgstr ""
msgid "qcow"
msgstr ""
msgid "qcow2"
msgstr ""
msgid "qed"
msgstr ""
msgid "raw"
msgstr ""
msgid "vmdk"
msgstr ""
msgid "vpc"
msgstr ""
msgid "Create a network"
msgstr "네트워크 작성"
msgid "Network Name"
msgstr "네트워크 이름"
msgid "Name should not contain '/' and '\"'."
msgstr "이름에는 '/' 및 '\"'를 포함하지 않아야 합니다."
msgid "Network Type"
msgstr "네트워크 유형"
msgid "Isolated: no external network connection"
msgstr "격리됨: 외부 네트워크 연결 없음"
msgid "NAT: outbound physical network connection only"
msgstr "NAT: 아웃바운드 물리적 네트워크 연결만"
msgid "Macvtap: Virtual machines are connected to physical network directly"
msgstr ""
msgid ""
"Passthrough: Virtual machines are connected using a macvtap connection in "
"passthrough mode."
msgstr ""
msgid ""
"VEPA: special mode where virtual machines are connected to a VEPA-enabled "
"switch"
msgstr ""
msgid "Bridged: Virtual machines are connected through a network bridge"
msgstr ""
msgid "Destination"
msgstr "목적지"
msgid "Select an Interface"
msgstr ""
msgid "Enable VLAN"
msgstr "VLAN 사용"
msgid "VLAN ID"
msgstr "VLAN ID"
msgid "Edit Network"
msgstr ""
msgid "Address Space"
msgstr ""
msgid "Define a New Storage Pool"
msgstr "새 스토리지 풀 정의"
msgid "Storage Pool Name"
msgstr "스토리지 풀 이름"
msgid ""
"The name used to identify the storage pools, and it should not be empty."
msgstr "스토리지 풀을 식별하는 데 사용되는 이름이며 비어 있지 않아야 합니다."
msgid "Storage Pool Type"
msgstr "스토리지 풀 유형"
msgid "Storage Path"
msgstr "스토리지 경로"
msgid ""
"The path of the Storage Pool. Each Storage Pool must have a unique path."
msgstr "스토리지 풀의 경로입니다. 각 스토리지 풀은 고유 경로를 가져야 합니다."
msgid ""
"Kimchi will try to create the directory when it does not already exist in "
"your system."
msgstr ""
"디렉토리가 시스템에 이미 존재하지 않으면 Kimchi가 디렉토리 작성을 시도합니다."
msgid "NFS Server IP"
msgstr "NFS 서버 IP"
msgid "NFS server IP or hostname. It can be input or chosen from history."
msgstr ""
"NFS 서버 IP 또는 호스트 이름입니다. 이것은 입력하거나 히스토리에서 선택할 수 "
"있습니다."
msgid "NFS Path"
msgstr "NFS 경로"
msgid "The NFS exported path on NFS server."
msgstr "NFS 서버에서 NFS의 내보낸 경로입니다."
msgid "Create from existing LVM"
msgstr ""
msgid "Create from raw disk"
msgstr ""
msgid "Looking for existing lvms ..."
msgstr ""
msgid "Looking for available partitions ..."
msgstr "사용 가능한 파티션을 찾는 중..."
msgid "iSCSI Server"
msgstr "iSCSI 서버"
msgid "Server"
msgstr "서버"
msgid "Port"
msgstr "포트"
msgid "iSCSI server IP or hostname. It should not be empty."
msgstr "iSCSI 서버 IP 또는 호스트 이름입니다. 비어 있지 않아야 합니다."
msgid "Target"
msgstr "대상"
msgid "The iSCSI target on iSCSI server"
msgstr "iSCSI 서버의 iSCSI 대상"
msgid "Add iSCSI Authentication"
msgstr "iSCSI 인증 추가"
msgid "User Name"
msgstr "사용자 이름"
msgid "SCSI Adapter"
msgstr "SCSI 어댑터"
msgid "Please, wait..."
msgstr "잠시 기다려 주십시오."
msgid "Add a Volume to Storage Pool"
msgstr "스토리지 풀에 볼륨 추가"
msgid "Fetch from remote URL"
msgstr "원격 URL에서 페치"
msgid "Enter the remote URL here."
msgstr "여기에 원격 URL을 입력하십시오."
msgid "Upload a file"
msgstr "파일 업로드"
msgid "Choose the file you want to upload."
msgstr "업로드할 파일을 선택하십시오."
msgid "Resize Volume"
msgstr ""
msgid "Size"
msgstr ""
msgid "The total space which can be used to store data. The unit is megabytes."
msgstr ""
msgid "Ok"
msgstr ""
msgid "Template Name"
msgstr ""
msgid ""
"The name used to identify the template. If omitted, a name will be "
"automatically chosen."
msgstr ""
msgid ""
"When selecting more than one Image Template, a name will be automatically "
"chosen for each Image Template selected."
msgstr ""
msgid "Where is the source media for this template? "
msgstr ""
msgid "Image Template"
msgstr ""
msgid "Netboot Template"
msgstr ""
msgid "File Path:"
msgstr "파일 경로:"
msgid "Search ISOs"
msgstr "ISO 검색"
msgid "The following ISOs are available:"
msgstr "다음 ISO가 사용 가능합니다."
msgid "QEMU does not have enough permission to work with this file"
msgstr ""
msgid "Search more ISOs"
msgstr "추가 ISO 검색"
msgid "Loading..."
msgstr ""
msgid "Edit Template"
msgstr "템플리트 편집"
msgid "CDROM"
msgstr "CDROM"
msgid "Image File"
msgstr "이미지 파일"
msgid "Graphics"
msgstr "그래픽"
msgid "Disk(GB)"
msgstr "디스크(GB)"
msgid "Disk Format"
msgstr "디스크 형식"
msgid "Add Interface"
msgstr ""
msgid "pool"
msgstr ""
msgid "bridge"
msgstr ""
msgid "vepa"
msgstr ""
msgid "State"
msgstr ""
msgid "Guest Name ID"
msgstr ""
msgid "OS Type"
msgstr ""
msgid "VNC"
msgstr ""
msgid "No guests found."
msgstr ""
msgid "Stop"
msgstr ""
msgid "Location"
msgstr ""
msgid "%Used"
msgstr ""
msgid "Allocated"
msgstr ""
msgid "Capacity"
msgstr ""
msgid "Disks"
msgstr ""
msgid "Extending logical pool"
msgstr ""
msgid "%"
msgstr ""
msgid "Deactivate"
msgstr ""
msgid "Activate"
msgstr ""
msgid "Extend"
msgstr ""
msgid "Undefine"
msgstr ""
msgid "Add Volume"
msgstr ""
msgid "Resize"
msgstr ""
msgid "Wipe"
msgstr ""
msgid "Filter:"
msgstr ""
msgid "Used By"
msgstr ""
msgid "Used"
msgstr ""
msgid "Progress"
msgstr ""
msgid "Used by the following VMs:"
msgstr ""
msgid "Allocation"
msgstr ""
msgid "Template Name (ID)"
msgstr ""
msgid "No templates found."
msgstr ""
msgid "M"
msgstr ""
================================================
FILE: po/pt_BR.po
================================================
# Portuguese translations for kimchi package.
# Copyright IBM Corp, 2013-2017
# Adam Litke , 2013.
#
msgid ""
msgstr ""
"Project-Id-Version: kimchi 0.1\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2017-06-30 10:27-0300\n"
"PO-Revision-Date: 2013-07-11 17:32-0400\n"
"Last-Translator: Crístian Viana \n"
"Language-Team: English\n"
"Language: pt_BR\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: pygettext.py 1.5\n"
"Plural-Forms: nplurals=2; plural=n>1;\n"
#, python-format
msgid "Unknown parameter %(value)s"
msgstr "Parâmetro desconhecido %(value)s"
#, python-format
msgid "User %(user_id)s not found with given LDAP settings."
msgstr ""
"Usuário %(user_id)s não localizado com as configurações de LDAP fornecidas."
#, python-format
msgid "Partition %(name)s does not exist in the host"
msgstr "A partição %(name)s não existe no host"
msgid "Error while accessing dev mapper device, %(err)s"
msgstr ""
msgid "Block device not found."
msgstr ""
msgid "Block device %(device)s not found."
msgstr ""
msgid "Unable to retrieve LVM information. Details: %(err)s"
msgstr ""
msgid "Unknown \"_cap\" specified"
msgstr "\"_cap\" desconhecido especificado"
msgid "\"_passthrough\" should be \"true\" or \"false\""
msgstr "\"_passthrough\" deve ser \"true\" ou \"false\""
msgid "\"_passthrough_affected_by\" should be a device name string"
msgstr ""
"\"_passthrough_affected_by\" deve ser uma sequência de nome do dispositivo"
msgid "\"_available_only\" should be \"true\" or \"false\""
msgstr "\"_available_only\" deve ser \"true\" ou \"false\""
#, python-format
msgid "Unable to find distro file: %(filename)s"
msgstr "Não é possível localizar o arquivo distro: %(filename)s"
#, python-format
msgid ""
"Unable to parse distro file: %(filename)s. Make sure, it is a JSON file."
msgstr ""
"Não é possível analisar o arquivo distro: %(filename)s. Certifique-se de que "
"seja um arquivo JSON."
#, python-format
msgid "Unable to login to iSCSI host target %(portal)s. Details: %(err)s"
msgstr ""
"Não é possível efetuar login no destino do host iSCSI %(portal)s. Detalhes: "
"%(err)s"
#, python-format
msgid "Unable to login to iSCSI host %(host)s target %(target)s"
msgstr ""
"Não é possível efetuar login no destino %(target)s do host %(host)s iSCSI"
#, python-format
msgid "Unable to find ISO file %(filename)s"
msgstr "Não é possível localizar o arquivo ISO %(filename)s"
#, python-format
msgid "The ISO file %(filename)s is not bootable"
msgstr "O arquivo ISO %(filename)s não é inicializável"
#, python-format
msgid "The ISO file %(filename)s does not have a valid El Torito boot record"
msgstr ""
"O arquivo ISO %(filename)s não possui um registro de inicialização El Torito "
"válido"
#, python-format
msgid "Invalid El Torito validation entry in ISO %(filename)s"
msgstr "Entrada de validação El Torito inválida no ISO %(filename)s"
#, python-format
msgid "Invalid El Torito boot indicator in ISO %(filename)s"
msgstr "Indicador de inicialização El Torito inválido no ISO %(filename)s"
#, python-format
msgid "Unexpected volume type for primary volume in ISO %(filename)s"
msgstr "Tipo de volume inesperado para o volume primário no ISO %(filename)s"
#, python-format
msgid "Bad format while reading volume descriptor in ISO %(filename)s"
msgstr "Formato inválido ao ler o descritor de volume no ISO %(filename)s"
#, python-format
msgid ""
"The hypervisor doesn't have permission to use this ISO %(filename)s. "
"Consider moving it under /var/lib/libvirt, or set the search permission to "
"file access control lists for '%(user)s' user if possible, or add the "
"'%(user)s' to the ISO path group, or (not recommended) 'chmod -R o+x "
"'path_to_iso'.Details: %(err)s"
msgstr ""
"O hypervisor não possui permissão para usar este ISO %(filename)s. Considere "
"movê-lo sob /var/lib/libvirt ou configure a permissão de procura para listas "
"de controle de acesso de arquivo para o usuário '%(user)s', se possível, ou "
"inclua o '%(user)s' no grupo de caminhos ISO ou (não recomendado) 'chmod -R o"
"+x 'path_to_iso'.Detalhes: %(err)s"
#, python-format
msgid "Unable to access remote ISO. Details: %(err)s"
msgstr ""
#, python-format
msgid "Error probing image OS information: %(err)s"
msgstr ""
#, python-format
msgid "Unable to read image file %(filename)s"
msgstr "Não é possível ler o arquivo de imagem %(filename)s"
#, python-format
msgid ""
"Image file must be an existing file on system. %(filename)s is not a valid "
"input."
msgstr ""
"O arquivo de imagem deve ser um arquivo existente no sistema. O %(filename)s "
"não é valido válida."
#, python-format
msgid "Virtual machine %(name)s already exists"
msgstr "A máquina virtual %(name)s já existe"
#, python-format
msgid "Virtual machine %(name)s does not exist"
msgstr "A máquina virtual %(name)s não existe"
#, python-format
msgid "Unable to retrieve screenshot for stopped virtual machine %(name)s"
msgstr ""
"Não é possível recuperar a captura de tela para a máquina virtual "
"interrompida %(name)s"
msgid "Remote ISO image is not supported by this server."
msgstr "A imagem ISO remota não é suportada por este servidor."
#, python-format
msgid "Screenshot is not supported on virtual machine %(name)s"
msgstr "A captura de tela não é suportada em máquina virtual %(name)s"
#, python-format
msgid "Unable to create virtual machine %(name)s. Details: %(err)s"
msgstr "Não é possível criar a máquina virtual %(name)s. Detalhes: %(err)s"
#, python-format
msgid "Unable to update virtual machine %(name)s. Details: %(err)s"
msgstr "Não é possível atualizar a máquina virtual %(name)s. Detalhes: %(err)s"
#, python-format
msgid "Unable to retrieve virtual machine %(name)s. Details: %(err)s"
msgstr "Não é possível recuperar a máquina virtual %(name)s. Detalhes: %(err)s"
#, python-format
msgid "Unable to connect to powered off virtual machine %(name)s."
msgstr "Não é possível se conectar à máquina virtual desligada %(name)s."
msgid "Virtual machine name must be a string without slashes (/)"
msgstr "O nome da máquina virtual deve ser uma sequência sem barras (/)"
#, python-format
msgid "Invalid template URI %(value)s specified for virtual machine"
msgstr "URI do modelo %(value)s inválido especificado para máquina virtual"
#, python-format
msgid "Invalid storage pool URI %(value)s specified for virtual machine"
msgstr ""
"URI do banco de armazenamento %(value)s inválido especificado para máquina "
"virtual"
msgid "Supported virtual machine graphics are Spice or VNC"
msgstr "Os gráficos de máquina virtual suportados são Spice ou VNC"
msgid "Graphics address to listen on must be IPv4 or IPv6"
msgstr "O endereço do gráfico para atendimento deve ser IPv4 ou IPv6"
msgid "Specify a template to create a virtual machine from"
msgstr "Especifique um modelo para criar uma máquina virtual a partir dele"
#, python-format
msgid "Unable to start virtual machine %(name)s. Details: %(err)s"
msgstr "Não é possível iniciar a máquina virtual %(name)s. Detalhes: %(err)s"
#, python-format
msgid "Unable to power off virtual machine %(name)s. Details: %(err)s"
msgstr "Não é possível desligar a máquina virtual %(name)s. Detalhes: %(err)s"
#, python-format
msgid "Unable to delete virtual machine %(name)s. Details: %(err)s"
msgstr "Não é possível excluir a máquina virtual %(name)s. Detalhes: %(err)s"
#, python-format
msgid "Unable to reset virtual machine %(name)s. Details: %(err)s"
msgstr ""
"Não é possível reconfigurar a máquina virtual %(name)s. Detalhes: %(err)s"
msgid "User name list must be an array"
msgstr "A lista de nomes de usuário deve ser uma matriz"
msgid "User name must be a string"
msgstr "O nome de usuário deve ser uma sequência"
msgid "Group name list must be an array"
msgstr "A lista de nomes grupo deve ser uma matriz"
msgid "Group name must be a string"
msgstr "O nome do grupo deve ser uma sequência"
#, python-format
msgid "User(s) '%(users)s' do not exist"
msgstr "O(s) usuário(s) '%(users)s' não existem"
#, python-format
msgid "Group(s) '%(groups)s' do not exist"
msgstr "O(s) grupo(s) '%(groups)s' não existem"
#, python-format
msgid "Unable to shutdown virtual machine %(name)s. Details: %(err)s"
msgstr "Não é possível encerrar a máquina virtual %(name)s. Detalhes: %(err)s"
msgid "The guest console password must be a string."
msgstr "A senha do console da máquina guest deve ser uma sequência."
msgid "The life time for the guest console password must be a number."
msgstr ""
"O tempo de vida para a senha do console da máquina guest deve ser um número."
#, python-format
msgid "Virtual machine '%(name)s' must be stopped before cloning it."
msgstr ""
"A máquina virtual '%(name)s' deve ser interrompida antes que seja clonada."
#, python-format
msgid "Insufficient disk space to clone virtual machine '%(name)s'"
msgstr "Espaço em disco insuficiente para clonar a máquina virtual '%(name)s'."
#, python-format
msgid "Unable to clone VM '%(name)s'. Details: %(err)s"
msgstr "Não é possível clonar a VM '%(name)s'. Detalhes: %(err)s"
#, python-format
msgid "Invalid operation for non-persistent virtual machine %(name)s"
msgstr "Operação inválida para máquina virtual não persistente %(name)s"
#, python-format
msgid "Cannot suspend VM '%(name)s' because it is not running."
msgstr ""
"Não é possível suspender a VM '%(name)s' porque ela não está em execução."
#, python-format
msgid "Unable to suspend VM '%(name)s'. Details: %(err)s"
msgstr "Não é possível suspender a VM '%(name)s'. Detalhes: %(err)s"
#, python-format
msgid "Cannot resume VM '%(name)s' because it is not paused."
msgstr "Não é possível continuar a VM '%(name)s' porque ela não está pausada."
#, python-format
msgid "Unable to resume VM '%(name)s'. Details: %(err)s"
msgstr "Não é possível continuar a VM %(name)s. Detalhes: %(err)s"
#, python-format
msgid ""
"Memory assigned is higher then the maximum allowed in the host: "
"%(maxmem)sMib."
msgstr ""
#, python-format
msgid ""
"Guest '%(name)s' does not support live memory update. Please, with the guest "
"offline, set Maximum Memory with a value greater then Memory to enable this "
"feature."
msgstr ""
msgid "Only increase memory is allowed in active VMs"
msgstr "Somente aumentar memória é permitido em VMs ativas"
msgid "There are not enough free slots to add a new memory device."
msgstr ""
msgid ""
"Host's libvirt or qemu version does not support memory devices and memory "
"hotplug. Libvirt must be >= 1.2.14 and QEMU must be >= 2.1."
msgstr ""
#, python-format
msgid "Error attaching memory device. Details: %(error)s"
msgstr "Erro ao anexar dispositivo de memória. Detalhes: %(error)s"
#, python-format
msgid "Cannot start %(name)s. Virtual machine is already running."
msgstr ""
"Não é possível iniciar o %(name)s. A máquina virtual já está em execução."
#, python-format
msgid "Cannot power off %(name)s. Virtual machine is shut off."
msgstr "Não é possível desligar o %(name)s. A máquina virtual está desligada."
#, python-format
msgid "Cannot shutdown %(name)s. Virtual machine is shut off."
msgstr "Não é possível encerrar o %(name)s. A máquina virtual está desligada."
#, python-format
msgid "Cannot reset %(name)s. Virtual machine is already shut off."
msgstr ""
"Não é possível reconfigurar o %(name)s. A máquina virtual já está desligada."
msgid "Boot order must be a list. Devices accepted: hd, cdrom, fd or network."
msgstr ""
msgid "Bootmenu must be boolean. Values accepted: true of false."
msgstr ""
msgid "Graphic type not valid. Values accepted: vnc or spice."
msgstr ""
#, python-format
msgid "Migrate to localhost %(host)s is not allowed."
msgstr ""
#, python-format
msgid ""
"To migrate a virtual machine to the remote host %(host)s the user %(user)s "
"must have password-less login to the remote host."
msgstr ""
#, python-format
msgid "Can not migrate virtual machine %(name)s when its in %(state)s state."
msgstr ""
#, python-format
msgid "Failed to migrate virtual machine %(name)s due error: %(err)s"
msgstr ""
msgid "User name of the remote server must be a string."
msgstr ""
msgid "Destination host of the migration must be a string."
msgstr ""
#, python-format
msgid "Unable to create file %(path)s at %(host)s using user %(user)s."
msgstr ""
#, python-format
msgid "Unable to read disk size of %(path)s, error: %(error)s"
msgstr ""
#, python-format
msgid ""
"Unable to create disk image %(path)s at %(host)s using user %(user)s. Error: "
"%(error)s"
msgstr ""
#, python-format
msgid ""
"Unable to migrate virtual machine to remote host %(host)s with arch "
"%(destarch)s using localhost with arch %(srcarch)s."
msgstr ""
#, python-format
msgid ""
"Unable to migrate virtual machine to remote host %(host)s with hypervisor "
"%(desthyp)s because localhost uses hypervisor %(srchyp)s."
msgstr ""
#, python-format
msgid ""
"Unable to determine remote host hypervisor and architecture. Error: %(error)s"
msgstr ""
#, python-format
msgid ""
"Unable to migrate virtual machine: subcores per core setting from "
"localhostand remote host %(host)s differs."
msgstr ""
#, python-format
msgid ""
"Unable to setup password-less login at remote host %(host)s using user "
"%(user)s. Error: %(error)s"
msgstr ""
msgid "Password field must be a string."
msgstr ""
msgid "Error creating local host ssh rsa key of user 'root'."
msgstr ""
#, python-format
msgid "%(param)s value (%(mem)sMiB) must be aligned to %(alignment)sMiB."
msgstr ""
#, python-format
msgid ""
"Unable to update the following parameters while the VM is offline: %(params)s"
msgstr ""
#, python-format
msgid ""
"Unable to update the following parameters while the VM is online: %(params)s"
msgstr ""
#, python-format
msgid ""
"VM %(name)s must have serial and console defined to open a web serial console"
msgstr ""
#, python-format
msgid "Impossible to get the serial console of %(name)s"
msgstr ""
#, python-format
msgid ""
"Memory or Maximum Memory value is higher than amount supported by the host: "
"%(memHost)sMiB."
msgstr ""
#, python-format
msgid ""
"Memory or Maximum Memory value is higher than maximum amount recommended: "
"%(value)sTiB"
msgstr ""
msgid "Cannot update Maximum Memory when guest is running."
msgstr ""
#, python-format
msgid "Impossible to create %(dir)s directory."
msgstr ""
#, python-format
msgid ""
"Either the guest %(name)s did not start to listen to the serial or it is not "
"configured to use the serial console."
msgstr ""
#, python-format
msgid ""
"Unable to retrieve Virt Viewer file for stopped virtual machine %(name)s"
msgstr ""
#, python-format
msgid ""
"Error occured while retrieving the Virt Viewer file for virtual machine "
"%(name)s : %(err)s"
msgstr ""
msgid "Virtual machine title must be a string"
msgstr ""
msgid "Virtual machine description must be a string"
msgstr ""
msgid "console parameter is only supported for s390x/s390 architecture."
msgstr ""
msgid "invalid console type, supported types are sclp/virtio."
msgstr ""
#, python-format
msgid ""
"Unable to setup password-less login at remote host %(host)s using user "
"%(user)s: remote directory %(sshdir)s does not exist."
msgstr ""
#, python-format
msgid ""
"Unable to create a password-less libvirt connection to the remote libvirt "
"daemon at host %(host)s with the user %(user)s. Please verify the remote "
"server libvirt configuration. More information: http://libvirt.org/auth."
"html ."
msgstr ""
msgid "'enable_rdma' must be of type boolean (true or false)."
msgstr ""
#, python-format
msgid ""
"VM %(vmid)s does not contain directly assigned host device %(dev_name)s."
msgstr ""
"A VM %(vmid)s não contém o dispositivo host diretamente designado "
"%(dev_name)s."
#, python-format
msgid "The host device %(dev_name)s is not allowed to directly assign to VM."
msgstr ""
"O dispositivo host %(dev_name)s não tem permissão para designar diretamente "
"para a VM."
msgid ""
"No IOMMU groups found. Host PCI pass through needs IOMMU group to function "
"correctly. Please enable Intel VT-d or AMD IOMMU in your BIOS, then verify "
"the Kernel is compiled with IOMMU support. For Intel CPU, add "
"'intel_iommu=on' to GRUB_CMDLINE_LINUX parameter in /etc/default/grub file. "
"For AMD CPU, add 'iommu=pt iommu=1'."
msgstr ""
msgid "\"name\" should be a device name string"
msgstr "\"name\" deve ser uma sequência de nome do dispositivo"
#, python-format
msgid ""
"The device %(name)s is probably in use by the host. Unable to attach it to "
"the guest."
msgstr ""
"O dispositivo %(name)s provavelmente está em uso pelo host. Não é possível "
"conectá-lo à máquina guest."
#, python-format
msgid "Hot-(un)plug of device %(name)s is not supported."
msgstr ""
#, python-format
msgid "Failed to attach %(device)s to %(vm)s"
msgstr ""
#, python-format
msgid "VM %(vmid)s does not have a USB controller to accept PCI hotplug."
msgstr ""
#, python-format
msgid "Interface %(iface)s does not exist in virtual machine %(name)s"
msgstr "A interface %(iface)s não existe na máquina virtual %(name)s"
#, python-format
msgid ""
"Network %(network)s specified for virtual machine %(name)s does not exist"
msgstr ""
"A rede %(network)s especificada para máquina virtual %(name)s não existe"
msgid ""
"Supported virtual machine interfaces type are network, ovs and macvtap.Type "
"ovs and macvtap are only supported for s390x/s390 architecture."
msgstr ""
msgid "Network name for virtual machine interface must be a string"
msgstr "O nome da rede para a interface de máquina virtual deve ser um texto"
msgid "Invalid network model card specified for virtual machine interface"
msgstr ""
"Placa do modelo de rede inválida especificada para a interface de máquina "
"virtual"
msgid "Specify type and network to add a new virtual machine interface"
msgstr ""
"Especifique o tipo e a rede para incluir uma nova interface de máquina "
"virtual"
msgid "MAC Address must respect this format FF:FF:FF:FF:FF:FF"
msgstr "O Endereço MAC deve respeitar esse formato FF:FF:FF:FF:FF:FF"
#, python-format
msgid "MAC Address %(mac)s already exists in virtual machine %(name)s"
msgstr "O Endereço MAC %(mac)s já existe na máquina virtual %(name)s"
msgid "Invalid MAC Address"
msgstr "Endereço MAC inválido"
msgid "Cannot change MAC address of a running virtual machine"
msgstr "Não é possível mudar o endereço MAC de uma máquina virtual em execução"
msgid "Type macvtap and ovs are only supported on s390x/s390 architecture."
msgstr ""
msgid "Source attribute is only supported on s390x/s390 architecture."
msgstr ""
msgid "If source is provided, only type supported are macvtap and ovs."
msgstr ""
msgid "For type macvtap and ovs, source has to be provided"
msgstr ""
msgid "Source name for virtual machine interface must be string"
msgstr ""
msgid "Invalid source mode. Valid options are: bridge or vepa."
msgstr ""
#, python-format
msgid "Template %(name)s already exists"
msgstr "O modelo %(name)s já existe"
#, python-format
msgid "Source media %(path)s not found"
msgstr ""
#, python-format
msgid ""
"Network '%(network)s' specified for template %(template)s does not exist"
msgstr ""
"A rede '%(network)s' especificada para o modelo %(template)s não existe"
#, python-format
msgid ""
"Storage pool %(pool)s specified for template %(template)s does not exist"
msgstr ""
"O banco de armazenamento %(pool)s especificado para o modelo %(template)s "
"não existe"
#, python-format
msgid "Invalid parameter '%(param)s' specified for CDROM."
msgstr "Parâmetro inválido '%(param)s' especificado para CDROM."
#, python-format
msgid "Network %(network)s specified for template %(template)s is not active"
msgstr ""
"Rede %(network)s especificada para o modelo %(template)s não está ativa"
msgid "Template name must be a string"
msgstr "O nome de modelo deve ser um texto"
msgid "Template icon must be a path to the image"
msgstr "O ícone de modelo deve ser um caminho para a imagem"
msgid "Template distribution must be a string"
msgstr "A distribuição do modelo deve ser um texto"
msgid "Template distribution version must be a string"
msgstr "A versão de distribuição do modelo deve ser um texto"
msgid "The number of CPUs must be an integer greater than 0"
msgstr ""
"O número de CPUs (unidades centrais de processamento) deve ser um número "
"inteiro maior que 0"
msgid ""
"Amount of memory and maximum memory (MB) must be an integer greater than 512"
msgstr ""
msgid "Template CDROM must be a local or remote ISO file"
msgstr "O modelo CD-ROM deve ser um arquivo ISO local ou remoto"
#, python-format
msgid "Invalid storage pool URI %(value)s specified for template"
msgstr ""
"URI do banco de armazenamento %(value)s inválido especificado para modelo"
msgid ""
"Specify a path to source media (ISO, disk or remote ISO) to create a template"
msgstr ""
msgid "All networks for the template must be specified in a list."
msgstr "Todas as redes para o modelo devem ser especificadas em uma lista."
msgid "Specify a volume to a template when storage pool is iSCSI or SCSI"
msgstr ""
"Especifique um volume para um modelo quando o banco de armazenamento for "
"iSCSI ou SCSI"
#, python-format
msgid "The volume %(volume)s is not in storage pool %(pool)s"
msgstr "O volume %(volume)s não está no banco de armazenamento %(pool)s"
#, python-format
msgid "Unable to create template due error: %(err)s"
msgstr "Não é possível criar o modelo devido ao erro: %(err)s"
#, python-format
msgid "Unable to delete template due error: %(err)s"
msgstr "Não é possível excluir o modelo devido ao erro: %(err)s"
msgid "Disk size must be an integer greater than 1GB."
msgstr "O tamanho do disco deve ser um número inteiro maior que 1 GB."
#, python-format
msgid "Cannot identify base image %(path)s format"
msgstr "Não é possível identificar o formato da imagem base %(path)s"
msgid ""
"When specifying CPU topology, each element must be an integer greater than "
"zero."
msgstr ""
"Ao especificar a topologia da CPU, cada elemento deve ser um número inteiro "
"maior que zero."
msgid ""
"Invalid disk image format. Valid formats: qcow, qcow2, qed, raw, vmdk, vpc."
msgstr ""
msgid ""
"When setting template disks, following parameters are required: 'index', "
"'pool name', 'format', 'size' or 'volume' (for scsi/iscsi pools)"
msgstr ""
msgid "Disk format must be 'raw', for logical, iscsi, and scsi pools."
msgstr ""
msgid ""
"Memory expects an object with one or both parameters: 'current' and "
"'maxmemory'"
msgstr ""
#, python-format
msgid ""
"Memory value (%(mem)sMiB) must be equal or lesser than maximum memory value "
"(%(maxmem)sMiB)"
msgstr ""
#, python-format
msgid "Unable to update template due error: %(err)s"
msgstr ""
msgid "Parameter 'disks' requires at least one disk object"
msgstr ""
msgid ""
"Invalid interface type. Type should be 'macvtap' for host network interface "
"(Ethernet, Bond, VLAN) to be connected as direct MacVTap or 'ovs' for "
"openvswitch host network interface to be connected as virtual switch to a VM."
msgstr ""
msgid "Interface name should be string."
msgstr ""
msgid "Invalid interface mode. Valid options are: bridge or vepa."
msgstr ""
msgid ""
"Interfaces should be list of interfaces. Each interface should have name, "
"type and mode(optional, only applicable for interfcae type 'macvtap'."
msgstr ""
msgid ""
"Interface expects an object with parameters: 'name', 'type' and 'mode'. Name "
"should be name of host network interface (Ethernet, Bond, VLAN) for type "
"'macvtap' or the name of host openvswitch bridge interface for type 'ovs'. "
"Mode (optional) is only applicable for interface type 'macvtap' to indicates "
"whether packets will be delivered directly to target device (bridge) or to "
"the external bridge (vepa-capable bridge)."
msgstr ""
msgid "Interfaces parameter only supported on s390x or s390 architecture."
msgstr ""
msgid "Storage without libvirt pool is not supported on this architecture"
msgstr ""
#, python-format
msgid "Error while creating the virtual disk for the guest. Details: %(err)s"
msgstr ""
msgid ""
"When setting template disks without libvirt, following parameters are "
"required: 'index', 'format', 'path', 'size'"
msgstr ""
#, python-format
msgid "Storage pool %(name)s already exists"
msgstr "O banco de armazenamento %(name)s já existe"
#, python-format
msgid "Storage pool %(name)s does not exist"
msgstr "O banco de armazenamento %(name)s não existe"
#, python-format
msgid "Specify %(item)s in order to create the storage pool %(name)s"
msgstr "Especifique %(item)s para criar o banco de armazenamento %(name)s"
#, python-format
msgid "Unable to delete active storage pool %(name)s"
msgstr "Não é possível excluir o banco de armazenamento ativo %(name)s"
#, python-format
msgid "Unable to list storage pools. Details: %(err)s"
msgstr "Não é possível listar os bancos de armazenamento. Detalhes: %(err)s"
#, python-format
msgid "Unable to create storage pool %(name)s. Details: %(err)s"
msgstr ""
"Não é possível criar o banco de armazenamento %(name)s. Detalhes: %(err)s"
#, python-format
msgid "Unable to activate storage pool %(name)s. Details: %(err)s"
msgstr ""
"Não é possível ativar o banco de armazenamento %(name)s. Detalhes: %(err)s"
#, python-format
msgid "Unable to deactivate storage pool %(name)s. Details: %(err)s"
msgstr ""
"Não é possível desativar o banco de armazenamento %(name)s. Detalhes: %(err)s"
#, python-format
msgid "Unable to delete storage pool %(name)s. Details: %(err)s"
msgstr ""
"Não é possível excluir o banco de armazenamento %(name)s. Detalhes: %(err)s"
#, python-format
msgid ""
"Unable to create NFS Pool as export path %(path)s may block during mount"
msgstr ""
"Não é possível criar o Banco NFS porque o caminho de exportação %(path)s "
"pode bloquear durante a montagem"
#, python-format
msgid "Unable to create NFS Pool as export path %(path)s mount failed"
msgstr ""
"Não é possível criar o Banco NFS porque a montagem do caminho de exportação "
"%(path)s falhou"
#, python-format
msgid "Unsupported storage pool type: %(type)s"
msgstr "Tipo de banco de armazenamento não suportado: %(type)s"
#, python-format
msgid "Error while retrieving storage pool XML to %(pool)s"
msgstr "Erro ao recuperar o banco de armazenamento XML para %(pool)s"
msgid "Storage pool name must be a string without slashes (/)"
msgstr "O nome do banco de armazenamento deve ser uma sequência sem barras (/)"
msgid ""
"Supported storage pool types are dir, netfs, logical, iscsi, isci and kimchi-"
"iso"
msgstr ""
"Os tipos de banco de armazenamento suportados são dir, netfs, lógico, iscsi, "
"isci e kimchiiso"
msgid "Storage pool path must be a string"
msgstr "O caminho do banco de armazenamento deve ser um texto"
msgid "Storage pool host must be a IP or hostname"
msgstr "O host do banco de armazenamento deve ser um IP ou nome do host"
msgid "Storage pool device must be the absolute path to the block device"
msgstr ""
"O dispositivo do banco de armazenamento deve ser o caminho absoluto para o "
"dispositivo de bloco"
msgid "Storage pool devices parameter must be a list"
msgstr ""
"O parâmetro de dispositivos do banco de armazenamento deve ser uma lista"
msgid "Target IQN of an iSCSI pool must be a string"
msgstr "O IQN de destino de um banco iSCSI deve ser um texto"
msgid "Port of a remote storage server must be an integer between 1 and 65535"
msgstr ""
"A porta de um servidor de armazenamento remoto deve ser um número inteiro "
"entre 1 e 65535"
msgid "iSCSI target username must be a string"
msgstr "O nome do usuário de destino iSCSI deve ser uma sequência"
msgid "iSCSI target password must be a string"
msgstr "A senha de destino iSCSI deve ser uma sequência"
msgid "Specify name and type to create a storage pool"
msgstr "Especifique o nome e o tipo para criar um banco de armazenamento"
#, python-format
msgid ""
"%(disk)s is not a valid disk/partition. Could not add it to the pool "
"%(pool)s."
msgstr ""
"%(disk)s não é um disco/partição válido. Não foi possível incluí-lo no banco "
"%(pool)s."
#, python-format
msgid "Unable to extend logical pool %(pool)s. Details: %(err)s"
msgstr "Não é possível estender o banco lógico %(pool)s. Detalhes: %(err)s"
msgid "The parameter disks only can be updated for logical storage pool."
msgstr ""
"O parâmetro discos só pode ser atualizado para o banco de armazenamento "
"lógico."
msgid "The SCSI host adapter name must be a string."
msgstr "O nome do adaptador de host SCSI deve ser um texto."
msgid "The storage pool kimchi_isos is reserved for internal use"
msgstr "O banco de armazenamento kimchi_isos está reservado para uso interno"
#, python-format
msgid ""
"Unable to activate NFS storage pool %(name)s. NFS server %(server)s is "
"unreachable."
msgstr ""
"Não é possível ativar o banco de armazenamento NFS %(name)s. O servidor NFS "
"%(server)s é inacessível."
#, python-format
msgid ""
"Unable to deactivate NFS storage pool %(name)s. NFS server %(server)s is "
"unreachable."
msgstr ""
"Não é possível desativar o banco de armazenamento NFS %(name)s. O servidor "
"NFS %(server)s é inacessível."
#, python-format
msgid ""
"Unable to deactivate pool %(name)s as it is associated with some templates"
msgstr ""
"Não é possível desativar o banco %(name)s porque ele está associado com "
"alguns modelos"
#, python-format
msgid "Unable to delete pool %(name)s as it is associated with some templates"
msgstr ""
"Não é possível excluir o banco %(name)s porque ele está associado com alguns "
"modelos"
#, python-format
msgid ""
"A volume group named '%(name)s' already exists. Please, choose another name "
"to create the logical pool."
msgstr ""
"Um grupo de volumes nomeado '%(name)s' já existe. Escolha outro nome para "
"criar o banco lógico."
#, python-format
msgid "Unable to update database with deep scan information due error: %(err)s"
msgstr ""
"Não é possível atualizar o banco de dados com informações de varredura "
"completas devido ao erro: %(err)s"
#, python-format
msgid ""
"No volume group '%(name)s' found. Please, specify an existing volume group "
"to create the logical pool from."
msgstr ""
#, python-format
msgid "Unable to delete pool %(name)s as it is associated with guests: %(vms)s"
msgstr ""
#, python-format
msgid "Storage volume %(name)s already exists"
msgstr "O volume de armazenamento %(name)s já existe"
#, python-format
msgid "Storage volume %(name)s does not exist in storage pool %(pool)s"
msgstr ""
"O volume de armazenamento %(name)s não existe no banco de armazenamento "
"%(pool)s"
#, python-format
msgid ""
"Unable to create storage volume %(volume)s because storage pool %(pool)s is "
"not active"
msgstr ""
"Não é possível criar o volume de armazenamento %(volume)s porque o banco de "
"armazenamento %(pool)s não está ativo"
#, python-format
msgid "Specify %(item)s in order to create storage volume %(volume)s"
msgstr "Especifique %(item)s para criar o volume de armazenamento %(volume)s"
#, python-format
msgid ""
"Unable to list storage volumes because storage pool %(pool)s is not active"
msgstr ""
"Não é possível listar os volumes de armazenamento porque o banco de "
"armazenamento %(pool)s não está ativo"
#, python-format
msgid ""
"Unable to create storage volume %(name)s in storage pool %(pool)s. Details: "
"%(err)s"
msgstr ""
"Não é possível criar o volume de armazenamento %(name)s no banco de "
"armazenamento %(pool)s. Detalhes: %(err)s"
#, python-format
msgid "Unable to wipe storage volumes %(name)s. Details: %(err)s"
msgstr ""
"Não é possível limpar volumes de armazenamento %(name)s. Detalhes: %(err)s"
#, python-format
msgid "Unable to delete storage volume %(name)s. Details: %(err)s"
msgstr ""
"Não é possível excluir o volume de armazenamento %(name)s. Detalhes: %(err)s"
#, python-format
msgid "Unable to resize storage volume %(name)s. Details: %(err)s"
msgstr ""
"Não é possível redimensionar o volume de armazenamento %(name)s. Detalhes: "
"%(err)s"
#, python-format
msgid "Storage type %(type)s does not support volume create and delete"
msgstr ""
"O tipo de armazenamento %(type)s não suporta a criação e a exclusão de volume"
msgid "Storage volume name must be a string"
msgstr "O nome do volume de armazenamento deve ser um texto"
msgid "Storage volume allocation must be an integer number"
msgstr "A alocação do volume de armazenamento deve ser um número inteiro"
msgid ""
"Storage volume format not supported. Valid formats: qcow, qcow2, qed, raw, "
"vmdk, vpc."
msgstr ""
msgid "Storage volume requires a volume name"
msgstr "O volume de armazenamento requer um nome de volume"
#, python-format
msgid ""
"Unable to update database with storage volume information due error: %(err)s"
msgstr ""
"Não é possível atualizar o banco de dados com informações de volume de "
"armazenamento devido ao erro: %(err)s"
#, python-format
msgid "Only one of parameter %(param)s can be specified"
msgstr "Somente um dos parâmetros %(param)s pode ser especificado"
#, python-format
msgid "Create volume from %(param)s is not supported"
msgstr "Criação de volume a partir de %(param)s não é suportada"
msgid "Storage volume capacity must be an integer number."
msgstr "A capacidade do volume de armazenamento deve ser um número inteiro."
msgid "Storage volume URL must be http://, https://, ftp:// or ftps://."
msgstr ""
"A URL do volume de armazenamento deve ser http://, https://, ftp:// ou "
"ftps://."
#, python-format
msgid "Unable to access file %(url)s. Please, check it."
msgstr "Não é possível acessar o arquivo %(url)s. Verifique."
#, python-format
msgid ""
"Unable to clone storage volume '%(name)s' in pool '%(pool)s'. Details: "
"%(err)s"
msgstr ""
"Não é possível clonar o volume de armazenamento '%(name)s' no banco "
"'%(pool)s'. Detalhes: %(err)s"
msgid "Specify chunk data and its size to upload a file."
msgstr ""
"Especifique os dados de chunk e seu tamanho para fazer o upload de um "
"arquivo."
msgid "In order to upload a storage volume, specify the 'upload' parameter."
msgstr ""
"Para fazer o upload de um volume de armazenamento, especifique o parâmetro "
"'upload'."
msgid ""
"Unable to upload chunk data as it does not match with requested chunk size."
msgstr ""
"Não é possível fazer upload dos dados de chunk porque eles não correspondem "
"ao tamanho de chunk solicitado."
#, python-format
msgid "The storage volume %(vol)s is not under an upload process."
msgstr "O volume de armazenamento %(vol)s não está sob um processo de upload."
msgid "The upload chunk data will exceed the storage volume size."
msgstr ""
"Os dados de chunk de upload irão exceder o tamanho do volume de "
"armazenamento."
#, python-format
msgid "Unable to upload chunk data to storage volume. Details: %(err)s."
msgstr ""
"Não é possível fazer upload dos dados de chunk para o volume de "
"armazenamento. Detalhes: %(err)s."
#, python-format
msgid "Interface %(name)s does not exist"
msgstr "A interface %(name)s não existe"
#, python-format
msgid ""
"Failed to list interfaces. Invalid _inuse parameter. Supported options for "
"_inuse are: %(supported_inuse)s"
msgstr ""
#, python-format
msgid "Network %(name)s already exists"
msgstr "A rede %(name)s já existe"
#, python-format
msgid "Network %(name)s does not exist"
msgstr "A rede %(name)s não existe"
#, python-format
msgid "Subnet %(subnet)s specified for network %(network)s is not valid."
msgstr ""
msgid "Specify a network interface to create bridged or macvtap networks."
msgstr ""
#, python-format
msgid "Unable to delete or update active network %(name)s"
msgstr ""
#, python-format
msgid "Interface %(iface)s specified for network %(network)s is already in use"
msgstr ""
"A interface %(iface)s especificada para a rede %(network)s já está em uso."
msgid "Interface should be bare NIC, bonding or bridge device."
msgstr "A interface deve ser um dispositivo bare NIC, de ligação ou bridge."
#, python-format
msgid "Unable to create or update network %(name)s. Details: %(err)s"
msgstr ""
#, python-format
msgid "Unable to find a free IP address for network '%(name)s'"
msgstr "Não é possível localizar um endereço IP livre para a rede '%(name)s'"
#, python-format
msgid "The interface %(iface)s already exists."
msgstr "A interface %(iface)s já existe."
msgid "Network name must be a string without slashes (/) or quotes (\")"
msgstr "O nome da rede deve ser uma sequência sem barras (/) ou aspas (\")"
msgid ""
"Supported network types are isolated, NAT, macvtap, bridge, vepa and "
"passthrough."
msgstr ""
msgid "Network subnet must be a string with IP address and prefix or netmask"
msgstr ""
"A sub-rede da rede deve ser um texto com endereço IP e prefixo ou máscara de "
"rede"
msgid "Network interfaces must be an array."
msgstr ""
msgid "Network VLAN ID must be an integer between 1 and 4094"
msgstr "O ID de VLAN da rede deve ser um número inteiro entre 1 e 4094"
msgid "Specify name and type to create a Network"
msgstr "Especifique o nome e o tipo para criar uma Rede"
#, python-format
msgid ""
"Unable to delete or update network %(name)s as it is linked to some virtual "
"machines (%(vms)s) and/or templates (%(tmpls)s)."
msgstr ""
#, python-format
msgid ""
"Unable to deactivate network %(name)s as it is linked to are some virtual "
"machines (%(vms)s) and/or templates (%(tmpls)s)."
msgstr ""
#, python-format
msgid "Bridge device %(name)s can not be the trunk device of a VLAN."
msgstr ""
"O dispositivo de ponte %(name)s não pode ser o dispositivo de tronco de uma "
"VLAN."
#, python-format
msgid "Failed to activate interface %(iface)s: %(err)s."
msgstr "Falha ao ativar a interface %(iface)s: %(err)s."
#, python-format
msgid ""
"Failed to activate interface %(iface)s. Please check the physical link "
"status."
msgstr "Falha ao ativar a interface %(iface)s. Verifique o link físico físico."
#, python-format
msgid "Failed to start network %(name)s. Details: %(err)s"
msgstr "Falha ao iniciar a rede %(name)s. Detalhes: %(err)s"
#, python-format
msgid "Unable to redefine interface %(name)s. Details: %(err)s"
msgstr ""
#, python-format
msgid "Unable to create bridge %(name)s. Details: %(err)s"
msgstr ""
msgid ""
"Unable to create bridge with NetworkManager enabled. Disable it and try "
"again."
msgstr ""
msgid "Interface should be bare NIC or bonding."
msgstr ""
msgid "Network interfaces parameter must contain at least one interface."
msgstr ""
msgid "Only one interface is allowed for 'bridge' and 'macvtap' networks."
msgstr ""
msgid "Subnet is not a valid parameter for this type of virtual network."
msgstr ""
msgid ""
"VLAN ID and interfaces are not valid parameters for this type of virtual "
"network."
msgstr ""
#, python-format
msgid "Storage server %(server)s was not used by Kimchi"
msgstr "O servidor de armazenamento %(server)s não foi usado pelo Kimchi"
#, python-format
msgid "Distro '%(name)s' does not exist"
msgstr "Distro '%(name)s' não existe"
#, python-format
msgid "Node device '%(name)s' not found"
msgstr "Dispositivo de nó '%(name)s' não localizado"
msgid "Conflicting flag filters specified."
msgstr "Filtros de sinalização conflitantes especificados."
msgid "Unable to choose a virtual machine name"
msgstr "Não é possível escolher um nome de máquina virtual"
msgid "Cannot upgrade objectstore data."
msgstr ""
msgid "Invalid storage type. Types supported: 'cdrom', 'disk'"
msgstr "Tipo de armazenamento inválido. Tipos suportados: 'cdrom', 'disk'"
#, python-format
msgid "The path '%(value)s' is not a valid local/remote path for the device"
msgstr ""
"O caminho '%(value)s' não é um caminho local/remoto válido para o dispositivo"
msgid "Only CDROM path can be update."
msgstr "Somente o caminho CDROM pode ser atualizado."
#, python-format
msgid ""
"The storage device %(dev_name)s does not exist in the virtual machine "
"%(vm_name)s"
msgstr ""
"O dispositivo de armazenamento %(dev_name)s não existe na máquina virtual "
"%(vm_name)s"
#, python-format
msgid "Error while creating new storage device: %(error)s"
msgstr "Erro ao criar o novo dispositivo de armazenamento: %(error)s"
#, python-format
msgid "Error while updating storage device: %(error)s"
msgstr "Erro ao atualizar o dispositivo de armazenamento: %(error)s"
#, python-format
msgid "Error while removing storage device: %(error)s"
msgstr "Erro ao remover o dispositivo de armazenamento: %(error)s"
msgid "Do not support IDE device hot plug"
msgstr "Não suportar hot plug de dispositivo IDE"
msgid ""
"Specify type and path or type and pool/volume to add a new virtual machine "
"disk"
msgstr ""
"Especificar tipo e caminho ou tipo e banco/volume para incluir um novo disco "
"de máquina virtual"
msgid "Specify path to update virtual machine disk"
msgstr "Especifique o caminho para atualizar o disco de máquina virtual"
#, python-format
msgid "Controller type %(type)s limitation of %(limit)s devices reached"
msgstr ""
"Limitação de tipo de controlador %(type)s de %(limit)s dispositivos atingidos"
#, python-format
msgid "Cannot retrieve disk path information for given pool/volume: %(error)s"
msgstr ""
"Não é possível recuperar informações de caminho do disco para o banco/volume "
"fornecido: %(error)s"
msgid "Volume already in use by other virtual machine."
msgstr "O volume já está sendo usado por outra máquina virtual."
msgid ""
"Only one of path or pool/volume can be specified to add a new virtual "
"machine disk"
msgstr ""
"Apenas um caminho ou banco/volume podem ser especificados para inclusão de "
"um novo disco de máquina virtual"
#, python-format
msgid ""
"Volume chosen with format %(format)s does not fit in the storage type "
"%(type)s"
msgstr ""
"O volume escolhido com o formato %(format)s não se ajusta no tipo de "
"armazenamento %(type)s"
msgid "On s390x arch one of pool, path of dir_path must be specified"
msgstr ""
msgid ""
"On s390x arch 'format' must be specified while attaching disk to virtual "
"machine"
msgstr ""
#, python-format
msgid "Virtual disk already exists on the system: %(disk_path)s"
msgstr ""
#, python-format
msgid ""
"Unable to create snapshot '%(name)s' on virtual machine '%(vm)s'. Details: "
"%(err)s"
msgstr ""
"Não é possível criar captura instantânea '%(name)s' na máquina virtual "
"'%(vm)s'. Detalhes: %(err)s"
#, python-format
msgid "Snapshot '%(name)s' does not exist on virtual machine '%(vm)s'."
msgstr ""
"A captura instantânea '%(name)s' não existe na máquina virtual '%(vm)s'."
#, python-format
msgid ""
"Unable to retrieve snapshot '%(name)s' on virtual machine '%(vm)s'. Details: "
"%(err)s"
msgstr ""
"Não é possível recuperar a captura instantânea '%(name)s' na máquina virtual "
"'%(vm)s'. Detalhes: %(err)s"
#, python-format
msgid "Unable to list snapshots on virtual machine '%(vm)s'. Details: %(err)s"
msgstr ""
"Não é possível listar capturas instantâneas na máquina virtual '%(vm)s'. "
"Detalhes: %(err)s"
#, python-format
msgid ""
"Unable to delete snapshot '%(name)s' on virtual machine '%(vm)s'. Details: "
"%(err)s"
msgstr ""
"Não é possível excluir a captura instantânea '%(name)s' na máquina virtual "
"'%(vm)s'. Detalhes: %(err)s"
#, python-format
msgid ""
"Unable to retrieve current snapshot of virtual machine '%(vm)s'. Details: "
"%(err)s"
msgstr ""
"Não é possível recuperar a captura instantânea atual da máquina virtual "
"'%(vm)s'. Detalhes: %(err)s"
#, python-format
msgid ""
"Unable to revert virtual machine '%(vm)s' to snapshot '%(name)s'. Details: "
"%(err)s"
msgstr ""
"Não é possível reverter a máquina virtual '%(vm)s' para a captura "
"instantânea '%(name)s'. Detalhes: %(err)s"
#, python-format
msgid ""
"Unable to create snapshot of virtual machine '%(vm)s' because it contains a "
"disk with format '%(format)s'; only 'qcow2' is supported."
msgstr ""
"Não é possível criar a captura instantânea da máquina virtual '%(vm)s' "
"porque ela contém um disco com o formato '%(format)s'; somente 'qcow2' é "
"suportado."
msgid ""
"The number of vCPUs must be less than or equal the maximum number of vCPUs "
"specified."
msgstr ""
msgid ""
"When CPU topology is defined, maximum number of vCPUs must be a product of "
"sockets, cores, and threads."
msgstr ""
msgid "This host (or current configuration) does not allow CPU topology."
msgstr "Esse host (ou configuração atual) não permite topologia de CPU."
msgid "The maximum number of vCPUs is too large for this system."
msgstr ""
msgid ""
"When CPU topology is defined, CPUs must be a multiple of the 'threads' "
"number defined."
msgstr ""
msgid ""
"When CPU topology is specified, sockets, cores and threads are required "
"paramaters."
msgstr ""
msgid ""
"Parameter 'cpu_info' expects an object with fields among: 'vcpus', "
"'maxvcpus', 'topology'."
msgstr ""
msgid ""
"Parameter 'topology' expects an object with fields among: 'sockets', "
"'cores', 'threads'."
msgstr ""
msgid "Unable to update Max CPU or CPU topology when guest is running."
msgstr ""
#, python-format
msgid "Unable to hot plug/unplug CPUs. Details: %(err)s"
msgstr ""
#, python-format
msgid "Invalid volume group name parameter: %(name)s."
msgstr ""
msgid ""
"Unable to establish connection with libvirt. Please check your libvirt URI "
"which is often defined in /etc/libvirt/libvirt.conf"
msgstr ""
msgid ""
"Libvirt service is not active. Please start the libvirt service in your host "
"system."
msgstr ""
msgid "Failed to register the default event implementation."
msgstr ""
msgid "Failed to register timeout event."
msgstr ""
msgid "Failed to Run the default event implementation."
msgstr ""
#, python-format
msgid ""
"I/O error on guest '%(vm)s': storage pool out of space for %(devAlias)s "
"(%(srcPath)s)."
msgstr ""
#, python-format
msgid "Create virtual network '%(name)s' type '%(connection)s'"
msgstr ""
#, python-format
msgid "Remove virtual network '%(ident)s'"
msgstr ""
#, python-format
msgid "Update virtual network '%(ident)s'"
msgstr ""
#, python-format
msgid "Activate virtual network '%(ident)s'"
msgstr ""
#, python-format
msgid "Deactivate virtual network '%(ident)s'"
msgstr ""
#, python-format
msgid "Create storage pool '%(name)s' type '%(type)s'"
msgstr ""
#, python-format
msgid "Remove storage pool '%(ident)s'"
msgstr ""
#, python-format
msgid "Update storage pool '%(ident)s'"
msgstr ""
#, python-format
msgid "Activate storage pool '%(ident)s'"
msgstr ""
#, python-format
msgid "Deactivate storage pool '%(ident)s'"
msgstr ""
#, python-format
msgid "Create snapshot '%(name)s' at guest '%(vm)s'"
msgstr ""
#, python-format
msgid "Remove snapshot '%(ident)s' from guest '%(vm)s'"
msgstr ""
#, python-format
msgid "Revert guest '%(vm)s' to snapshot '%(ident)s'"
msgstr ""
#, python-format
msgid "Create template '%(name)s'"
msgstr ""
#, python-format
msgid "Remove template '%(ident)s'"
msgstr ""
#, python-format
msgid "Update template '%(ident)s'"
msgstr ""
#, python-format
msgid "Clone template '%(ident)s'"
msgstr ""
#, python-format
msgid "Create guest '%(name)s' from template '%(template)s'"
msgstr ""
#, python-format
msgid "Remove guest '%(ident)s'"
msgstr ""
#, python-format
msgid "Edit guest '%(ident)s'"
msgstr ""
#, python-format
msgid "Start guest '%(ident)s'"
msgstr ""
#, python-format
msgid "Power off guest '%(ident)s'"
msgstr ""
#, python-format
msgid "Shutdown guest '%(ident)s'"
msgstr ""
#, python-format
msgid "Restart guest '%(ident)s'"
msgstr ""
#, python-format
msgid "Connect to guest '%(ident)s' through novnc/spice"
msgstr ""
#, python-format
msgid "Clone guest '%(ident)s'"
msgstr ""
#, python-format
msgid "Migrate guest '%(ident)s' to '%(remote_host)s'"
msgstr ""
#, python-format
msgid "Suspend guest '%(ident)s'"
msgstr ""
#, python-format
msgid "Resume guest '%(ident)s'"
msgstr ""
#, python-format
msgid "Connect to guest '%(ident)s' through serial"
msgstr ""
#, python-format
msgid "Attach host device '%(name)s' to guest '%(vmid)s'"
msgstr ""
#, python-format
msgid "Detach host device '%(ident)s' from guest '%(vmid)s'"
msgstr ""
#, python-format
msgid "Attach network interface '%(network)s' to guest '%(vm)s'"
msgstr ""
#, python-format
msgid "Detach network interface '%(ident)s' from guest '%(vm)s'"
msgstr ""
#, python-format
msgid "Update network interface '%(ident)s' at guest '%(vm)s'"
msgstr ""
#, python-format
msgid "Attach %(type)s storage '%(path)s' to guest '%(vm)s'"
msgstr ""
#, python-format
msgid "Remove storage '%(ident)s' from guest '%(vm)s'"
msgstr ""
#, python-format
msgid "Update storage '%(ident)s' at guest '%(vm)s'"
msgstr ""
#, python-format
msgid "Create storage volume '%(name)s' at pool '%(pool)s'"
msgstr ""
#, python-format
msgid "Remove storage volume '%(ident)s' from pool '%(pool)s'"
msgstr ""
#, python-format
msgid "Update storage volume '%(ident)s' at pool '%(pool)s'"
msgstr ""
#, python-format
msgid "Wipe storage volume '%(ident)s' off pool '%(pool)s'"
msgstr ""
#, python-format
msgid "Resize storage volume '%(ident)s' at pool '%(pool)s' with size %(size)s"
msgstr ""
#, python-format
msgid "Clone storage volume '%(ident)s' at pool '%(pool)s'"
msgstr ""
msgid "Create a New Virtual Machine"
msgstr "Criar uma nova máquina virtual"
msgid "Virtual Machine Name"
msgstr "Nome da máquina virtual"
msgid ""
"The name used to identify the virtual machine. If omitted, a name will be "
"chosen based on the template used."
msgstr ""
"O nome usado para identificar a máquina virtual. Se omitido, um nome será "
"escolhido com base no modelo usado."
msgid "Please create a template first."
msgstr "Crie um modelo primeiro."
msgid "Create a Template"
msgstr "Criar um modelo"
msgid "Please choose a template."
msgstr "Escolha um modelo."
msgid "This template has invalid parameters."
msgstr ""
msgid "This template has invalid parameters"
msgstr ""
msgid "OS"
msgstr "S.O."
msgid "Version"
msgstr "Versão"
msgid "Current CPUs"
msgstr ""
msgid "Memory"
msgstr "Memória"
msgid "Create"
msgstr "Criar"
msgid "Creating..."
msgstr "Criando..."
msgid "Cancel"
msgstr "Cancelar"
msgid "Clone a Guest"
msgstr ""
msgid ""
"When the target guest has SCSI or iSCSI volumes, they will be cloned on the "
"default storage pool. The same will happen when the target pool does not "
"have enough space to clone the volumes. Do you want to continue?"
msgstr ""
msgid "Number of times to clone"
msgstr ""
msgid "Continue"
msgstr ""
msgid "Edit Guest"
msgstr "Editar máquina guest"
msgid "General"
msgstr "Geral"
msgid "Storage"
msgstr "Armazenamento"
msgid "Interface"
msgstr "Interface"
msgid "Permission"
msgstr ""
msgid "Pci"
msgstr ""
msgid "Snapshot"
msgstr ""
msgid "Processor"
msgstr "Processador"
msgid "Name"
msgstr "Nome"
msgid "Memory (MB)"
msgstr "Memória (megabyte)"
msgid "More"
msgstr ""
msgid "Max Memory (MB)"
msgstr ""
msgid "Host does not support memory hotplug"
msgstr ""
msgid "Icon"
msgstr "Ícone"
msgid "Console"
msgstr ""
msgid "Nothing selected"
msgstr ""
msgid "sclp"
msgstr ""
msgid "virtio"
msgstr ""
msgid ""
"Select which items for boot order and grad them when needed to order them. "
"At least one option must be selected."
msgstr ""
msgid "Add"
msgstr "Incluir"
msgid "Device"
msgstr "Dispositivo"
msgid "Path"
msgstr "Caminho"
msgid "Actions"
msgstr "Ações"
msgid "Network"
msgstr "Rede"
msgid "Type"
msgstr "Tipo"
msgid "MAC Address"
msgstr "Endereço MAC"
msgid "IP Address"
msgstr ""
msgid "Network/Interface"
msgstr ""
msgid "Mode"
msgstr ""
msgid "Available system users and groups"
msgstr "Usuários e grupos do sistema disponível"
msgid "Users"
msgstr "Usuários"
msgid "Groups"
msgstr "Grupos"
msgid "Selected system users and groups"
msgstr "Usuários e grupos do sistema selecionado"
msgid "User"
msgstr "Usuário"
msgid "All"
msgstr "Todos"
msgid "To Add"
msgstr "Para Incluir"
msgid "Added"
msgstr "Incluído(a)"
msgid "Filter"
msgstr ""
msgid "Status"
msgstr ""
msgid "Product"
msgstr "Produto"
msgid "Vendor"
msgstr "Fornecedor"
msgid "Loading"
msgstr ""
msgid "Created"
msgstr "Criado"
msgid "Current CPU Number"
msgstr ""
msgid ""
"Current CPU must be equal or lower than the Maximum CPU value. If a topology "
"is set, it must be also be a multiple of the 'threads' value."
msgstr ""
msgid "Max CPU"
msgstr ""
msgid ""
"Unable to edit maximum CPU or CPU topology when editing a running or paused "
"virtual machine."
msgstr ""
msgid ""
"If a topology is set, this value will be the product of sockets * times * "
"cores."
msgstr ""
msgid "Manually set CPU topology"
msgstr "Configurar manualmente a topologia da CPU"
msgid "Sockets"
msgstr ""
msgid "Cores"
msgstr "Núcleos"
msgid "Threads"
msgstr "Encadeamentos"
msgid "Save"
msgstr "Salvar"
msgid "Replace"
msgstr "Substituir"
msgid "Detach"
msgstr "Desanexar"
msgid "Remove"
msgstr "Remover"
msgid "Edit"
msgstr "Editar"
msgid "LDAP User ID,e.g.foo@foo.com"
msgstr "ID do usuário LDAP, por ex., foo@foo.com"
msgid "Revert"
msgstr ""
msgid "Running"
msgstr ""
msgid "Disconnected"
msgstr ""
msgid "Starting"
msgstr ""
msgid "Crashed"
msgstr ""
msgid "Unknown"
msgstr ""
msgid "Paused"
msgstr ""
msgid "Suspended"
msgstr ""
msgid "Resetting"
msgstr ""
msgid "View Console"
msgstr ""
msgid "View Serial"
msgstr ""
msgid "Clone"
msgstr "Clonar"
msgid "Migrate"
msgstr ""
msgid "Reset"
msgstr "Reiniciar"
msgid "Pause"
msgstr "Pausar"
msgid "Resume"
msgstr "Continuar"
msgid "Shut Down"
msgstr "Encerrar"
msgid "Start"
msgstr "Iniciar"
msgid "Power Off"
msgstr "Desligar"
msgid "Delete"
msgstr "Excluir"
msgid "No Data Available"
msgstr ""
msgid "Processors Utilization"
msgstr ""
msgid "Memory Utilization"
msgstr ""
msgid "Storage I/O"
msgstr "E/S de disco"
msgid "Network I/O"
msgstr "E/S de Rede"
msgid "Migrate a Guest"
msgstr ""
msgid ""
"Disclaimer: This process cannot be stopped after started, can take a long "
"time to complete and will turn off the VM on this Hypervisor when it is "
"successfully migrated to the remote destination."
msgstr ""
msgid "Remote Server"
msgstr ""
msgid "IP Address or Hostname"
msgstr ""
msgid ""
"The following fields are optional. Fill them if you want Kimchi to setup a "
"password-less ssh session between the localhost and the remote host. The "
"setup process will only be successful if the user has 'SUDO ALL' permission "
"in the remote machine."
msgstr ""
msgid "Username of the remote host"
msgstr ""
msgid "Password"
msgstr "Senha"
msgid "Password of the user in the remote host"
msgstr ""
msgid "Use RDMA transport"
msgstr ""
msgid ""
"Check this option only if RDMA is properly configured in both source and "
"destination hosts, otherwise migration will fail."
msgstr ""
msgid "Delete this VM when the migration is completed"
msgstr ""
msgid "Add a Storage Device to VM"
msgstr "Incluir um Dispositivo de Armazenamento na VM"
msgid "Device Type"
msgstr "Tipo de Dispositivo"
msgid ""
"The device type. Currently, \"cdrom\" and \"disk\" are supported. If the "
"guest is running, only \"disk\" is supported."
msgstr ""
msgid "Create a new disk"
msgstr ""
msgid "Select an existing disk"
msgstr ""
msgid "Source"
msgstr ""
msgid "Storage based on Libvirt pool or direct block device"
msgstr ""
msgid "Storage Pool"
msgstr "Banco de Armazenamento"
msgid "Storage pool to create the volume in"
msgstr ""
msgid "Disk Size (GB)"
msgstr ""
msgid "New disk size to be created"
msgstr ""
msgid "Format"
msgstr ""
msgid "Format of the new disk to be created"
msgstr ""
msgid "Directory Path"
msgstr ""
msgid "Provide a directory path"
msgstr ""
msgid "Storage pool in which the volume is located in"
msgstr ""
msgid "Storage Volume"
msgstr "Volume de Armazenamento"
msgid "Storage volume to be attached"
msgstr "Volume de armazenamento a ser conectado"
msgid "Disk Path"
msgstr ""
msgid "Provide a block device"
msgstr ""
msgid "File Path"
msgstr "Caminho do arquivo"
msgid "The ISO file path in the server for CDROM."
msgstr "O caminho do arquivo ISO no servidor para o CDROM."
msgid "Attach"
msgstr "Anexar"
msgid "Host"
msgstr "Host"
msgid "Guests"
msgstr "Máquinas Guests"
msgid "Templates"
msgstr "Modelos"
msgid "This is not a valid Linux path"
msgstr "Este não é um caminho do Linux válido"
msgid "Unable to read file."
msgstr "Não é possível ler o arquivo."
msgid "Error while uploading file."
msgstr "Erro ao fazer upload do arquivo."
msgid "Delete Confirmation"
msgstr "Confirmação de exclusão"
msgid "OK"
msgstr "OK"
msgid "Confirm"
msgstr "Confirmar"
msgid "Warning"
msgstr "Aviso"
msgid "Cloning..."
msgstr "Clonando..."
msgid "Saving..."
msgstr ""
msgid "Migrating..."
msgstr ""
msgid "No ISO found"
msgstr "Nenhum ISO localizado"
msgid "Add Template"
msgstr "Incluir Modelo"
msgid "This may take a long time. Do you want to continue?"
msgstr "Isso pode demorar. Deseja continuar?"
msgid ""
"This will permanently delete the %1 template. Would you like to continue?"
msgstr ""
msgid "View Table"
msgstr ""
msgid "View Gallery"
msgstr ""
msgid "Not Available"
msgstr ""
msgid "Please check the invalid Storage Pools"
msgstr ""
msgid "Please check the invalid Storage Pools or Paths"
msgstr ""
msgid "macvtap"
msgstr ""
msgid "ovs"
msgstr ""
msgid "network"
msgstr ""
msgid ""
"This will delete the %1 virtual machine and its virtual disks. This "
"operation cannot be undone. Would you like to continue?"
msgstr ""
msgid "Power off Confirmation"
msgstr "Confirmação de Desligamento"
msgid ""
"This action may produce undesirable results, for example unflushed disk "
"cache in the %1 guest. Would you like to continue?"
msgstr ""
msgid "Reset Confirmation"
msgstr "Confirmação de Reconfiguração"
msgid ""
"There is a risk of data loss caused by reset without the %1 guest OS "
"shutdown. Would you like to continue?"
msgstr ""
msgid "Shut Down Confirmation"
msgstr "Confirmação de Encerramento"
msgid ""
"Note the %1 guest OS may ignore this request. Would you like to continue?"
msgstr ""
msgid "Virtual Machine delete Confirmation"
msgstr "Confirmação de exclusão de máquina virtual"
msgid ""
"The %1 virtual machine is not persistent. Power Off will delete it. Continue?"
msgstr ""
msgid "Add Guest"
msgstr ""
msgid "Input is not a number"
msgstr ""
msgid "Memory value cannot be higher than Max Memory value"
msgstr ""
msgid ""
"For better performance it is recommended a threads per core value not "
"greater than %1."
msgstr ""
msgid ""
"This CDROM will be detached permanently and you can re-attach it. Continue "
"to detach it?"
msgstr ""
"Este CD-ROM será removido permanentemente e é possível reconectá-lo. "
"Continuar a removê-lo?"
msgid "Attaching..."
msgstr "Conectando..."
msgid ""
"This disk will be detached permanently and you can re-attach it. Continue to "
"detach it?"
msgstr ""
"Este disco será removido permanentemente e é possível reconectá-lo. "
"Continuar a remoção?"
msgid "interface:"
msgstr "interface:"
msgid "address:"
msgstr "endereço:"
msgid "link_type:"
msgstr "link_type:"
msgid "block:"
msgstr "bloco:"
msgid "drive_type:"
msgstr "drive_type:"
msgid "model:"
msgstr "modelo:"
msgid "Affected devices:"
msgstr "Dispositivos afetados:"
msgid "Less"
msgstr ""
msgid "Successfully attached device to VM"
msgstr ""
msgid "Successfully detached device from VM"
msgstr ""
msgid "Following devices will be affected, confirm?"
msgstr ""
msgid "Bridge"
msgstr ""
msgid "Vepa"
msgstr ""
msgid "None"
msgstr ""
msgid "unavailable"
msgstr "indisponível"
msgid ""
"This action will interrupt network connectivity for any virtual machine that "
"depend on the %1 network."
msgstr ""
msgid "Add Network"
msgstr ""
msgid ""
"The %1 network is not persistent. Instead of stop, this action will "
"permanently delete it. Would you like to continue?"
msgstr ""
msgid ""
"The bridged VLAN tag may not work well with NetworkManager enabled. You "
"should consider disabling it."
msgstr ""
"A identificação de VLAN em ponte pode não funcionar bem com o NetworkManager "
"ativado. Você deve considerar desativá-lo."
msgid ""
"This will permanently delete the %1 storage pool. Would you like to continue?"
msgstr ""
msgid "This storage pool is empty."
msgstr "Este banco de armazenamento está vazio."
msgid ""
"It will format your disk and you will loose any data in there, are you sure "
"to continue? "
msgstr ""
"Isso formatará seu disco e você perderá quaisquer dados contidos nele, tem "
"certeza de que deseja continuar? "
msgid "SCSI Fibre Channel"
msgstr "Fibre Channel SCSI"
msgid "No SCSI adapters found."
msgstr "Nenhum adaptador SCSI localizado."
msgid "Loading iSCSI targets..."
msgstr "Carregando destinos iSCSI..."
msgid "No iSCSI found. Please input one."
msgstr "Nenhum iSCSI localizado. Insira um."
msgid "Failed to load iSCSI targets."
msgstr "Falha ao carregar destinos iSCSI."
msgid "Would you like to continue?"
msgstr ""
msgid "This will permanently delete the following storage volumes: %1"
msgstr ""
msgid "No available partitions found."
msgstr "Nenhuma partição disponível localizada."
msgid ""
"The %1 storage pool is not persistent. Instead of deactivate, this action "
"will permanently delete it. Would you like to continue?"
msgstr ""
msgid "Unable to retrieve partitions information."
msgstr "Não é possível recuperar as informações da partição."
msgid "In progress..."
msgstr "Em andamento..."
msgid "Failed!"
msgstr "Falhou!"
msgid "No LVM found in the system."
msgstr ""
msgid "This will permanently wipe the following storage volumes: %1"
msgstr ""
msgid "Wipe Confirmation"
msgstr ""
msgid "Select one or more partitions to be added to the logical pool %1:"
msgstr ""
msgid "Add Storage"
msgstr "Incluir Armazenamento"
msgid "DIR"
msgstr ""
msgid "NFS"
msgstr ""
msgid "iSCSI"
msgstr ""
msgid "LOGICAL"
msgstr ""
msgid "device"
msgstr ""
msgid "path"
msgstr ""
msgid "size (GiB)"
msgstr ""
msgid "free size (GiB)"
msgstr ""
msgid "Invalid NFS mount path."
msgstr "Caminho de montagem do NFS inválido."
msgid "No logical device selected."
msgstr "Nenhum dispositivo lógico selecionado."
msgid "This is not a valid Server Name or IP. Please, modify it."
msgstr "Este não é um Nome de Servidor ou IP válido. Modifique-o."
msgid "CDROM path needs to be a valid local/remote path and cannot be blank."
msgstr ""
"O caminho CDROM precisa ser um caminho local/remote válido e não pode estar "
"em branco."
msgid "Disk pool or volume cannot be blank."
msgstr "O volume ou banco de discos não pode estar em branco."
msgid ""
"Disk size or Format or Directory path cannot be blank and Directory path "
"needs to be a valid local/remote path."
msgstr ""
msgid "Disk path needs to be a valid local/remote path and cannot be blank."
msgstr ""
msgid "Storage pool or Disk size or Format cannot be blank."
msgstr ""
msgid "cdrom"
msgstr ""
msgid "disk"
msgstr ""
msgid "Pool"
msgstr ""
msgid "qcow"
msgstr ""
msgid "qcow2"
msgstr ""
msgid "qed"
msgstr ""
msgid "raw"
msgstr ""
msgid "vmdk"
msgstr ""
msgid "vpc"
msgstr ""
msgid "Create a network"
msgstr "Criar uma rede"
msgid "Network Name"
msgstr "Nome da rede"
msgid "Name should not contain '/' and '\"'."
msgstr "O nome não deve conter '/' e '\"'."
msgid "Network Type"
msgstr "Tipo de rede"
msgid "Isolated: no external network connection"
msgstr "Isolado: nenhuma conexão de rede externa"
msgid "NAT: outbound physical network connection only"
msgstr "NAT: somente conexão de rede física de saída"
msgid "Macvtap: Virtual machines are connected to physical network directly"
msgstr ""
msgid ""
"Passthrough: Virtual machines are connected using a macvtap connection in "
"passthrough mode."
msgstr ""
msgid ""
"VEPA: special mode where virtual machines are connected to a VEPA-enabled "
"switch"
msgstr ""
msgid "Bridged: Virtual machines are connected through a network bridge"
msgstr ""
msgid "Destination"
msgstr "Destino"
msgid "Select an Interface"
msgstr ""
msgid "Enable VLAN"
msgstr "Ativar VLAN"
msgid "VLAN ID"
msgstr "ID de VLAN"
msgid "Edit Network"
msgstr ""
msgid "Address Space"
msgstr ""
msgid "Define a New Storage Pool"
msgstr "Definir um novo banco de armazenamento"
msgid "Storage Pool Name"
msgstr "Nome do banco de armazenamento"
msgid ""
"The name used to identify the storage pools, and it should not be empty."
msgstr ""
"O nome usado para identificar os bancos de armazenamento e não deve ser "
"vazio."
msgid "Storage Pool Type"
msgstr "Tipo do banco de armazenamento"
msgid "Storage Path"
msgstr "Caminho do armazenamento"
msgid ""
"The path of the Storage Pool. Each Storage Pool must have a unique path."
msgstr ""
"O caminho do banco de armazenamento. Cada banco de armazenamento deve ter um "
"caminho exclusivo."
msgid ""
"Kimchi will try to create the directory when it does not already exist in "
"your system."
msgstr ""
"Kimchi tentará criar o diretório quando ele não existir em seu sistema."
msgid "NFS Server IP"
msgstr "IP do servidor NFS"
msgid "NFS server IP or hostname. It can be input or chosen from history."
msgstr ""
"IP ou nome do servidor NFS. Ele pode ser inserido ou escolhido a partir do "
"histórico."
msgid "NFS Path"
msgstr "Caminho de NFS"
msgid "The NFS exported path on NFS server."
msgstr "O caminho exportado de NFS no servidor NFS."
msgid "Create from existing LVM"
msgstr ""
msgid "Create from raw disk"
msgstr ""
msgid "Looking for existing lvms ..."
msgstr ""
msgid "Looking for available partitions ..."
msgstr "Procurando partições disponíveis..."
msgid "iSCSI Server"
msgstr "Servidor iSCSI"
msgid "Server"
msgstr "Servidor"
msgid "Port"
msgstr "Porta"
msgid "iSCSI server IP or hostname. It should not be empty."
msgstr "IP ou nome do servidor iSCSI. Ele não deve ser vazio."
msgid "Target"
msgstr "Destino"
msgid "The iSCSI target on iSCSI server"
msgstr "O destino iSCSI no servidor iSCSI"
msgid "Add iSCSI Authentication"
msgstr "Incluir autenticação de iSCSI"
msgid "User Name"
msgstr "Nome de usuário"
msgid "SCSI Adapter"
msgstr "Adaptador SCSI"
msgid "Please, wait..."
msgstr "Aguarde..."
msgid "Add a Volume to Storage Pool"
msgstr "Incluir um volume no banco de armazenamento"
msgid "Fetch from remote URL"
msgstr "Buscar a partir da URL remota"
msgid "Enter the remote URL here."
msgstr "Inserir a URL remota aqui."
msgid "Upload a file"
msgstr "Fazer upload de um arquivo"
msgid "Choose the file you want to upload."
msgstr "Escolher o arquivo do qual você deseja fazer upload."
msgid "Resize Volume"
msgstr ""
msgid "Size"
msgstr "Tamanho"
msgid "The total space which can be used to store data. The unit is megabytes."
msgstr ""
msgid "Ok"
msgstr ""
msgid "Template Name"
msgstr ""
msgid ""
"The name used to identify the template. If omitted, a name will be "
"automatically chosen."
msgstr ""
msgid ""
"When selecting more than one Image Template, a name will be automatically "
"chosen for each Image Template selected."
msgstr ""
msgid "Where is the source media for this template? "
msgstr ""
msgid "Image Template"
msgstr ""
msgid "Netboot Template"
msgstr ""
msgid "File Path:"
msgstr "Caminho do arquivo: "
msgid "Search ISOs"
msgstr "Procurar ISOs"
msgid "The following ISOs are available:"
msgstr "Os ISOs a seguir estão disponíveis:"
msgid "QEMU does not have enough permission to work with this file"
msgstr ""
msgid "Search more ISOs"
msgstr "Procurar mais ISOs"
msgid "Loading..."
msgstr ""
msgid "Edit Template"
msgstr "Editar modelo"
msgid "CDROM"
msgstr "CD-ROM"
msgid "Image File"
msgstr "Arquivo de imagem"
msgid "Graphics"
msgstr "Gráficos"
msgid "Disk(GB)"
msgstr "Disco (GB)"
msgid "Disk Format"
msgstr "Formato do disco"
msgid "Add Interface"
msgstr "Incluir Interface"
msgid "pool"
msgstr ""
msgid "bridge"
msgstr ""
msgid "vepa"
msgstr ""
msgid "State"
msgstr ""
msgid "Guest Name ID"
msgstr ""
msgid "OS Type"
msgstr ""
msgid "VNC"
msgstr ""
msgid "No guests found."
msgstr ""
msgid "Stop"
msgstr ""
msgid "Location"
msgstr ""
msgid "%Used"
msgstr ""
msgid "Allocated"
msgstr ""
msgid "Capacity"
msgstr ""
msgid "Disks"
msgstr ""
msgid "Extending logical pool"
msgstr ""
msgid "%"
msgstr ""
msgid "Deactivate"
msgstr ""
msgid "Activate"
msgstr ""
msgid "Extend"
msgstr ""
msgid "Undefine"
msgstr ""
msgid "Add Volume"
msgstr ""
msgid "Resize"
msgstr ""
msgid "Wipe"
msgstr ""
msgid "Filter:"
msgstr ""
msgid "Used By"
msgstr ""
msgid "Used"
msgstr ""
msgid "Progress"
msgstr ""
msgid "Used by the following VMs:"
msgstr ""
msgid "Allocation"
msgstr ""
msgid "Template Name (ID)"
msgstr ""
msgid "No templates found."
msgstr ""
msgid "M"
msgstr ""
================================================
FILE: po/ru_RU.po
================================================
# Russian translations for kimchi package.
# Copyright IBM Corp, 2014-2017
# Adam Litke , 2013.
#
msgid ""
msgstr ""
"Project-Id-Version: kimchi 0.1\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2017-06-30 10:27-0300\n"
"PO-Revision-Date: 2013-07-11 17:32-0400\n"
"Last-Translator: Crístian Viana \n"
"Language-Team: English\n"
"Language: ru_RU\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: pygettext.py 1.5\n"
"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n"
"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
#, python-format
msgid "Unknown parameter %(value)s"
msgstr "Неизвестный параметр %(value)s"
#, python-format
msgid "User %(user_id)s not found with given LDAP settings."
msgstr "Пользователь %(user_id)s не найден с указанными параметрами LDAP."
#, python-format
msgid "Partition %(name)s does not exist in the host"
msgstr "Раздел %(name)s не существует на хосте"
msgid "Error while accessing dev mapper device, %(err)s"
msgstr ""
msgid "Block device not found."
msgstr ""
msgid "Block device %(device)s not found."
msgstr ""
msgid "Unable to retrieve LVM information. Details: %(err)s"
msgstr ""
msgid "Unknown \"_cap\" specified"
msgstr "Указано неизвестное значение \"_cap\""
msgid "\"_passthrough\" should be \"true\" or \"false\""
msgstr "Значение \"_passthrough\" должно быть \"true\" или \"false\""
msgid "\"_passthrough_affected_by\" should be a device name string"
msgstr ""
"Значение \"_passthrough_affected_by\" должно быть строкой с именем устройства"
msgid "\"_available_only\" should be \"true\" or \"false\""
msgstr "Допустимые значения для \"_available_only\": \"true\" или \"false\""
#, python-format
msgid "Unable to find distro file: %(filename)s"
msgstr "Не найден файл варианта ОС: %(filename)s"
#, python-format
msgid ""
"Unable to parse distro file: %(filename)s. Make sure, it is a JSON file."
msgstr ""
"Ошибка анализа файла варианта ОС: %(filename)s. Убедитесь, что это файл JSON."
#, python-format
msgid "Unable to login to iSCSI host target %(portal)s. Details: %(err)s"
msgstr "Не удалось войти в целевой %(portal)s хоста iSCSI. Сведения: %(err)s"
#, python-format
msgid "Unable to login to iSCSI host %(host)s target %(target)s"
msgstr "Не удалось войти в целевой %(target)s хоста %(host)s iSCSI"
#, python-format
msgid "Unable to find ISO file %(filename)s"
msgstr "Не найден файл ISO %(filename)s"
#, python-format
msgid "The ISO file %(filename)s is not bootable"
msgstr "Файл ISO %(filename)s не загрузочный"
#, python-format
msgid "The ISO file %(filename)s does not have a valid El Torito boot record"
msgstr ""
"Файл ISO %(filename)s не содержит правильную загрузочную запись El Torito"
#, python-format
msgid "Invalid El Torito validation entry in ISO %(filename)s"
msgstr "Недопустимая запись проверки El Torito в образе ISO %(filename)s"
#, python-format
msgid "Invalid El Torito boot indicator in ISO %(filename)s"
msgstr "Недопустимый индикатор загрузки El Torito в образе ISO %(filename)s"
#, python-format
msgid "Unexpected volume type for primary volume in ISO %(filename)s"
msgstr "Неожиданный тип главного тома в образе ISO %(filename)s"
#, python-format
msgid "Bad format while reading volume descriptor in ISO %(filename)s"
msgstr "Неверный формат дескриптора тома в образе ISO %(filename)s"
#, python-format
msgid ""
"The hypervisor doesn't have permission to use this ISO %(filename)s. "
"Consider moving it under /var/lib/libvirt, or set the search permission to "
"file access control lists for '%(user)s' user if possible, or add the "
"'%(user)s' to the ISO path group, or (not recommended) 'chmod -R o+x "
"'path_to_iso'.Details: %(err)s"
msgstr ""
"У гипервизора нет прав доступа для использования этого образа ISO "
"%(filename)s. Переместите его в каталог /var/lib/libvirt, добавьте "
"разрешение на поиск в списки контроля доступа для пользователя %(user)s, "
"если это возможно, добавьте %(user)s в группу пути к образу ISO или (не "
"рекомендуется) выполните команду 'chmod -R o+x путь-к-iso'. Сведения: %(err)s"
#, python-format
msgid "Unable to access remote ISO. Details: %(err)s"
msgstr ""
#, python-format
msgid "Error probing image OS information: %(err)s"
msgstr ""
#, python-format
msgid "Unable to read image file %(filename)s"
msgstr "Не удалось прочитать файл образа %(filename)s"
#, python-format
msgid ""
"Image file must be an existing file on system. %(filename)s is not a valid "
"input."
msgstr ""
"Файл образа должен быть существующим файлом в системе. %(filename)s не "
"является допустимым вводом."
#, python-format
msgid "Virtual machine %(name)s already exists"
msgstr "Виртуальная машина %(name)s уже существует"
#, python-format
msgid "Virtual machine %(name)s does not exist"
msgstr "Виртуальная машина %(name)s не существует"
#, python-format
msgid "Unable to retrieve screenshot for stopped virtual machine %(name)s"
msgstr ""
"Не удалось получить снимок экрана для остановленной виртуальной машины "
"%(name)s"
msgid "Remote ISO image is not supported by this server."
msgstr "Удаленный образ ISO не поддерживается этим сервером."
#, python-format
msgid "Screenshot is not supported on virtual machine %(name)s"
msgstr "Снимки экрана не поддерживаются в виртуальной машине %(name)s"
#, python-format
msgid "Unable to create virtual machine %(name)s. Details: %(err)s"
msgstr "Не удалось создать виртуальную машину %(name)s. Сведения: %(err)s"
#, python-format
msgid "Unable to update virtual machine %(name)s. Details: %(err)s"
msgstr "Не удалось обновить виртуальную машину %(name)s. Сведения: %(err)s"
#, python-format
msgid "Unable to retrieve virtual machine %(name)s. Details: %(err)s"
msgstr "Не удалось получить виртуальную машину %(name)s. Сведения: %(err)s"
#, python-format
msgid "Unable to connect to powered off virtual machine %(name)s."
msgstr "Не удалось подключиться к выключенной виртуальной машине %(name)s."
msgid "Virtual machine name must be a string without slashes (/)"
msgstr ""
"Имя виртуальной машины должно быть строкой без символов косой черты (/)"
#, python-format
msgid "Invalid template URI %(value)s specified for virtual machine"
msgstr "Для виртуальной машины указан недопустимый URI шаблона %(value)s"
#, python-format
msgid "Invalid storage pool URI %(value)s specified for virtual machine"
msgstr "Для виртуальной машины указан недопустимый URI пула памяти %(value)s"
msgid "Supported virtual machine graphics are Spice or VNC"
msgstr "Поддерживаемые графические подсистемы виртуальной машины: Spice, VNC"
msgid "Graphics address to listen on must be IPv4 or IPv6"
msgstr ""
"Адрес приема запросов для графической подсистемы должен быть IPv4 или IPv6"
msgid "Specify a template to create a virtual machine from"
msgstr "Укажите шаблон для создания виртуальной машины"
#, python-format
msgid "Unable to start virtual machine %(name)s. Details: %(err)s"
msgstr "Не удалось запустить виртуальную машину %(name)s. Сведения: %(err)s"
#, python-format
msgid "Unable to power off virtual machine %(name)s. Details: %(err)s"
msgstr "Не удалось выключить виртуальную машину %(name)s. Сведения: %(err)s"
#, python-format
msgid "Unable to delete virtual machine %(name)s. Details: %(err)s"
msgstr "Не удалось удалить виртуальную машину %(name)s. Сведения: %(err)s"
#, python-format
msgid "Unable to reset virtual machine %(name)s. Details: %(err)s"
msgstr "Не удалось сбросить виртуальную машину %(name)s. Сведения: %(err)s"
msgid "User name list must be an array"
msgstr "Список имен пользователей должен быть массивом"
msgid "User name must be a string"
msgstr "Имя пользователя должно быть строкой"
msgid "Group name list must be an array"
msgstr "Список имен групп должен быть массивом"
msgid "Group name must be a string"
msgstr "Имя группы должно быть строкой"
#, python-format
msgid "User(s) '%(users)s' do not exist"
msgstr "Следующие пользователи не существуют: %(users)s"
#, python-format
msgid "Group(s) '%(groups)s' do not exist"
msgstr "Следующие группы не существуют: %(groups)s"
#, python-format
msgid "Unable to shutdown virtual machine %(name)s. Details: %(err)s"
msgstr ""
"Не удалось завершить работу виртуальной машины %(name)s. Сведения: %(err)s"
msgid "The guest console password must be a string."
msgstr "Пароль консоли гостевой системы должен быть строкой."
msgid "The life time for the guest console password must be a number."
msgstr "Срок действия пароля консоли гостевой системы должен быть числом."
#, python-format
msgid "Virtual machine '%(name)s' must be stopped before cloning it."
msgstr ""
"Виртуальную машину '%(name)s' необходимо остановить перед созданием ее копии."
#, python-format
msgid "Insufficient disk space to clone virtual machine '%(name)s'"
msgstr ""
"Недостаточно дисковой памяти для дублирования виртуальной машины '%(name)s'"
#, python-format
msgid "Unable to clone VM '%(name)s'. Details: %(err)s"
msgstr ""
"Не удалось дублировать виртуальную машину '%(name)s'. Сведения: %(err)s"
#, python-format
msgid "Invalid operation for non-persistent virtual machine %(name)s"
msgstr "Недопустимая операция для непостоянной виртуальной машины %(name)s"
#, python-format
msgid "Cannot suspend VM '%(name)s' because it is not running."
msgstr ""
"Невозможно приостановить виртуальную машину '%(name)s', поскольку она не "
"работает."
#, python-format
msgid "Unable to suspend VM '%(name)s'. Details: %(err)s"
msgstr ""
"Не удалось приостановить виртуальную машину '%(name)s'. Сведения: %(err)s"
#, python-format
msgid "Cannot resume VM '%(name)s' because it is not paused."
msgstr ""
"Невозможно возобновить выполнение виртуальной машины '%(name)s', поскольку "
"она не приостановлена."
#, python-format
msgid "Unable to resume VM '%(name)s'. Details: %(err)s"
msgstr ""
"Не удалось возобновить выполнение виртуальной машины '%(name)s'. Сведения: "
"%(err)s"
#, python-format
msgid ""
"Memory assigned is higher then the maximum allowed in the host: "
"%(maxmem)sMib."
msgstr ""
#, python-format
msgid ""
"Guest '%(name)s' does not support live memory update. Please, with the guest "
"offline, set Maximum Memory with a value greater then Memory to enable this "
"feature."
msgstr ""
msgid "Only increase memory is allowed in active VMs"
msgstr "В активных виртуальных машинах объем памяти можно только увеличивать"
msgid "There are not enough free slots to add a new memory device."
msgstr ""
msgid ""
"Host's libvirt or qemu version does not support memory devices and memory "
"hotplug. Libvirt must be >= 1.2.14 and QEMU must be >= 2.1."
msgstr ""
#, python-format
msgid "Error attaching memory device. Details: %(error)s"
msgstr "Ошибка подключения устройства памяти. Сведения: %(error)s"
#, python-format
msgid "Cannot start %(name)s. Virtual machine is already running."
msgstr "Не удается запустить %(name)s. Виртуальная машина уже запущена."
#, python-format
msgid "Cannot power off %(name)s. Virtual machine is shut off."
msgstr "Не удалось отключить питание %(name)s. Виртуальная машина выключена."
#, python-format
msgid "Cannot shutdown %(name)s. Virtual machine is shut off."
msgstr "Не удается завершить работу %(name)s. Виртуальная машина выключена."
#, python-format
msgid "Cannot reset %(name)s. Virtual machine is already shut off."
msgstr "Не удается выполнить сброс %(name)s. Виртуальная машина уже выключена."
msgid "Boot order must be a list. Devices accepted: hd, cdrom, fd or network."
msgstr ""
msgid "Bootmenu must be boolean. Values accepted: true of false."
msgstr ""
msgid "Graphic type not valid. Values accepted: vnc or spice."
msgstr ""
#, python-format
msgid "Migrate to localhost %(host)s is not allowed."
msgstr ""
#, python-format
msgid ""
"To migrate a virtual machine to the remote host %(host)s the user %(user)s "
"must have password-less login to the remote host."
msgstr ""
#, python-format
msgid "Can not migrate virtual machine %(name)s when its in %(state)s state."
msgstr ""
#, python-format
msgid "Failed to migrate virtual machine %(name)s due error: %(err)s"
msgstr ""
msgid "User name of the remote server must be a string."
msgstr ""
msgid "Destination host of the migration must be a string."
msgstr ""
#, python-format
msgid "Unable to create file %(path)s at %(host)s using user %(user)s."
msgstr ""
#, python-format
msgid "Unable to read disk size of %(path)s, error: %(error)s"
msgstr ""
#, python-format
msgid ""
"Unable to create disk image %(path)s at %(host)s using user %(user)s. Error: "
"%(error)s"
msgstr ""
#, python-format
msgid ""
"Unable to migrate virtual machine to remote host %(host)s with arch "
"%(destarch)s using localhost with arch %(srcarch)s."
msgstr ""
#, python-format
msgid ""
"Unable to migrate virtual machine to remote host %(host)s with hypervisor "
"%(desthyp)s because localhost uses hypervisor %(srchyp)s."
msgstr ""
#, python-format
msgid ""
"Unable to determine remote host hypervisor and architecture. Error: %(error)s"
msgstr ""
#, python-format
msgid ""
"Unable to migrate virtual machine: subcores per core setting from "
"localhostand remote host %(host)s differs."
msgstr ""
#, python-format
msgid ""
"Unable to setup password-less login at remote host %(host)s using user "
"%(user)s. Error: %(error)s"
msgstr ""
msgid "Password field must be a string."
msgstr ""
msgid "Error creating local host ssh rsa key of user 'root'."
msgstr ""
#, python-format
msgid "%(param)s value (%(mem)sMiB) must be aligned to %(alignment)sMiB."
msgstr ""
#, python-format
msgid ""
"Unable to update the following parameters while the VM is offline: %(params)s"
msgstr ""
#, python-format
msgid ""
"Unable to update the following parameters while the VM is online: %(params)s"
msgstr ""
#, python-format
msgid ""
"VM %(name)s must have serial and console defined to open a web serial console"
msgstr ""
#, python-format
msgid "Impossible to get the serial console of %(name)s"
msgstr ""
#, python-format
msgid ""
"Memory or Maximum Memory value is higher than amount supported by the host: "
"%(memHost)sMiB."
msgstr ""
#, python-format
msgid ""
"Memory or Maximum Memory value is higher than maximum amount recommended: "
"%(value)sTiB"
msgstr ""
msgid "Cannot update Maximum Memory when guest is running."
msgstr ""
#, python-format
msgid "Impossible to create %(dir)s directory."
msgstr ""
#, python-format
msgid ""
"Either the guest %(name)s did not start to listen to the serial or it is not "
"configured to use the serial console."
msgstr ""
#, python-format
msgid ""
"Unable to retrieve Virt Viewer file for stopped virtual machine %(name)s"
msgstr ""
#, python-format
msgid ""
"Error occured while retrieving the Virt Viewer file for virtual machine "
"%(name)s : %(err)s"
msgstr ""
msgid "Virtual machine title must be a string"
msgstr ""
msgid "Virtual machine description must be a string"
msgstr ""
msgid "console parameter is only supported for s390x/s390 architecture."
msgstr ""
msgid "invalid console type, supported types are sclp/virtio."
msgstr ""
#, python-format
msgid ""
"Unable to setup password-less login at remote host %(host)s using user "
"%(user)s: remote directory %(sshdir)s does not exist."
msgstr ""
#, python-format
msgid ""
"Unable to create a password-less libvirt connection to the remote libvirt "
"daemon at host %(host)s with the user %(user)s. Please verify the remote "
"server libvirt configuration. More information: http://libvirt.org/auth."
"html ."
msgstr ""
msgid "'enable_rdma' must be of type boolean (true or false)."
msgstr ""
#, python-format
msgid ""
"VM %(vmid)s does not contain directly assigned host device %(dev_name)s."
msgstr ""
"Виртуальная машина %(vmid)s не содержит непосредственно присвоенного "
"устройства хоста %(dev_name)s."
#, python-format
msgid "The host device %(dev_name)s is not allowed to directly assign to VM."
msgstr ""
"Прямое присвоение виртуальной машине недопустимо для хоста %(dev_name)s."
msgid ""
"No IOMMU groups found. Host PCI pass through needs IOMMU group to function "
"correctly. Please enable Intel VT-d or AMD IOMMU in your BIOS, then verify "
"the Kernel is compiled with IOMMU support. For Intel CPU, add "
"'intel_iommu=on' to GRUB_CMDLINE_LINUX parameter in /etc/default/grub file. "
"For AMD CPU, add 'iommu=pt iommu=1'."
msgstr ""
msgid "\"name\" should be a device name string"
msgstr "Значение \"name\" должно быть строкой с именем устройства"
#, python-format
msgid ""
"The device %(name)s is probably in use by the host. Unable to attach it to "
"the guest."
msgstr ""
"Возможно, устройство %(name)s используется хостом. Его невозможно подключить "
"к гостевой системе."
#, python-format
msgid "Hot-(un)plug of device %(name)s is not supported."
msgstr ""
#, python-format
msgid "Failed to attach %(device)s to %(vm)s"
msgstr ""
#, python-format
msgid "VM %(vmid)s does not have a USB controller to accept PCI hotplug."
msgstr ""
#, python-format
msgid "Interface %(iface)s does not exist in virtual machine %(name)s"
msgstr "Интерфейс %(iface)s не существует в виртуальной машине %(name)s"
#, python-format
msgid ""
"Network %(network)s specified for virtual machine %(name)s does not exist"
msgstr ""
"Сеть %(network)s, указанная для виртуальной машины %(name)s, не существует"
msgid ""
"Supported virtual machine interfaces type are network, ovs and macvtap.Type "
"ovs and macvtap are only supported for s390x/s390 architecture."
msgstr ""
msgid "Network name for virtual machine interface must be a string"
msgstr "Имя сети для интерфейса виртуальной машины должно быть строкой"
msgid "Invalid network model card specified for virtual machine interface"
msgstr ""
"Указана недопустимая карта модели сети для интерфейса виртуальной машины"
msgid "Specify type and network to add a new virtual machine interface"
msgstr "Укажите тип и сеть для добавления нового интерфейса виртуальной машины"
msgid "MAC Address must respect this format FF:FF:FF:FF:FF:FF"
msgstr "MAC-адрес должен иметь формат FF:FF:FF:FF:FF:FF"
#, python-format
msgid "MAC Address %(mac)s already exists in virtual machine %(name)s"
msgstr "MAC-адрес %(mac)s уже существует в виртуальной машине %(name)s"
msgid "Invalid MAC Address"
msgstr "Недопустимый MAC-адрес"
msgid "Cannot change MAC address of a running virtual machine"
msgstr "Нельзя изменить MAC-адрес работающей виртуальной машины"
msgid "Type macvtap and ovs are only supported on s390x/s390 architecture."
msgstr ""
msgid "Source attribute is only supported on s390x/s390 architecture."
msgstr ""
msgid "If source is provided, only type supported are macvtap and ovs."
msgstr ""
msgid "For type macvtap and ovs, source has to be provided"
msgstr ""
msgid "Source name for virtual machine interface must be string"
msgstr ""
msgid "Invalid source mode. Valid options are: bridge or vepa."
msgstr ""
#, python-format
msgid "Template %(name)s already exists"
msgstr "Шаблон %(name)s уже существует"
#, python-format
msgid "Source media %(path)s not found"
msgstr ""
#, python-format
msgid ""
"Network '%(network)s' specified for template %(template)s does not exist"
msgstr "Сеть '%(network)s', указанная для шаблона %(template)s, не существует"
#, python-format
msgid ""
"Storage pool %(pool)s specified for template %(template)s does not exist"
msgstr "Пул памяти %(pool)s, указанный для шаблона %(template)s, не существует"
#, python-format
msgid "Invalid parameter '%(param)s' specified for CDROM."
msgstr "Указан недопустимый параметр %(param)s для CDROM."
#, python-format
msgid "Network %(network)s specified for template %(template)s is not active"
msgstr "Сеть %(network)s, указанная для шаблона %(template)s, неактивна"
msgid "Template name must be a string"
msgstr "Имя шаблона должно быть строкой"
msgid "Template icon must be a path to the image"
msgstr "Значок шаблона должен быть путем к образу"
msgid "Template distribution must be a string"
msgstr "Вариант шаблона должен быть строкой"
msgid "Template distribution version must be a string"
msgstr "Версия варианта шаблона должна быть строкой"
msgid "The number of CPUs must be an integer greater than 0"
msgstr "Число процессоров должно быть целым числом, большим 0"
msgid ""
"Amount of memory and maximum memory (MB) must be an integer greater than 512"
msgstr ""
msgid "Template CDROM must be a local or remote ISO file"
msgstr "CDROM шаблона должен быть локальным или удаленным файлом ISO"
#, python-format
msgid "Invalid storage pool URI %(value)s specified for template"
msgstr "Для шаблона указан недопустимый URI пула памяти %(value)s"
msgid ""
"Specify a path to source media (ISO, disk or remote ISO) to create a template"
msgstr ""
msgid "All networks for the template must be specified in a list."
msgstr "Все сети для шаблона должны быть указаны в списке."
msgid "Specify a volume to a template when storage pool is iSCSI or SCSI"
msgstr "Укажите том для шаблона, когда пул памяти - iSCSI или SCSI"
#, python-format
msgid "The volume %(volume)s is not in storage pool %(pool)s"
msgstr "Том %(volume)s отсутствует в пуле памяти %(pool)s"
#, python-format
msgid "Unable to create template due error: %(err)s"
msgstr "Не удалось создать шаблон из-за следующей ошибки: %(err)s"
#, python-format
msgid "Unable to delete template due error: %(err)s"
msgstr "Не удалось удалить шаблон из-за следующей ошибки: %(err)s"
msgid "Disk size must be an integer greater than 1GB."
msgstr "Размер диска должен быть целым числом больше 1 ГБ."
#, python-format
msgid "Cannot identify base image %(path)s format"
msgstr "Не удалось идентифицировать формат %(path)s базового образа"
msgid ""
"When specifying CPU topology, each element must be an integer greater than "
"zero."
msgstr ""
"При указании топологии процессоров каждый элемент должен быть целым числом "
"больше нуля."
msgid ""
"Invalid disk image format. Valid formats: qcow, qcow2, qed, raw, vmdk, vpc."
msgstr ""
msgid ""
"When setting template disks, following parameters are required: 'index', "
"'pool name', 'format', 'size' or 'volume' (for scsi/iscsi pools)"
msgstr ""
msgid "Disk format must be 'raw', for logical, iscsi, and scsi pools."
msgstr ""
msgid ""
"Memory expects an object with one or both parameters: 'current' and "
"'maxmemory'"
msgstr ""
#, python-format
msgid ""
"Memory value (%(mem)sMiB) must be equal or lesser than maximum memory value "
"(%(maxmem)sMiB)"
msgstr ""
#, python-format
msgid "Unable to update template due error: %(err)s"
msgstr ""
msgid "Parameter 'disks' requires at least one disk object"
msgstr ""
msgid ""
"Invalid interface type. Type should be 'macvtap' for host network interface "
"(Ethernet, Bond, VLAN) to be connected as direct MacVTap or 'ovs' for "
"openvswitch host network interface to be connected as virtual switch to a VM."
msgstr ""
msgid "Interface name should be string."
msgstr ""
msgid "Invalid interface mode. Valid options are: bridge or vepa."
msgstr ""
msgid ""
"Interfaces should be list of interfaces. Each interface should have name, "
"type and mode(optional, only applicable for interfcae type 'macvtap'."
msgstr ""
msgid ""
"Interface expects an object with parameters: 'name', 'type' and 'mode'. Name "
"should be name of host network interface (Ethernet, Bond, VLAN) for type "
"'macvtap' or the name of host openvswitch bridge interface for type 'ovs'. "
"Mode (optional) is only applicable for interface type 'macvtap' to indicates "
"whether packets will be delivered directly to target device (bridge) or to "
"the external bridge (vepa-capable bridge)."
msgstr ""
msgid "Interfaces parameter only supported on s390x or s390 architecture."
msgstr ""
msgid "Storage without libvirt pool is not supported on this architecture"
msgstr ""
#, python-format
msgid "Error while creating the virtual disk for the guest. Details: %(err)s"
msgstr ""
msgid ""
"When setting template disks without libvirt, following parameters are "
"required: 'index', 'format', 'path', 'size'"
msgstr ""
#, python-format
msgid "Storage pool %(name)s already exists"
msgstr "Пул памяти %(name)s уже существует"
#, python-format
msgid "Storage pool %(name)s does not exist"
msgstr "Пул памяти %(name)s не существует"
#, python-format
msgid "Specify %(item)s in order to create the storage pool %(name)s"
msgstr "Укажите %(item)s, чтобы создать пул памяти %(name)s"
#, python-format
msgid "Unable to delete active storage pool %(name)s"
msgstr "Не удалось удалить пул памяти %(name)s"
#, python-format
msgid "Unable to list storage pools. Details: %(err)s"
msgstr "Не удалось вывести список пулов памяти. Сведения: %(err)s"
#, python-format
msgid "Unable to create storage pool %(name)s. Details: %(err)s"
msgstr "Не удалось создать пул памяти %(name)s. Сведения: %(err)s"
#, python-format
msgid "Unable to activate storage pool %(name)s. Details: %(err)s"
msgstr "Не удалось активировать пул памяти %(name)s. Сведения: %(err)s"
#, python-format
msgid "Unable to deactivate storage pool %(name)s. Details: %(err)s"
msgstr "Не удалось деактивировать пул памяти %(name)s. Сведения: %(err)s"
#, python-format
msgid "Unable to delete storage pool %(name)s. Details: %(err)s"
msgstr "Не удалось удалить пул памяти %(name)s. Сведения: %(err)s"
#, python-format
msgid ""
"Unable to create NFS Pool as export path %(path)s may block during mount"
msgstr ""
"Не удалось создать пул NFS: экспортированный путь %(path)s мог быть "
"заблокирован во время монтирования"
#, python-format
msgid "Unable to create NFS Pool as export path %(path)s mount failed"
msgstr ""
"Не удалось создать пул NFS: не удалось смонтировать экспортированный путь "
"%(path)s"
#, python-format
msgid "Unsupported storage pool type: %(type)s"
msgstr "Неподдерживаемый тип пула памяти: %(type)s"
#, python-format
msgid "Error while retrieving storage pool XML to %(pool)s"
msgstr "Ошибка получения XML пула памяти для %(pool)s"
msgid "Storage pool name must be a string without slashes (/)"
msgstr "Имя пула памяти должно быть строкой без символов косой черты (/)"
msgid ""
"Supported storage pool types are dir, netfs, logical, iscsi, isci and kimchi-"
"iso"
msgstr ""
"Поддерживаемые типы пулов памяти: dir, netfs, logical, iscsi, isci и kimchi-"
"iso"
msgid "Storage pool path must be a string"
msgstr "Путь к пулу памяти должен быть строкой"
msgid "Storage pool host must be a IP or hostname"
msgstr "Хост пула памяти должен быть IP-адресом или именем хоста"
msgid "Storage pool device must be the absolute path to the block device"
msgstr ""
"Устройство пула памяти должно быть абсолютным путем к блочному устройству"
msgid "Storage pool devices parameter must be a list"
msgstr "Параметр устройств пула памяти должен быть списком"
msgid "Target IQN of an iSCSI pool must be a string"
msgstr "Целевой IQN пула iSCSI должен быть строкой"
msgid "Port of a remote storage server must be an integer between 1 and 65535"
msgstr "Порт удаленного сервера памяти должен быть целым числом от 1 до 65535"
msgid "iSCSI target username must be a string"
msgstr "Имя пользователя целевого объекта iSCSI должно быть строкой"
msgid "iSCSI target password must be a string"
msgstr "Пароль целевого объекта iSCSI должен быть строкой"
msgid "Specify name and type to create a storage pool"
msgstr "Укажите имя и тип для создания пула памяти"
#, python-format
msgid ""
"%(disk)s is not a valid disk/partition. Could not add it to the pool "
"%(pool)s."
msgstr ""
"%(disk)s не является допустимым диском/разделом. Его не удалось добавить в "
"пул %(pool)s."
#, python-format
msgid "Unable to extend logical pool %(pool)s. Details: %(err)s"
msgstr "Не удалось расширить логический пул %(pool)s. Сведения: %(err)s"
msgid "The parameter disks only can be updated for logical storage pool."
msgstr "Диски параметров можно обновлять только для логического пула памяти."
msgid "The SCSI host adapter name must be a string."
msgstr "Имя адаптера хоста SCSI должно быть строкой."
msgid "The storage pool kimchi_isos is reserved for internal use"
msgstr "kimchi_isos пула памяти зарезервирован для внутреннего использования"
#, python-format
msgid ""
"Unable to activate NFS storage pool %(name)s. NFS server %(server)s is "
"unreachable."
msgstr ""
"Не удалось активировать пул памяти NFS %(name)s. Сервер NFS %(server)s "
"недоступен."
#, python-format
msgid ""
"Unable to deactivate NFS storage pool %(name)s. NFS server %(server)s is "
"unreachable."
msgstr ""
"Не удалось деактивировать пул памяти NFS %(name)s. Сервер NFS %(server)s "
"недоступен."
#, python-format
msgid ""
"Unable to deactivate pool %(name)s as it is associated with some templates"
msgstr "Не удалось деактивировать пул %(name)s: пул связан с шаблонами"
#, python-format
msgid "Unable to delete pool %(name)s as it is associated with some templates"
msgstr "Не удалось удалить пул %(name)s: пул связан с шаблонами"
#, python-format
msgid ""
"A volume group named '%(name)s' already exists. Please, choose another name "
"to create the logical pool."
msgstr ""
"Группа томов с именем '%(name)s' уже существует. Выберите другое имя для "
"создания логического пула."
#, python-format
msgid "Unable to update database with deep scan information due error: %(err)s"
msgstr ""
"Не удалось обновить базу данных информацией глубокого сканирования из-за "
"следующей ошибки: %(err)s"
#, python-format
msgid ""
"No volume group '%(name)s' found. Please, specify an existing volume group "
"to create the logical pool from."
msgstr ""
#, python-format
msgid "Unable to delete pool %(name)s as it is associated with guests: %(vms)s"
msgstr ""
#, python-format
msgid "Storage volume %(name)s already exists"
msgstr "Том памяти %(name)s уже существует"
#, python-format
msgid "Storage volume %(name)s does not exist in storage pool %(pool)s"
msgstr "Том памяти %(name)s не существует в пуле памяти %(pool)s"
#, python-format
msgid ""
"Unable to create storage volume %(volume)s because storage pool %(pool)s is "
"not active"
msgstr ""
"Не удалось создать том памяти %(volume)s, поскольку пул памяти %(pool)s "
"неактивен"
#, python-format
msgid "Specify %(item)s in order to create storage volume %(volume)s"
msgstr "Укажите %(item)s, чтобы создать том памяти %(volume)s"
#, python-format
msgid ""
"Unable to list storage volumes because storage pool %(pool)s is not active"
msgstr "Не удалось вывести список томов: пул памяти %(pool)s неактивен"
#, python-format
msgid ""
"Unable to create storage volume %(name)s in storage pool %(pool)s. Details: "
"%(err)s"
msgstr ""
"Не удалось создать том памяти %(name)s в пуле памяти %(pool)s. Сведения: "
"%(err)s"
#, python-format
msgid "Unable to wipe storage volumes %(name)s. Details: %(err)s"
msgstr "Не удалось стереть тома памяти %(name)s. Сведения: %(err)s"
#, python-format
msgid "Unable to delete storage volume %(name)s. Details: %(err)s"
msgstr "Не удалось удалить том памяти %(name)s. Сведения: %(err)s"
#, python-format
msgid "Unable to resize storage volume %(name)s. Details: %(err)s"
msgstr "Не удалось изменить размер тома памяти %(name)s. Сведения: %(err)s"
#, python-format
msgid "Storage type %(type)s does not support volume create and delete"
msgstr "Тип памяти %(type)s не поддерживает создание и удаление томов"
msgid "Storage volume name must be a string"
msgstr "Имя тома должно быть строкой"
msgid "Storage volume allocation must be an integer number"
msgstr "Выделение тома должно быть целым числом"
msgid ""
"Storage volume format not supported. Valid formats: qcow, qcow2, qed, raw, "
"vmdk, vpc."
msgstr ""
msgid "Storage volume requires a volume name"
msgstr "Тому требуется имя"
#, python-format
msgid ""
"Unable to update database with storage volume information due error: %(err)s"
msgstr ""
"Не удалось обновить базу данных информацией о томах памяти из-за следующей "
"ошибки: %(err)s"
#, python-format
msgid "Only one of parameter %(param)s can be specified"
msgstr "Можно указать только один параметр %(param)s"
#, python-format
msgid "Create volume from %(param)s is not supported"
msgstr "Создание тома из %(param)s не поддерживается"
msgid "Storage volume capacity must be an integer number."
msgstr "Емкость тома памяти должна быть целым числом."
msgid "Storage volume URL must be http://, https://, ftp:// or ftps://."
msgstr "URL тома памяти должен быть http://, https://, ftp:// или ftps://."
#, python-format
msgid "Unable to access file %(url)s. Please, check it."
msgstr "Нет доступа к файлу %(url)s. Проверьте его."
#, python-format
msgid ""
"Unable to clone storage volume '%(name)s' in pool '%(pool)s'. Details: "
"%(err)s"
msgstr ""
"Не удалось дублировать том памяти '%(name)s' в пуле '%(pool)s'. Сведения: "
"%(err)s"
msgid "Specify chunk data and its size to upload a file."
msgstr "Укажите данные блока и его размер для передачи файла."
msgid "In order to upload a storage volume, specify the 'upload' parameter."
msgstr "Для передачи тома памяти укажите параметр upload."
msgid ""
"Unable to upload chunk data as it does not match with requested chunk size."
msgstr ""
"Не удалось передать данные блока, поскольку они не соответствуют "
"запрошенному размеру блока."
#, python-format
msgid "The storage volume %(vol)s is not under an upload process."
msgstr "Том памяти %(vol)s не находится в процессе передачи."
msgid "The upload chunk data will exceed the storage volume size."
msgstr "Данные блока передачи превысят размер тома памяти."
#, python-format
msgid "Unable to upload chunk data to storage volume. Details: %(err)s."
msgstr ""
"Не удалось передать данные блока передачи в том памяти. Сведения: %(err)s."
#, python-format
msgid "Interface %(name)s does not exist"
msgstr "Интерфейс %(name)s не существует"
#, python-format
msgid ""
"Failed to list interfaces. Invalid _inuse parameter. Supported options for "
"_inuse are: %(supported_inuse)s"
msgstr ""
#, python-format
msgid "Network %(name)s already exists"
msgstr "Сеть %(name)s уже существует"
#, python-format
msgid "Network %(name)s does not exist"
msgstr "Сеть %(name)s не существует"
#, python-format
msgid "Subnet %(subnet)s specified for network %(network)s is not valid."
msgstr ""
msgid "Specify a network interface to create bridged or macvtap networks."
msgstr ""
#, python-format
msgid "Unable to delete or update active network %(name)s"
msgstr ""
#, python-format
msgid "Interface %(iface)s specified for network %(network)s is already in use"
msgstr "Интерфейс %(iface)s, указанный для сети %(network)s, уже используется"
msgid "Interface should be bare NIC, bonding or bridge device."
msgstr ""
"Интерфейс должен быть сетевой картой, устройством моста или связующим "
"устройством."
#, python-format
msgid "Unable to create or update network %(name)s. Details: %(err)s"
msgstr ""
#, python-format
msgid "Unable to find a free IP address for network '%(name)s'"
msgstr "Не найден свободный IP-адрес для сети %(name)s"
#, python-format
msgid "The interface %(iface)s already exists."
msgstr "Интерфейс %(iface)s уже существует."
msgid "Network name must be a string without slashes (/) or quotes (\")"
msgstr ""
"Имя сети должно быть строкой без символов косой черты (/) и кавычек (\")"
msgid ""
"Supported network types are isolated, NAT, macvtap, bridge, vepa and "
"passthrough."
msgstr ""
msgid "Network subnet must be a string with IP address and prefix or netmask"
msgstr ""
"Подсеть сети должна быть строкой, содержащей IP-адрес, префикс или маску сети"
msgid "Network interfaces must be an array."
msgstr ""
msgid "Network VLAN ID must be an integer between 1 and 4094"
msgstr "Сетевой ИД VLAN должен быть целым числом от 1 до 4094"
msgid "Specify name and type to create a Network"
msgstr "Укажите имя и тип для создания сети"
#, python-format
msgid ""
"Unable to delete or update network %(name)s as it is linked to some virtual "
"machines (%(vms)s) and/or templates (%(tmpls)s)."
msgstr ""
#, python-format
msgid ""
"Unable to deactivate network %(name)s as it is linked to are some virtual "
"machines (%(vms)s) and/or templates (%(tmpls)s)."
msgstr ""
#, python-format
msgid "Bridge device %(name)s can not be the trunk device of a VLAN."
msgstr ""
"Устройство моста %(name)s не может быть магистральным устройством VLAN."
#, python-format
msgid "Failed to activate interface %(iface)s: %(err)s."
msgstr "Не удалось активировать интерфейс %(iface)s: %(err)s."
#, python-format
msgid ""
"Failed to activate interface %(iface)s. Please check the physical link "
"status."
msgstr ""
"Не удалось активировать интерфейс %(iface)s. Проверьте физическую линию "
"связи "
#, python-format
msgid "Failed to start network %(name)s. Details: %(err)s"
msgstr "Не удалось запустить сеть %(name)s. Сведения: %(err)s"
#, python-format
msgid "Unable to redefine interface %(name)s. Details: %(err)s"
msgstr ""
#, python-format
msgid "Unable to create bridge %(name)s. Details: %(err)s"
msgstr ""
msgid ""
"Unable to create bridge with NetworkManager enabled. Disable it and try "
"again."
msgstr ""
msgid "Interface should be bare NIC or bonding."
msgstr ""
msgid "Network interfaces parameter must contain at least one interface."
msgstr ""
msgid "Only one interface is allowed for 'bridge' and 'macvtap' networks."
msgstr ""
msgid "Subnet is not a valid parameter for this type of virtual network."
msgstr ""
msgid ""
"VLAN ID and interfaces are not valid parameters for this type of virtual "
"network."
msgstr ""
#, python-format
msgid "Storage server %(server)s was not used by Kimchi"
msgstr "Сервер памяти %(server)s не использовался Kimchi"
#, python-format
msgid "Distro '%(name)s' does not exist"
msgstr "Вариант ОС '%(name)s' не существует"
#, python-format
msgid "Node device '%(name)s' not found"
msgstr "Устройство узла '%(name)s' не найдено"
msgid "Conflicting flag filters specified."
msgstr "Фильтры конфликтующих меток указаны."
msgid "Unable to choose a virtual machine name"
msgstr "Не удалось выбрать имя виртуальной машины"
msgid "Cannot upgrade objectstore data."
msgstr ""
msgid "Invalid storage type. Types supported: 'cdrom', 'disk'"
msgstr "Недопустимый тип памяти. Поддерживаемые типы: 'cdrom', 'disk'"
#, python-format
msgid "The path '%(value)s' is not a valid local/remote path for the device"
msgstr ""
"Путь '%(value)s' не является допустимым локальным/удаленным путем для "
"устройства"
msgid "Only CDROM path can be update."
msgstr "Можно изменить только путь к CDROM."
#, python-format
msgid ""
"The storage device %(dev_name)s does not exist in the virtual machine "
"%(vm_name)s"
msgstr ""
"Устройство хранения %(dev_name)s не существует в виртуальной машине "
"%(vm_name)s"
#, python-format
msgid "Error while creating new storage device: %(error)s"
msgstr "Ошибка создания устройства хранения: %(error)s"
#, python-format
msgid "Error while updating storage device: %(error)s"
msgstr "Ошибка обновления устройства хранения: %(error)s"
#, python-format
msgid "Error while removing storage device: %(error)s"
msgstr "Ошибка удаления устройства хранения: %(error)s"
msgid "Do not support IDE device hot plug"
msgstr "Не поддерживается оперативное подключение устройств IDE"
msgid ""
"Specify type and path or type and pool/volume to add a new virtual machine "
"disk"
msgstr ""
"Укажите тип и путь, либо тип и пул/том для добавления нового диска "
"виртуальной машины"
msgid "Specify path to update virtual machine disk"
msgstr "Укажите путь для обновления диска виртуальной машины"
#, python-format
msgid "Controller type %(type)s limitation of %(limit)s devices reached"
msgstr ""
"Достигнуто ограничение на число устройств (%(limit)s) для типа контроллера "
"%(type)s"
#, python-format
msgid "Cannot retrieve disk path information for given pool/volume: %(error)s"
msgstr ""
"Не удалось получить информацию о пути к диску для данного пула/тома: "
"%(error)s"
msgid "Volume already in use by other virtual machine."
msgstr "Том уже используется другой виртуальной машиной."
msgid ""
"Only one of path or pool/volume can be specified to add a new virtual "
"machine disk"
msgstr ""
"При добавлении нового диска виртуальной машины укажите либо путь, либо пул и "
"том"
#, python-format
msgid ""
"Volume chosen with format %(format)s does not fit in the storage type "
"%(type)s"
msgstr ""
"Выбранный том с форматом %(format)s не подходит для типа памяти %(type)s"
msgid "On s390x arch one of pool, path of dir_path must be specified"
msgstr ""
msgid ""
"On s390x arch 'format' must be specified while attaching disk to virtual "
"machine"
msgstr ""
#, python-format
msgid "Virtual disk already exists on the system: %(disk_path)s"
msgstr ""
#, python-format
msgid ""
"Unable to create snapshot '%(name)s' on virtual machine '%(vm)s'. Details: "
"%(err)s"
msgstr ""
"Не удалось создать моментальную копию '%(name)s' виртуальной машины "
"'%(vm)s'. Сведения: %(err)s"
#, python-format
msgid "Snapshot '%(name)s' does not exist on virtual machine '%(vm)s'."
msgstr ""
"Моментальная копия '%(name)s' не существует у виртуальной машины '%(vm)s'."
#, python-format
msgid ""
"Unable to retrieve snapshot '%(name)s' on virtual machine '%(vm)s'. Details: "
"%(err)s"
msgstr ""
"Не удалось получить моментальную копию '%(name)s' виртуальной машины "
"'%(vm)s'. Сведения: %(err)s"
#, python-format
msgid "Unable to list snapshots on virtual machine '%(vm)s'. Details: %(err)s"
msgstr ""
"Не удалось вывести список моментальных копий виртуальной машины '%(vm)s'. "
"Сведения: %(err)s"
#, python-format
msgid ""
"Unable to delete snapshot '%(name)s' on virtual machine '%(vm)s'. Details: "
"%(err)s"
msgstr ""
"Не удалось удалить моментальную копию '%(name)s' виртуальной машины "
"'%(vm)s'. Сведения: %(err)s"
#, python-format
msgid ""
"Unable to retrieve current snapshot of virtual machine '%(vm)s'. Details: "
"%(err)s"
msgstr ""
"Не удалось получить текущую моментальную копию виртуальной машины '%(vm)s'. "
"Сведения: %(err)s"
#, python-format
msgid ""
"Unable to revert virtual machine '%(vm)s' to snapshot '%(name)s'. Details: "
"%(err)s"
msgstr ""
"Не удалось восстановить состояние виртуальной машины '%(vm)s' из "
"моментальной копии '%(name)s'. Сведения: %(err)s"
#, python-format
msgid ""
"Unable to create snapshot of virtual machine '%(vm)s' because it contains a "
"disk with format '%(format)s'; only 'qcow2' is supported."
msgstr ""
"Не удалось создать моментальную копию виртуальной машины '%(vm)s', поскольку "
"она содержит диск в формате %(format)s. Поддерживается только формат qcow2."
msgid ""
"The number of vCPUs must be less than or equal the maximum number of vCPUs "
"specified."
msgstr ""
msgid ""
"When CPU topology is defined, maximum number of vCPUs must be a product of "
"sockets, cores, and threads."
msgstr ""
msgid "This host (or current configuration) does not allow CPU topology."
msgstr ""
"На этом хосте (или в текущей конфигурации) не разрешена топология "
"процессоров."
msgid "The maximum number of vCPUs is too large for this system."
msgstr ""
msgid ""
"When CPU topology is defined, CPUs must be a multiple of the 'threads' "
"number defined."
msgstr ""
msgid ""
"When CPU topology is specified, sockets, cores and threads are required "
"paramaters."
msgstr ""
msgid ""
"Parameter 'cpu_info' expects an object with fields among: 'vcpus', "
"'maxvcpus', 'topology'."
msgstr ""
msgid ""
"Parameter 'topology' expects an object with fields among: 'sockets', "
"'cores', 'threads'."
msgstr ""
msgid "Unable to update Max CPU or CPU topology when guest is running."
msgstr ""
#, python-format
msgid "Unable to hot plug/unplug CPUs. Details: %(err)s"
msgstr ""
#, python-format
msgid "Invalid volume group name parameter: %(name)s."
msgstr ""
msgid ""
"Unable to establish connection with libvirt. Please check your libvirt URI "
"which is often defined in /etc/libvirt/libvirt.conf"
msgstr ""
msgid ""
"Libvirt service is not active. Please start the libvirt service in your host "
"system."
msgstr ""
msgid "Failed to register the default event implementation."
msgstr ""
msgid "Failed to register timeout event."
msgstr ""
msgid "Failed to Run the default event implementation."
msgstr ""
#, python-format
msgid ""
"I/O error on guest '%(vm)s': storage pool out of space for %(devAlias)s "
"(%(srcPath)s)."
msgstr ""
#, python-format
msgid "Create virtual network '%(name)s' type '%(connection)s'"
msgstr ""
#, python-format
msgid "Remove virtual network '%(ident)s'"
msgstr ""
#, python-format
msgid "Update virtual network '%(ident)s'"
msgstr ""
#, python-format
msgid "Activate virtual network '%(ident)s'"
msgstr ""
#, python-format
msgid "Deactivate virtual network '%(ident)s'"
msgstr ""
#, python-format
msgid "Create storage pool '%(name)s' type '%(type)s'"
msgstr ""
#, python-format
msgid "Remove storage pool '%(ident)s'"
msgstr ""
#, python-format
msgid "Update storage pool '%(ident)s'"
msgstr ""
#, python-format
msgid "Activate storage pool '%(ident)s'"
msgstr ""
#, python-format
msgid "Deactivate storage pool '%(ident)s'"
msgstr ""
#, python-format
msgid "Create snapshot '%(name)s' at guest '%(vm)s'"
msgstr ""
#, python-format
msgid "Remove snapshot '%(ident)s' from guest '%(vm)s'"
msgstr ""
#, python-format
msgid "Revert guest '%(vm)s' to snapshot '%(ident)s'"
msgstr ""
#, python-format
msgid "Create template '%(name)s'"
msgstr ""
#, python-format
msgid "Remove template '%(ident)s'"
msgstr ""
#, python-format
msgid "Update template '%(ident)s'"
msgstr ""
#, python-format
msgid "Clone template '%(ident)s'"
msgstr ""
#, python-format
msgid "Create guest '%(name)s' from template '%(template)s'"
msgstr ""
#, python-format
msgid "Remove guest '%(ident)s'"
msgstr ""
#, python-format
msgid "Edit guest '%(ident)s'"
msgstr ""
#, python-format
msgid "Start guest '%(ident)s'"
msgstr ""
#, python-format
msgid "Power off guest '%(ident)s'"
msgstr ""
#, python-format
msgid "Shutdown guest '%(ident)s'"
msgstr ""
#, python-format
msgid "Restart guest '%(ident)s'"
msgstr ""
#, python-format
msgid "Connect to guest '%(ident)s' through novnc/spice"
msgstr ""
#, python-format
msgid "Clone guest '%(ident)s'"
msgstr ""
#, python-format
msgid "Migrate guest '%(ident)s' to '%(remote_host)s'"
msgstr ""
#, python-format
msgid "Suspend guest '%(ident)s'"
msgstr ""
#, python-format
msgid "Resume guest '%(ident)s'"
msgstr ""
#, python-format
msgid "Connect to guest '%(ident)s' through serial"
msgstr ""
#, python-format
msgid "Attach host device '%(name)s' to guest '%(vmid)s'"
msgstr ""
#, python-format
msgid "Detach host device '%(ident)s' from guest '%(vmid)s'"
msgstr ""
#, python-format
msgid "Attach network interface '%(network)s' to guest '%(vm)s'"
msgstr ""
#, python-format
msgid "Detach network interface '%(ident)s' from guest '%(vm)s'"
msgstr ""
#, python-format
msgid "Update network interface '%(ident)s' at guest '%(vm)s'"
msgstr ""
#, python-format
msgid "Attach %(type)s storage '%(path)s' to guest '%(vm)s'"
msgstr ""
#, python-format
msgid "Remove storage '%(ident)s' from guest '%(vm)s'"
msgstr ""
#, python-format
msgid "Update storage '%(ident)s' at guest '%(vm)s'"
msgstr ""
#, python-format
msgid "Create storage volume '%(name)s' at pool '%(pool)s'"
msgstr ""
#, python-format
msgid "Remove storage volume '%(ident)s' from pool '%(pool)s'"
msgstr ""
#, python-format
msgid "Update storage volume '%(ident)s' at pool '%(pool)s'"
msgstr ""
#, python-format
msgid "Wipe storage volume '%(ident)s' off pool '%(pool)s'"
msgstr ""
#, python-format
msgid "Resize storage volume '%(ident)s' at pool '%(pool)s' with size %(size)s"
msgstr ""
#, python-format
msgid "Clone storage volume '%(ident)s' at pool '%(pool)s'"
msgstr ""
msgid "Create a New Virtual Machine"
msgstr "Создать новую виртуальную машину"
msgid "Virtual Machine Name"
msgstr "Имя виртуальной машины"
msgid ""
"The name used to identify the virtual machine. If omitted, a name will be "
"chosen based on the template used."
msgstr ""
"Имя для идентификации виртуальной машины. Если не указано, имя будет выбрано "
"в зависимости от используемого шаблона."
msgid "Please create a template first."
msgstr "Сначала создайте шаблон."
msgid "Create a Template"
msgstr "Создать шаблон"
msgid "Please choose a template."
msgstr "Выберите шаблон."
msgid "This template has invalid parameters."
msgstr ""
msgid "This template has invalid parameters"
msgstr ""
msgid "OS"
msgstr "ОС"
msgid "Version"
msgstr "Версия"
msgid "Current CPUs"
msgstr ""
msgid "Memory"
msgstr "Память"
msgid "Create"
msgstr "Создать"
msgid "Creating..."
msgstr "Создание..."
msgid "Cancel"
msgstr "Отмена"
msgid "Clone a Guest"
msgstr ""
msgid ""
"When the target guest has SCSI or iSCSI volumes, they will be cloned on the "
"default storage pool. The same will happen when the target pool does not "
"have enough space to clone the volumes. Do you want to continue?"
msgstr ""
msgid "Number of times to clone"
msgstr ""
msgid "Continue"
msgstr ""
msgid "Edit Guest"
msgstr "Изменить гостевую систему"
msgid "General"
msgstr "Общие"
msgid "Storage"
msgstr "Дисковая память"
msgid "Interface"
msgstr "Интерфейс"
msgid "Permission"
msgstr ""
msgid "Pci"
msgstr ""
msgid "Snapshot"
msgstr ""
msgid "Processor"
msgstr "Процессор"
msgid "Name"
msgstr "Имя"
msgid "Memory (MB)"
msgstr "Объем памяти (МБ)"
msgid "More"
msgstr ""
msgid "Max Memory (MB)"
msgstr ""
msgid "Host does not support memory hotplug"
msgstr ""
msgid "Icon"
msgstr "Значок"
msgid "Console"
msgstr ""
msgid "Nothing selected"
msgstr ""
msgid "sclp"
msgstr ""
msgid "virtio"
msgstr ""
msgid ""
"Select which items for boot order and grad them when needed to order them. "
"At least one option must be selected."
msgstr ""
msgid "Add"
msgstr "Добавить"
msgid "Device"
msgstr "Устройство"
msgid "Path"
msgstr "Путь"
msgid "Actions"
msgstr "Действия"
msgid "Network"
msgstr "Сеть"
msgid "Type"
msgstr "Тип"
msgid "MAC Address"
msgstr "MAC-адрес"
msgid "IP Address"
msgstr ""
msgid "Network/Interface"
msgstr ""
msgid "Mode"
msgstr ""
msgid "Available system users and groups"
msgstr "Доступные системные пользователи и группы"
msgid "Users"
msgstr "Пользователи"
msgid "Groups"
msgstr "Группы"
msgid "Selected system users and groups"
msgstr "Выбранные системные пользователи и группы"
msgid "User"
msgstr "Пользователь"
msgid "All"
msgstr "Все"
msgid "To Add"
msgstr "Добавить"
msgid "Added"
msgstr "Добавлено"
msgid "Filter"
msgstr ""
msgid "Status"
msgstr ""
msgid "Product"
msgstr "Продукт"
msgid "Vendor"
msgstr "Вендор"
msgid "Loading"
msgstr ""
msgid "Created"
msgstr "Дата создания"
msgid "Current CPU Number"
msgstr ""
msgid ""
"Current CPU must be equal or lower than the Maximum CPU value. If a topology "
"is set, it must be also be a multiple of the 'threads' value."
msgstr ""
msgid "Max CPU"
msgstr ""
msgid ""
"Unable to edit maximum CPU or CPU topology when editing a running or paused "
"virtual machine."
msgstr ""
msgid ""
"If a topology is set, this value will be the product of sockets * times * "
"cores."
msgstr ""
msgid "Manually set CPU topology"
msgstr "Вручную настроить топологию процессоров"
msgid "Sockets"
msgstr ""
msgid "Cores"
msgstr "Ядра"
msgid "Threads"
msgstr "Нити"
msgid "Save"
msgstr "Сохранить"
msgid "Replace"
msgstr "Заменить"
msgid "Detach"
msgstr "Отключить"
msgid "Remove"
msgstr "Удалить"
msgid "Edit"
msgstr "Изменить"
msgid "LDAP User ID,e.g.foo@foo.com"
msgstr "ИД пользователя LDAP, например foo@foo.com"
msgid "Revert"
msgstr ""
msgid "Running"
msgstr ""
msgid "Disconnected"
msgstr ""
msgid "Starting"
msgstr ""
msgid "Crashed"
msgstr ""
msgid "Unknown"
msgstr ""
msgid "Paused"
msgstr ""
msgid "Suspended"
msgstr ""
msgid "Resetting"
msgstr ""
msgid "View Console"
msgstr ""
msgid "View Serial"
msgstr ""
msgid "Clone"
msgstr "Дублировать"
msgid "Migrate"
msgstr ""
msgid "Reset"
msgstr "Сброс"
msgid "Pause"
msgstr "Приостановить"
msgid "Resume"
msgstr "Возобновить"
msgid "Shut Down"
msgstr "Завершить работу"
msgid "Start"
msgstr "Запустить"
msgid "Power Off"
msgstr "Выключить питание"
msgid "Delete"
msgstr "Удалить"
msgid "No Data Available"
msgstr ""
msgid "Processors Utilization"
msgstr ""
msgid "Memory Utilization"
msgstr ""
msgid "Storage I/O"
msgstr ""
msgid "Network I/O"
msgstr "Сетевой ввод-вывод"
msgid "Migrate a Guest"
msgstr ""
msgid ""
"Disclaimer: This process cannot be stopped after started, can take a long "
"time to complete and will turn off the VM on this Hypervisor when it is "
"successfully migrated to the remote destination."
msgstr ""
msgid "Remote Server"
msgstr ""
msgid "IP Address or Hostname"
msgstr ""
msgid ""
"The following fields are optional. Fill them if you want Kimchi to setup a "
"password-less ssh session between the localhost and the remote host. The "
"setup process will only be successful if the user has 'SUDO ALL' permission "
"in the remote machine."
msgstr ""
msgid "Username of the remote host"
msgstr ""
msgid "Password"
msgstr "Пароль"
msgid "Password of the user in the remote host"
msgstr ""
msgid "Use RDMA transport"
msgstr ""
msgid ""
"Check this option only if RDMA is properly configured in both source and "
"destination hosts, otherwise migration will fail."
msgstr ""
msgid "Delete this VM when the migration is completed"
msgstr ""
msgid "Add a Storage Device to VM"
msgstr "Добавить устройство хранения в VM"
msgid "Device Type"
msgstr "Тип устройства"
msgid ""
"The device type. Currently, \"cdrom\" and \"disk\" are supported. If the "
"guest is running, only \"disk\" is supported."
msgstr ""
msgid "Create a new disk"
msgstr ""
msgid "Select an existing disk"
msgstr ""
msgid "Source"
msgstr ""
msgid "Storage based on Libvirt pool or direct block device"
msgstr ""
msgid "Storage Pool"
msgstr "Пул памяти"
msgid "Storage pool to create the volume in"
msgstr ""
msgid "Disk Size (GB)"
msgstr ""
msgid "New disk size to be created"
msgstr ""
msgid "Format"
msgstr ""
msgid "Format of the new disk to be created"
msgstr ""
msgid "Directory Path"
msgstr ""
msgid "Provide a directory path"
msgstr ""
msgid "Storage pool in which the volume is located in"
msgstr ""
msgid "Storage Volume"
msgstr "Том памяти"
msgid "Storage volume to be attached"
msgstr "Том подключен"
msgid "Disk Path"
msgstr ""
msgid "Provide a block device"
msgstr ""
msgid "File Path"
msgstr "Путь к файлу"
msgid "The ISO file path in the server for CDROM."
msgstr "Путь к файлу ISO для CDROM на сервере."
msgid "Attach"
msgstr "Подключить"
msgid "Host"
msgstr "Хост"
msgid "Guests"
msgstr "Гостевые системы"
msgid "Templates"
msgstr "Шаблоны"
msgid "This is not a valid Linux path"
msgstr "Этот недопустимый путь в Linux"
msgid "Unable to read file."
msgstr "Не удалось прочитать файл."
msgid "Error while uploading file."
msgstr "Ошибка передачи файла."
msgid "Delete Confirmation"
msgstr "Подтверждение удаления"
msgid "OK"
msgstr "OK"
msgid "Confirm"
msgstr "Подтвердить"
msgid "Warning"
msgstr "Предупреждение"
msgid "Cloning..."
msgstr "Дублирование..."
msgid "Saving..."
msgstr ""
msgid "Migrating..."
msgstr ""
msgid "No ISO found"
msgstr "Не найден образ ISO"
msgid "Add Template"
msgstr "Добавить шаблон"
msgid "This may take a long time. Do you want to continue?"
msgstr "Это может занять много времени. Продолжить?"
msgid ""
"This will permanently delete the %1 template. Would you like to continue?"
msgstr ""
msgid "View Table"
msgstr ""
msgid "View Gallery"
msgstr ""
msgid "Not Available"
msgstr ""
msgid "Please check the invalid Storage Pools"
msgstr ""
msgid "Please check the invalid Storage Pools or Paths"
msgstr ""
msgid "macvtap"
msgstr ""
msgid "ovs"
msgstr ""
msgid "network"
msgstr ""
msgid ""
"This will delete the %1 virtual machine and its virtual disks. This "
"operation cannot be undone. Would you like to continue?"
msgstr ""
msgid "Power off Confirmation"
msgstr "Подтверждение отключения питания"
msgid ""
"This action may produce undesirable results, for example unflushed disk "
"cache in the %1 guest. Would you like to continue?"
msgstr ""
msgid "Reset Confirmation"
msgstr "Подтверждение сброса"
msgid ""
"There is a risk of data loss caused by reset without the %1 guest OS "
"shutdown. Would you like to continue?"
msgstr ""
msgid "Shut Down Confirmation"
msgstr "Подтверждение завершения работы"
msgid ""
"Note the %1 guest OS may ignore this request. Would you like to continue?"
msgstr ""
msgid "Virtual Machine delete Confirmation"
msgstr "Подтверждение удаления виртуальной машины"
msgid ""
"The %1 virtual machine is not persistent. Power Off will delete it. Continue?"
msgstr ""
msgid "Add Guest"
msgstr ""
msgid "Input is not a number"
msgstr ""
msgid "Memory value cannot be higher than Max Memory value"
msgstr ""
msgid ""
"For better performance it is recommended a threads per core value not "
"greater than %1."
msgstr ""
msgid ""
"This CDROM will be detached permanently and you can re-attach it. Continue "
"to detach it?"
msgstr ""
"Этот CDROM будет отключен. Его можно будет снова подключить. Отключить?"
msgid "Attaching..."
msgstr "Подключение..."
msgid ""
"This disk will be detached permanently and you can re-attach it. Continue to "
"detach it?"
msgstr "Этот диск будет отключен. Его можно будет снова подключить. Отключить?"
msgid "interface:"
msgstr "интерфейс:"
msgid "address:"
msgstr "адрес:"
msgid "link_type:"
msgstr "тип линии связи:"
msgid "block:"
msgstr "блок:"
msgid "drive_type:"
msgstr "тип накопителя:"
msgid "model:"
msgstr "модель:"
msgid "Affected devices:"
msgstr "Затронутые устройства:"
msgid "Less"
msgstr ""
msgid "Successfully attached device to VM"
msgstr ""
msgid "Successfully detached device from VM"
msgstr ""
msgid "Following devices will be affected, confirm?"
msgstr ""
msgid "Bridge"
msgstr ""
msgid "Vepa"
msgstr ""
msgid "None"
msgstr ""
msgid "unavailable"
msgstr "недоступно"
msgid ""
"This action will interrupt network connectivity for any virtual machine that "
"depend on the %1 network."
msgstr ""
msgid "Add Network"
msgstr ""
msgid ""
"The %1 network is not persistent. Instead of stop, this action will "
"permanently delete it. Would you like to continue?"
msgstr ""
msgid ""
"The bridged VLAN tag may not work well with NetworkManager enabled. You "
"should consider disabling it."
msgstr ""
"Тег комплексной VLAN может работать неправильно с включенным NetworkManager. "
"Его рекомендуется выключить."
msgid ""
"This will permanently delete the %1 storage pool. Would you like to continue?"
msgstr ""
msgid "This storage pool is empty."
msgstr "Этот пул памяти пустой."
msgid ""
"It will format your disk and you will loose any data in there, are you sure "
"to continue? "
msgstr ""
"Диск будет отформатирован, и все данные на нем будут потеряны. Вы "
"действительно хотите продолжить? "
msgid "SCSI Fibre Channel"
msgstr "SCSI Fibre Channel"
msgid "No SCSI adapters found."
msgstr "Не найдены адаптеры SCSI."
msgid "Loading iSCSI targets..."
msgstr "Загрузка целевых объектов iSCSI..."
msgid "No iSCSI found. Please input one."
msgstr "Не найден iSCSI. Введите."
msgid "Failed to load iSCSI targets."
msgstr "Не удалось загрузить целевые объекты iSCSI."
msgid "Would you like to continue?"
msgstr ""
msgid "This will permanently delete the following storage volumes: %1"
msgstr ""
msgid "No available partitions found."
msgstr "Не найдены доступные разделы."
msgid ""
"The %1 storage pool is not persistent. Instead of deactivate, this action "
"will permanently delete it. Would you like to continue?"
msgstr ""
msgid "Unable to retrieve partitions information."
msgstr "Не удалось получить информацию о разделах."
msgid "In progress..."
msgstr "Выполнение..."
msgid "Failed!"
msgstr "Сбой!"
msgid "No LVM found in the system."
msgstr ""
msgid "This will permanently wipe the following storage volumes: %1"
msgstr ""
msgid "Wipe Confirmation"
msgstr ""
msgid "Select one or more partitions to be added to the logical pool %1:"
msgstr ""
msgid "Add Storage"
msgstr ""
msgid "DIR"
msgstr ""
msgid "NFS"
msgstr ""
msgid "iSCSI"
msgstr ""
msgid "LOGICAL"
msgstr ""
msgid "device"
msgstr ""
msgid "path"
msgstr ""
msgid "size (GiB)"
msgstr ""
msgid "free size (GiB)"
msgstr ""
msgid "Invalid NFS mount path."
msgstr "Недопустимый путь монтирования NFS."
msgid "No logical device selected."
msgstr "Не выбрано логическое устройство."
msgid "This is not a valid Server Name or IP. Please, modify it."
msgstr "Это не допустимое имя или IP-адрес сервера. Измените его."
msgid "CDROM path needs to be a valid local/remote path and cannot be blank."
msgstr ""
"Путь к CDROM должен быть правильным локальным или удаленным путем и не может "
"быть пустым."
msgid "Disk pool or volume cannot be blank."
msgstr "Не указан пул или том диска."
msgid ""
"Disk size or Format or Directory path cannot be blank and Directory path "
"needs to be a valid local/remote path."
msgstr ""
msgid "Disk path needs to be a valid local/remote path and cannot be blank."
msgstr ""
msgid "Storage pool or Disk size or Format cannot be blank."
msgstr ""
msgid "cdrom"
msgstr ""
msgid "disk"
msgstr ""
msgid "Pool"
msgstr ""
msgid "qcow"
msgstr ""
msgid "qcow2"
msgstr ""
msgid "qed"
msgstr ""
msgid "raw"
msgstr ""
msgid "vmdk"
msgstr ""
msgid "vpc"
msgstr ""
msgid "Create a network"
msgstr "Создать сеть"
msgid "Network Name"
msgstr "Имя сети"
msgid "Name should not contain '/' and '\"'."
msgstr "Имя не должно содержать '/' и '\"'."
msgid "Network Type"
msgstr "Тип сети"
msgid "Isolated: no external network connection"
msgstr "Изолированный: без внешних сетевых соединений"
msgid "NAT: outbound physical network connection only"
msgstr "NAT (только исходящее физическое сетевое соединение)"
msgid "Macvtap: Virtual machines are connected to physical network directly"
msgstr ""
msgid ""
"Passthrough: Virtual machines are connected using a macvtap connection in "
"passthrough mode."
msgstr ""
msgid ""
"VEPA: special mode where virtual machines are connected to a VEPA-enabled "
"switch"
msgstr ""
msgid "Bridged: Virtual machines are connected through a network bridge"
msgstr ""
msgid "Destination"
msgstr "Целевое расположение"
msgid "Select an Interface"
msgstr ""
msgid "Enable VLAN"
msgstr "Включить VLAN"
msgid "VLAN ID"
msgstr "Идентификатор VLAN"
msgid "Edit Network"
msgstr ""
msgid "Address Space"
msgstr ""
msgid "Define a New Storage Pool"
msgstr "Создать пул памяти"
msgid "Storage Pool Name"
msgstr "Имя пула памяти"
msgid ""
"The name used to identify the storage pools, and it should not be empty."
msgstr "Имя для идентификации пулов памяти. Не может быть пустым."
msgid "Storage Pool Type"
msgstr "Тип пула памяти"
msgid "Storage Path"
msgstr "Путь к диску"
msgid ""
"The path of the Storage Pool. Each Storage Pool must have a unique path."
msgstr "Путь к пулу памяти. Каждый пул памяти должен иметь уникальный путь."
msgid ""
"Kimchi will try to create the directory when it does not already exist in "
"your system."
msgstr "Kimchi попытается создать каталог, если он не существует в системе."
msgid "NFS Server IP"
msgstr "IP-адрес сервера NFS"
msgid "NFS server IP or hostname. It can be input or chosen from history."
msgstr ""
"IP-адрес или имя хоста сервера NFS. Его можно ввести или выбрать в "
"хронологии."
msgid "NFS Path"
msgstr "Путь NFS"
msgid "The NFS exported path on NFS server."
msgstr "Экспортированный путь NFS на сервере NFS."
msgid "Create from existing LVM"
msgstr ""
msgid "Create from raw disk"
msgstr ""
msgid "Looking for existing lvms ..."
msgstr ""
msgid "Looking for available partitions ..."
msgstr "Поиск доступных разделов..."
msgid "iSCSI Server"
msgstr "Сервер iSCSI"
msgid "Server"
msgstr "Сервер"
msgid "Port"
msgstr "Порт"
msgid "iSCSI server IP or hostname. It should not be empty."
msgstr "IP-адрес или имя хоста сервера iSCSI. Не может быть пустым."
msgid "Target"
msgstr "Целевой объект"
msgid "The iSCSI target on iSCSI server"
msgstr "Целевой объект iSCSI на сервере iSCSI"
msgid "Add iSCSI Authentication"
msgstr "Добавить идентификацию iSCSI"
msgid "User Name"
msgstr "Имя пользователя"
msgid "SCSI Adapter"
msgstr "Адаптер SCSI"
msgid "Please, wait..."
msgstr "Подождите..."
msgid "Add a Volume to Storage Pool"
msgstr "Добавить том в пул памяти"
msgid "Fetch from remote URL"
msgstr "Загрузить с удаленного URL"
msgid "Enter the remote URL here."
msgstr "Введите сюда удаленный URL."
msgid "Upload a file"
msgstr "Передать файл"
msgid "Choose the file you want to upload."
msgstr "Выберите файл для передачи."
msgid "Resize Volume"
msgstr ""
msgid "Size"
msgstr ""
msgid "The total space which can be used to store data. The unit is megabytes."
msgstr ""
msgid "Ok"
msgstr ""
msgid "Template Name"
msgstr ""
msgid ""
"The name used to identify the template. If omitted, a name will be "
"automatically chosen."
msgstr ""
msgid ""
"When selecting more than one Image Template, a name will be automatically "
"chosen for each Image Template selected."
msgstr ""
msgid "Where is the source media for this template? "
msgstr ""
msgid "Image Template"
msgstr ""
msgid "Netboot Template"
msgstr ""
msgid "File Path:"
msgstr "Путь к файлу:"
msgid "Search ISOs"
msgstr "Поиск образов ISO"
msgid "The following ISOs are available:"
msgstr "Доступные образы ISO:"
msgid "QEMU does not have enough permission to work with this file"
msgstr ""
msgid "Search more ISOs"
msgstr "Поиск дополнительных образов ISO"
msgid "Loading..."
msgstr ""
msgid "Edit Template"
msgstr "Изменить шаблон"
msgid "CDROM"
msgstr "CDROM"
msgid "Image File"
msgstr "Файл образа"
msgid "Graphics"
msgstr "Графика"
msgid "Disk(GB)"
msgstr "Диск (ГБ)"
msgid "Disk Format"
msgstr "Формат диска"
msgid "Add Interface"
msgstr ""
msgid "pool"
msgstr ""
msgid "bridge"
msgstr ""
msgid "vepa"
msgstr ""
msgid "State"
msgstr ""
msgid "Guest Name ID"
msgstr ""
msgid "OS Type"
msgstr ""
msgid "VNC"
msgstr ""
msgid "No guests found."
msgstr ""
msgid "Stop"
msgstr ""
msgid "Location"
msgstr ""
msgid "%Used"
msgstr ""
msgid "Allocated"
msgstr ""
msgid "Capacity"
msgstr ""
msgid "Disks"
msgstr ""
msgid "Extending logical pool"
msgstr ""
msgid "%"
msgstr ""
msgid "Deactivate"
msgstr ""
msgid "Activate"
msgstr ""
msgid "Extend"
msgstr ""
msgid "Undefine"
msgstr ""
msgid "Add Volume"
msgstr ""
msgid "Resize"
msgstr ""
msgid "Wipe"
msgstr ""
msgid "Filter:"
msgstr ""
msgid "Used By"
msgstr ""
msgid "Used"
msgstr ""
msgid "Progress"
msgstr ""
msgid "Used by the following VMs:"
msgstr ""
msgid "Allocation"
msgstr ""
msgid "Template Name (ID)"
msgstr ""
msgid "No templates found."
msgstr ""
msgid "M"
msgstr ""
================================================
FILE: po/zh_CN.po
================================================
# Chinese (zh_CN) translations for kimchi package.
# Copyright IBM Corp, 2013-2017
# Adam Litke , 2013.
#
msgid ""
msgstr ""
"Project-Id-Version: kimchi 0.1\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2017-06-30 10:27-0300\n"
"PO-Revision-Date: 2013-07-11 17:32-0400\n"
"Last-Translator: Crístian Viana \n"
"Language-Team: English\n"
"Language: zh_CN\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: pygettext.py 1.5\n"
"Plural-Forms: nplurals=1; plural=0;\n"
#, python-format
msgid "Unknown parameter %(value)s"
msgstr "未知参数 %(value)s"
#, python-format
msgid "User %(user_id)s not found with given LDAP settings."
msgstr "找不到具有给定 LDAP 设置的用户 %(user_id)s。"
#, python-format
msgid "Partition %(name)s does not exist in the host"
msgstr "分区 %(name)s 在主机中不存在"
msgid "Error while accessing dev mapper device, %(err)s"
msgstr ""
msgid "Block device not found."
msgstr ""
msgid "Block device %(device)s not found."
msgstr ""
msgid "Unable to retrieve LVM information. Details: %(err)s"
msgstr ""
msgid "Unknown \"_cap\" specified"
msgstr "指定了未知“_cap”"
msgid "\"_passthrough\" should be \"true\" or \"false\""
msgstr "“_passthrough”应该为“true”或“false”"
msgid "\"_passthrough_affected_by\" should be a device name string"
msgstr "“_passthrough_affected_by”应该为设备名字符串"
msgid "\"_available_only\" should be \"true\" or \"false\""
msgstr "“_available_only”应该为“true”或“false”"
#, python-format
msgid "Unable to find distro file: %(filename)s"
msgstr "找不到 distro 文件:%(filename)s"
#, python-format
msgid ""
"Unable to parse distro file: %(filename)s. Make sure, it is a JSON file."
msgstr "无法解析 Distro 文件:%(filename)s。请确保该文件是 JSON 文件。"
#, python-format
msgid "Unable to login to iSCSI host target %(portal)s. Details: %(err)s"
msgstr "无法登录 iSCSI 主机目标 %(portal)s。详细信息:%(err)s"
#, python-format
msgid "Unable to login to iSCSI host %(host)s target %(target)s"
msgstr "无法登录 iSCSI 主机 %(host)s 目标 %(target)s"
#, python-format
msgid "Unable to find ISO file %(filename)s"
msgstr "找不到 ISO 文件 %(filename)s"
#, python-format
msgid "The ISO file %(filename)s is not bootable"
msgstr "ISO 文件 %(filename)s 不可引导"
#, python-format
msgid "The ISO file %(filename)s does not have a valid El Torito boot record"
msgstr "ISO 文件 %(filename)s 没有有效的 EI Torito 引导记录"
#, python-format
msgid "Invalid El Torito validation entry in ISO %(filename)s"
msgstr "ISO %(filename)s 中的 El Torito 验证条目无效"
#, python-format
msgid "Invalid El Torito boot indicator in ISO %(filename)s"
msgstr "ISO %(filename)s 中的 El Torito 引导指示器无效"
#, python-format
msgid "Unexpected volume type for primary volume in ISO %(filename)s"
msgstr "ISO %(filename)s 中主要卷具有意外的卷类型"
#, python-format
msgid "Bad format while reading volume descriptor in ISO %(filename)s"
msgstr "在 ISO %(filename)s 中读取卷描述符时格式错误"
#, python-format
msgid ""
"The hypervisor doesn't have permission to use this ISO %(filename)s. "
"Consider moving it under /var/lib/libvirt, or set the search permission to "
"file access control lists for '%(user)s' user if possible, or add the "
"'%(user)s' to the ISO path group, or (not recommended) 'chmod -R o+x "
"'path_to_iso'.Details: %(err)s"
msgstr ""
"管理程序不具使用此 ISO %(filename)s 的许可权。考虑在 /var/lib/libvirt 下移动"
"该 ISO、设置对“%(user)s”用户的文件访问控制表的搜索许可权(如果可能)、"
"将“%(user)s”添加至 ISO 路径组或者(不推荐)使用 'chmod -R o+x 'path_to_iso'。"
"详细信息:%(err)s"
#, python-format
msgid "Unable to access remote ISO. Details: %(err)s"
msgstr "无法访问远程 ISO。详细信息:%(err)s"
#, python-format
msgid "Error probing image OS information: %(err)s"
msgstr ""
#, python-format
msgid "Unable to read image file %(filename)s"
msgstr "无法读取映像文件 %(filename)s"
#, python-format
msgid ""
"Image file must be an existing file on system. %(filename)s is not a valid "
"input."
msgstr "映像文件必须是系统上的现有文件。%(filename)s 是无效输入。"
#, python-format
msgid "Virtual machine %(name)s already exists"
msgstr "虚拟机 %(name)s 已存在"
#, python-format
msgid "Virtual machine %(name)s does not exist"
msgstr "虚拟机 %(name)s 不存在"
#, python-format
msgid "Unable to retrieve screenshot for stopped virtual machine %(name)s"
msgstr "无法检索已停止的虚拟机 %(name)s 的屏幕快照"
msgid "Remote ISO image is not supported by this server."
msgstr "远程 ISO 映像不受此服务器支持。"
#, python-format
msgid "Screenshot is not supported on virtual machine %(name)s"
msgstr "屏幕快照在虚拟机 %(name)s 上不受支持"
#, python-format
msgid "Unable to create virtual machine %(name)s. Details: %(err)s"
msgstr "无法创建虚拟机 %(name)s。详细信息:%(err)s"
#, python-format
msgid "Unable to update virtual machine %(name)s. Details: %(err)s"
msgstr "无法更新虚拟机 %(name)s。详细信息:%(err)s"
#, python-format
msgid "Unable to retrieve virtual machine %(name)s. Details: %(err)s"
msgstr "无法检索虚拟机 %(name)s。详细信息:%(err)s"
#, python-format
msgid "Unable to connect to powered off virtual machine %(name)s."
msgstr "无法连接到已关闭电源的虚拟机 %(name)s。"
msgid "Virtual machine name must be a string without slashes (/)"
msgstr "虚拟机名称必须是不带斜杠 (/) 的字符串"
#, python-format
msgid "Invalid template URI %(value)s specified for virtual machine"
msgstr "为虚拟机指定的模板 URI %(value)s 无效"
#, python-format
msgid "Invalid storage pool URI %(value)s specified for virtual machine"
msgstr "为虚拟机指定的存储池 URI %(value)s 无效"
msgid "Supported virtual machine graphics are Spice or VNC"
msgstr "受支持的虚拟机图形为 Spice 或 VNC"
msgid "Graphics address to listen on must be IPv4 or IPv6"
msgstr "要侦听的图形地址必须是 IPv4 或 IPv6"
msgid "Specify a template to create a virtual machine from"
msgstr "指定要从其创建虚拟机的模板"
#, python-format
msgid "Unable to start virtual machine %(name)s. Details: %(err)s"
msgstr "无法启动虚拟机 %(name)s。详细信息:%(err)s"
#, python-format
msgid "Unable to power off virtual machine %(name)s. Details: %(err)s"
msgstr "无法对虚拟机 %(name)s 断电。详细信息:%(err)s"
#, python-format
msgid "Unable to delete virtual machine %(name)s. Details: %(err)s"
msgstr "无法删除虚拟机 %(name)s。详细信息:%(err)s"
#, python-format
msgid "Unable to reset virtual machine %(name)s. Details: %(err)s"
msgstr "无法重置虚拟机 %(name)s。详细信息:%(err)s"
msgid "User name list must be an array"
msgstr "用户名列表必须是数组"
msgid "User name must be a string"
msgstr "用户名必须是字符串"
msgid "Group name list must be an array"
msgstr "组名列表必须是数组"
msgid "Group name must be a string"
msgstr "组名必须是字符串"
#, python-format
msgid "User(s) '%(users)s' do not exist"
msgstr "用户“%(users)s”不存在"
#, python-format
msgid "Group(s) '%(groups)s' do not exist"
msgstr "组“%(groups)s”不存在"
#, python-format
msgid "Unable to shutdown virtual machine %(name)s. Details: %(err)s"
msgstr "无法关闭虚拟机 %(name)s。详细信息:%(err)s"
msgid "The guest console password must be a string."
msgstr "访客控制台密码必须是字符串。"
msgid "The life time for the guest console password must be a number."
msgstr "访客控制台密码的有效期必须是数字。"
#, python-format
msgid "Virtual machine '%(name)s' must be stopped before cloning it."
msgstr "在对虚拟机“%(name)s”进行克隆之前,必须将其停止。"
#, python-format
msgid "Insufficient disk space to clone virtual machine '%(name)s'"
msgstr "没有足够的磁盘空间,无法对虚拟机“%(name)s”进行克隆"
#, python-format
msgid "Unable to clone VM '%(name)s'. Details: %(err)s"
msgstr "无法对 VM“%(name)s”进行克隆。详细信息:%(err)s"
#, python-format
msgid "Invalid operation for non-persistent virtual machine %(name)s"
msgstr "对非持久性虚拟机 %(name)s 的操作无效"
#, python-format
msgid "Cannot suspend VM '%(name)s' because it is not running."
msgstr "无法暂挂 VM“%(name)s”,因为它未在运行。"
#, python-format
msgid "Unable to suspend VM '%(name)s'. Details: %(err)s"
msgstr "无法暂挂 VM“%(name)s”。详细信息:%(err)s"
#, python-format
msgid "Cannot resume VM '%(name)s' because it is not paused."
msgstr "无法恢复 VM“%(name)s”,因为它未暂停。"
#, python-format
msgid "Unable to resume VM '%(name)s'. Details: %(err)s"
msgstr "无法恢复 VM“%(name)s”。详细信息:%(err)s"
#, python-format
msgid ""
"Memory assigned is higher then the maximum allowed in the host: "
"%(maxmem)sMib."
msgstr "所分配内存高于主机中允许的最大内存:%(maxmem)sMiB。"
#, python-format
msgid ""
"Guest '%(name)s' does not support live memory update. Please, with the guest "
"offline, set Maximum Memory with a value greater then Memory to enable this "
"feature."
msgstr ""
"访客“%(name)s”不支持实时内存更新。在访客脱机的情况下,请将“最大内存”设置为大"
"于“内存”的值以启用此功能。"
msgid "Only increase memory is allowed in active VMs"
msgstr "仅允许在活动 VM 中增加内存"
msgid "There are not enough free slots to add a new memory device."
msgstr "没有足够的可用插槽来添加新的内存设备。"
msgid ""
"Host's libvirt or qemu version does not support memory devices and memory "
"hotplug. Libvirt must be >= 1.2.14 and QEMU must be >= 2.1."
msgstr ""
"主机的 libvirt 或 qemu 版本不支持内存设备和内存热插拔。Libvirt 至少是 "
"1.2.14,QEMU 至少是 2.1。"
#, python-format
msgid "Error attaching memory device. Details: %(error)s"
msgstr "连接内存设备时出错。详细信息:%(error)s"
#, python-format
msgid "Cannot start %(name)s. Virtual machine is already running."
msgstr "无法启动 %(name)s。虚拟机正在运行。"
#, python-format
msgid "Cannot power off %(name)s. Virtual machine is shut off."
msgstr "无法关闭 %(name)s 电源。虚拟机已关机。"
#, python-format
msgid "Cannot shutdown %(name)s. Virtual machine is shut off."
msgstr "无法关闭 %(name)s。虚拟机已关机。"
#, python-format
msgid "Cannot reset %(name)s. Virtual machine is already shut off."
msgstr "无法重置 %(name)s。虚拟机已关机。"
msgid "Boot order must be a list. Devices accepted: hd, cdrom, fd or network."
msgstr "引导顺序必须为列表。接受的设备:硬盘、CD-ROM、软盘或网络。"
msgid "Bootmenu must be boolean. Values accepted: true of false."
msgstr "Bootmenu 必须为布尔值。接受的值:true 或 false。"
msgid "Graphic type not valid. Values accepted: vnc or spice."
msgstr "图形类型无效。接受的值:vnc 或 spice。"
#, python-format
msgid "Migrate to localhost %(host)s is not allowed."
msgstr "不允许迁移至本地主机 %(host)s。"
#, python-format
msgid ""
"To migrate a virtual machine to the remote host %(host)s the user %(user)s "
"must have password-less login to the remote host."
msgstr ""
"要将虚拟机迁移至远程主机 %(host)s,用户 %(user)s 必须以无密码方式登录远程主"
"机。"
#, python-format
msgid "Can not migrate virtual machine %(name)s when its in %(state)s state."
msgstr "虚拟机 %(name)s 处于 %(state)s 状态时,无法迁移该虚拟机。"
#, python-format
msgid "Failed to migrate virtual machine %(name)s due error: %(err)s"
msgstr "无法迁移虚拟机 %(name)s,因为发生了错误:%(err)s"
msgid "User name of the remote server must be a string."
msgstr "远程服务器的用户名必须为字符串。"
msgid "Destination host of the migration must be a string."
msgstr "迁移的目标主机必须为字符串。"
#, python-format
msgid "Unable to create file %(path)s at %(host)s using user %(user)s."
msgstr "无法在 %(host)s 上使用用户 %(user)s 创建文件 %(path)s。"
#, python-format
msgid "Unable to read disk size of %(path)s, error: %(error)s"
msgstr "无法读取 %(path)s 的磁盘大小,因为发生了错误:%(error)s"
#, python-format
msgid ""
"Unable to create disk image %(path)s at %(host)s using user %(user)s. Error: "
"%(error)s"
msgstr ""
"无法在 %(host)s 上使用用户 %(user)s 创建磁盘映像 %(path)s。错误:%(error)s"
#, python-format
msgid ""
"Unable to migrate virtual machine to remote host %(host)s with arch "
"%(destarch)s using localhost with arch %(srcarch)s."
msgstr ""
"无法使用体系结构为 %(srcarch)s 的本地主机将虚拟机迁移至体系结构为 "
"%(destarch)s 的远程主机 %(host)s。"
#, python-format
msgid ""
"Unable to migrate virtual machine to remote host %(host)s with hypervisor "
"%(desthyp)s because localhost uses hypervisor %(srchyp)s."
msgstr ""
"无法将虚拟机迁移至管理程序为 %(desthyp)s 的远程主机 %(host)s,因为本地主机使"
"用管理程序 %(srchyp)s。"
#, python-format
msgid ""
"Unable to determine remote host hypervisor and architecture. Error: %(error)s"
msgstr "无法确定远程主机管理程序和体系结构。错误:%(error)s"
#, python-format
msgid ""
"Unable to migrate virtual machine: subcores per core setting from "
"localhostand remote host %(host)s differs."
msgstr ""
"无法迁移虚拟机:远程主机和本地主机 %(host)s 中的每个核心的子核心数设置不同。"
#, python-format
msgid ""
"Unable to setup password-less login at remote host %(host)s using user "
"%(user)s. Error: %(error)s"
msgstr ""
"无法通过用户 %(user)s 在远程主机 %(host)s 上设置无密码登录。错误:%(error)s"
msgid "Password field must be a string."
msgstr "密码字段必须为字符串。"
msgid "Error creating local host ssh rsa key of user 'root'."
msgstr "创建用户“root”的本地主机 ssh rsa 密钥时出错。"
#, python-format
msgid "%(param)s value (%(mem)sMiB) must be aligned to %(alignment)sMiB."
msgstr "%(param)s 值 (%(mem)sMiB) 必须与 %(alignment)sMiB 匹配。"
#, python-format
msgid ""
"Unable to update the following parameters while the VM is offline: %(params)s"
msgstr "VM 脱机时无法更新以下参数:%(params)s"
#, python-format
msgid ""
"Unable to update the following parameters while the VM is online: %(params)s"
msgstr "VM 联机时无法更新以下参数:%(params)s"
#, python-format
msgid ""
"VM %(name)s must have serial and console defined to open a web serial console"
msgstr "VM %(name)s 必须已定义串行线路和控制台以打开 Web 串行控制台"
#, python-format
msgid "Impossible to get the serial console of %(name)s"
msgstr "无法获取 %(name)s 的串行控制台"
#, python-format
msgid ""
"Memory or Maximum Memory value is higher than amount supported by the host: "
"%(memHost)sMiB."
msgstr "“内存”或“最大内存”值高于主机支持的量:%(memHost)sMiB。"
#, python-format
msgid ""
"Memory or Maximum Memory value is higher than maximum amount recommended: "
"%(value)sTiB"
msgstr "“内存”或“最大内存”值高于建议的最大量:%(value)sTiB。"
msgid "Cannot update Maximum Memory when guest is running."
msgstr "访客正在运行时,无法更新最大内存。"
#, python-format
msgid "Impossible to create %(dir)s directory."
msgstr "无法创建 %(dir)s 目录。"
#, python-format
msgid ""
"Either the guest %(name)s did not start to listen to the serial or it is not "
"configured to use the serial console."
msgstr "访客 %(name)s 未开始侦听串行线路或它未配置为使用串行控制台。"
#, python-format
msgid ""
"Unable to retrieve Virt Viewer file for stopped virtual machine %(name)s"
msgstr "无法检索已停止虚拟机 %(name)s 的 Virt Viewer 文件"
#, python-format
msgid ""
"Error occured while retrieving the Virt Viewer file for virtual machine "
"%(name)s : %(err)s"
msgstr "检索虚拟机 %(name)s 的 Virt Viewer 文件时发生了错误:%(err)s"
msgid "Virtual machine title must be a string"
msgstr "虚拟机标题必须为字符串"
msgid "Virtual machine description must be a string"
msgstr "虚拟机描述必须为字符串"
msgid "console parameter is only supported for s390x/s390 architecture."
msgstr "仅 s390x/s390 体系结构支持控制台参数。"
msgid "invalid console type, supported types are sclp/virtio."
msgstr "无效控制台类型,受支持类型为 sclp/virtio。"
#, python-format
msgid ""
"Unable to setup password-less login at remote host %(host)s using user "
"%(user)s: remote directory %(sshdir)s does not exist."
msgstr ""
"无法通过用户 %(user)s 在远程主机 %(host)s 上设置无密码登录:远程目录 "
"%(sshdir)s 不存在。"
#, python-format
msgid ""
"Unable to create a password-less libvirt connection to the remote libvirt "
"daemon at host %(host)s with the user %(user)s. Please verify the remote "
"server libvirt configuration. More information: http://libvirt.org/auth."
"html ."
msgstr ""
"无法通过用户 %(user)s 在主机 %(host)s 上创建与远程 libvirt 守护程序的无密码 "
"libvirt 连接。请验证远程服务器 libvirt 配置。有关更多信息,请参阅 http://"
"libvirt.org/auth.html。"
msgid "'enable_rdma' must be of type boolean (true or false)."
msgstr ""
#, python-format
msgid ""
"VM %(vmid)s does not contain directly assigned host device %(dev_name)s."
msgstr "VM %(vmid)s 不包含直接分配的主机设备 %(dev_name)s。"
#, python-format
msgid "The host device %(dev_name)s is not allowed to directly assign to VM."
msgstr "不允许将主机设备 %(dev_name)s 直接分配给 VM。"
msgid ""
"No IOMMU groups found. Host PCI pass through needs IOMMU group to function "
"correctly. Please enable Intel VT-d or AMD IOMMU in your BIOS, then verify "
"the Kernel is compiled with IOMMU support. For Intel CPU, add "
"'intel_iommu=on' to GRUB_CMDLINE_LINUX parameter in /etc/default/grub file. "
"For AMD CPU, add 'iommu=pt iommu=1'."
msgstr ""
"找不到 IOMMU 组。主机 PCI 传递要求 IOMMU 组正常工作。请在 BIOS 中启用 Intel "
"VT-d 或 AMD IOMMU,然后验证内核在编译时是否带有 IOMMU 支持。对于 Intel CPU,"
"将“intel_iommu=on”添加至 /etc/default/grub 文件中的 GRUB_CMDLINE_LINUX 参数。"
"对于 AMD CPU,添加“iommu=pt iommu=1”。"
msgid "\"name\" should be a device name string"
msgstr "“name”应该为设备名字符串"
#, python-format
msgid ""
"The device %(name)s is probably in use by the host. Unable to attach it to "
"the guest."
msgstr "主机可能正在使用设备 %(name)s。无法将其连接至访客。"
#, python-format
msgid "Hot-(un)plug of device %(name)s is not supported."
msgstr "不支持设备 %(name)s 的热插拔。"
#, python-format
msgid "Failed to attach %(device)s to %(vm)s"
msgstr "无法将 %(device)s 连接至 %(vm)s"
#, python-format
msgid "VM %(vmid)s does not have a USB controller to accept PCI hotplug."
msgstr ""
#, python-format
msgid "Interface %(iface)s does not exist in virtual machine %(name)s"
msgstr "接口 %(iface)s 在虚拟机 %(name)s 中不存在"
#, python-format
msgid ""
"Network %(network)s specified for virtual machine %(name)s does not exist"
msgstr "为虚拟机 %(name)s 所指定的网络 %(network)s 不存在"
msgid ""
"Supported virtual machine interfaces type are network, ovs and macvtap.Type "
"ovs and macvtap are only supported for s390x/s390 architecture."
msgstr ""
"受支持虚拟机接口类型为 network、ovs 和 macvtap。仅 s390x/s390 体系结构支持类"
"型 ovs 和 macvtap。"
msgid "Network name for virtual machine interface must be a string"
msgstr "虚拟机接口的网络名必须是字符串"
msgid "Invalid network model card specified for virtual machine interface"
msgstr "为虚拟机接口所指定的网络模型卡无效"
msgid "Specify type and network to add a new virtual machine interface"
msgstr "指定类型和网络以添加新虚拟机接口"
msgid "MAC Address must respect this format FF:FF:FF:FF:FF:FF"
msgstr "MAC 地址必须遵循格式 FF:FF:FF:FF:FF:FF"
#, python-format
msgid "MAC Address %(mac)s already exists in virtual machine %(name)s"
msgstr "MAC 地址 %(mac)s 已在虚拟机 %(name)s 中存在"
msgid "Invalid MAC Address"
msgstr "无效 MAC 地址"
msgid "Cannot change MAC address of a running virtual machine"
msgstr "无法更改正在运行的虚拟机的 MAC 地址"
msgid "Type macvtap and ovs are only supported on s390x/s390 architecture."
msgstr "仅 s390x/s390 体系结构支持类型 macvtap 和 ovs。"
msgid "Source attribute is only supported on s390x/s390 architecture."
msgstr "仅 s390x/s390 体系结构支持源属性。"
msgid "If source is provided, only type supported are macvtap and ovs."
msgstr "如果提供了源,那么仅支持类型 macvtap 和 ovs。"
msgid "For type macvtap and ovs, source has to be provided"
msgstr "对于类型 macvtap 和 ovs,必须提供源"
msgid "Source name for virtual machine interface must be string"
msgstr "虚拟机接口的源名称必须是字符串"
msgid "Invalid source mode. Valid options are: bridge or vepa."
msgstr "无效源方式。有效选项为:bridge 或 vepa。"
#, python-format
msgid "Template %(name)s already exists"
msgstr "模板 %(name)s 已存在"
#, python-format
msgid "Source media %(path)s not found"
msgstr "找不到源介质 %(path)s"
#, python-format
msgid ""
"Network '%(network)s' specified for template %(template)s does not exist"
msgstr "为模板 %(template)s 所指定的网络“%(network)s”不存在"
#, python-format
msgid ""
"Storage pool %(pool)s specified for template %(template)s does not exist"
msgstr "为模板 %(template)s 所指定的存储池“%(pool)s”不存在"
#, python-format
msgid "Invalid parameter '%(param)s' specified for CDROM."
msgstr "为 CDROM 所指定的参数“%(param)s”无效。"
#, python-format
msgid "Network %(network)s specified for template %(template)s is not active"
msgstr "为模板 %(template)s 所指定的网络 %(network)s 处于不活动状态"
msgid "Template name must be a string"
msgstr "模板名称必须是字符串"
msgid "Template icon must be a path to the image"
msgstr "模板图标必须是映像的路径"
msgid "Template distribution must be a string"
msgstr "模板分发必须是字符串"
msgid "Template distribution version must be a string"
msgstr "模板分发版本必须是字符串"
msgid "The number of CPUs must be an integer greater than 0"
msgstr "CPU 的数目必须是一个大于 0 的整数"
msgid ""
"Amount of memory and maximum memory (MB) must be an integer greater than 512"
msgstr "内存量和最大内存量 (MB) 必须是大于 512 的整数"
msgid "Template CDROM must be a local or remote ISO file"
msgstr "模板 CDROM 必须是一个本地或远程 ISO 文件"
#, python-format
msgid "Invalid storage pool URI %(value)s specified for template"
msgstr "为模板所指定的存储池 URI %(value)s 无效"
msgid ""
"Specify a path to source media (ISO, disk or remote ISO) to create a template"
msgstr "指定源介质(ISO、磁盘或远程 ISO)的路径以创建模板"
msgid "All networks for the template must be specified in a list."
msgstr "必须以列表格式指定模板的所有网络。"
msgid "Specify a volume to a template when storage pool is iSCSI or SCSI"
msgstr "当存储池为 iSCSI 或 SCSI 时,请对模板指定卷。"
#, python-format
msgid "The volume %(volume)s is not in storage pool %(pool)s"
msgstr "卷 %(volume)s 不在存储池 %(pool)s 中"
#, python-format
msgid "Unable to create template due error: %(err)s"
msgstr "无法创建模板,因为错误:%(err)s"
#, python-format
msgid "Unable to delete template due error: %(err)s"
msgstr "无法删除模板,因为错误:%(err)s"
msgid "Disk size must be an integer greater than 1GB."
msgstr "磁盘大小必须是大于 1 GB 的整数。"
#, python-format
msgid "Cannot identify base image %(path)s format"
msgstr "无法识别基本映像 %(path)s 格式"
msgid ""
"When specifying CPU topology, each element must be an integer greater than "
"zero."
msgstr "指定 CPU 拓扑时,每个元素必须是大于零的整数。"
msgid ""
"Invalid disk image format. Valid formats: qcow, qcow2, qed, raw, vmdk, vpc."
msgstr "无效磁盘映像格式。有效格式为:qcow、qcow2、qed、raw、vmdk 和 vpc。"
msgid ""
"When setting template disks, following parameters are required: 'index', "
"'pool name', 'format', 'size' or 'volume' (for scsi/iscsi pools)"
msgstr ""
"设置模板磁盘时,需要以下参数:“index”、“pool "
"name”、“format”、“size”或“volume”(对于 scsi/iscsi 池)"
msgid "Disk format must be 'raw', for logical, iscsi, and scsi pools."
msgstr "对于逻辑池,iSCSI 池和 SCSI 池,磁盘格式必须为“raw”。"
msgid ""
"Memory expects an object with one or both parameters: 'current' and "
"'maxmemory'"
msgstr "内存需要具有下列一个或两个参数的对象:“current”和“maxmemory”"
#, python-format
msgid ""
"Memory value (%(mem)sMiB) must be equal or lesser than maximum memory value "
"(%(maxmem)sMiB)"
msgstr "内存值 (%(mem)sMiB) 必须等于或小于最大内存值 (%(maxmem)sMiB)"
#, python-format
msgid "Unable to update template due error: %(err)s"
msgstr "无法更新模板,因为发生了错误:%(err)s"
msgid "Parameter 'disks' requires at least one disk object"
msgstr "参数“disks”需要至少一个磁盘对象"
msgid ""
"Invalid interface type. Type should be 'macvtap' for host network interface "
"(Ethernet, Bond, VLAN) to be connected as direct MacVTap or 'ovs' for "
"openvswitch host network interface to be connected as virtual switch to a VM."
msgstr ""
"无效接口类型。对于主机网络接口(Ethernet、Bond 和 VLAN),类型应该"
"为“macvtap”才能作为直接 MacVTap 进行连接,对于 openvswitch,类型应该为“ovs”以"
"作为虚拟交换机连接至 VM。"
msgid "Interface name should be string."
msgstr "接口名称应该为字符串。"
msgid "Invalid interface mode. Valid options are: bridge or vepa."
msgstr "无效接口方式。有效选项为:bridge 或 vepa。"
msgid ""
"Interfaces should be list of interfaces. Each interface should have name, "
"type and mode(optional, only applicable for interfcae type 'macvtap'."
msgstr ""
"接口应该为接口列表。每个接口应该具有名称、类型和方式(可选,仅当接口类型"
"为“macvtap”时才适用)。"
msgid ""
"Interface expects an object with parameters: 'name', 'type' and 'mode'. Name "
"should be name of host network interface (Ethernet, Bond, VLAN) for type "
"'macvtap' or the name of host openvswitch bridge interface for type 'ovs'. "
"Mode (optional) is only applicable for interface type 'macvtap' to indicates "
"whether packets will be delivered directly to target device (bridge) or to "
"the external bridge (vepa-capable bridge)."
msgstr ""
"接口需要带有以下参数的对象:“name”、“type”和“mode”。对于类型“macvtap”,名称应"
"该为主机网络接口(Ethernet、Bond 和 VLAN)的名称,对于类型“ovs”,名称应该为主"
"机 openvswitch 网桥接口的名称。方式(可选)仅对接口类型“macvtap”适用,用于指"
"示是直接将包传送至目标设备(网桥)还是传送至外部网桥(支持 vepa 的网桥)。"
msgid "Interfaces parameter only supported on s390x or s390 architecture."
msgstr "仅 s390x 或 s390 体系结构支持接口参数。"
msgid "Storage without libvirt pool is not supported on this architecture"
msgstr "此体系结构不支持不带 libvirt 池的存储器"
#, python-format
msgid "Error while creating the virtual disk for the guest. Details: %(err)s"
msgstr "为访客创建虚拟盘时出错。详细信息:%(err)s"
msgid ""
"When setting template disks without libvirt, following parameters are "
"required: 'index', 'format', 'path', 'size'"
msgstr ""
"设置不带 libvirt 的模板磁盘时,需要以下参"
"数:“index”、“format”、“path”和“size”。"
#, python-format
msgid "Storage pool %(name)s already exists"
msgstr "存储池 %(name)s 已存在"
#, python-format
msgid "Storage pool %(name)s does not exist"
msgstr "存储池 %(name)s 不存在"
#, python-format
msgid "Specify %(item)s in order to create the storage pool %(name)s"
msgstr "指定 %(item)s 以创建存储池 %(name)s"
#, python-format
msgid "Unable to delete active storage pool %(name)s"
msgstr "无法删除活动存储池 %(name)s"
#, python-format
msgid "Unable to list storage pools. Details: %(err)s"
msgstr "无法列示存储池。详细信息:%(err)s"
#, python-format
msgid "Unable to create storage pool %(name)s. Details: %(err)s"
msgstr "无法创建存储池 %(name)s。详细信息:%(err)s"
#, python-format
msgid "Unable to activate storage pool %(name)s. Details: %(err)s"
msgstr "无法激活存储池 %(name)s。详细信息:%(err)s"
#, python-format
msgid "Unable to deactivate storage pool %(name)s. Details: %(err)s"
msgstr "无法取消激活存储池 %(name)s。详细信息:%(err)s"
#, python-format
msgid "Unable to delete storage pool %(name)s. Details: %(err)s"
msgstr "无法删除存储池 %(name)s。详细信息:%(err)s"
#, python-format
msgid ""
"Unable to create NFS Pool as export path %(path)s may block during mount"
msgstr "无法创建 NFS 池,因为导出路径 %(path)s 可能在安装期间被阻塞"
#, python-format
msgid "Unable to create NFS Pool as export path %(path)s mount failed"
msgstr "无法创建 NFS 池,因为导出路径 %(path)s 安装失败"
#, python-format
msgid "Unsupported storage pool type: %(type)s"
msgstr "不受支持的存储池类型:%(type)s"
#, python-format
msgid "Error while retrieving storage pool XML to %(pool)s"
msgstr "将存储池 XML 检索至 %(pool)s 时出错"
msgid "Storage pool name must be a string without slashes (/)"
msgstr "存储池名称必须是不带斜杠 (/) 的字符串"
msgid ""
"Supported storage pool types are dir, netfs, logical, iscsi, isci and kimchi-"
"iso"
msgstr "受支持的存储池类型为 dir、netfs、logical、iscsi、isci 和 kimchi-iso"
msgid "Storage pool path must be a string"
msgstr "存储池路径必须是字符串"
msgid "Storage pool host must be a IP or hostname"
msgstr "存储池主机必须是一个 IP 或主机名"
msgid "Storage pool device must be the absolute path to the block device"
msgstr "存储池设备必须是块设备的绝对路径"
msgid "Storage pool devices parameter must be a list"
msgstr "存储池设备参数必须是一个列表"
msgid "Target IQN of an iSCSI pool must be a string"
msgstr "iSCSI 池的目标 IQN 必须是字符串"
msgid "Port of a remote storage server must be an integer between 1 and 65535"
msgstr "远程存储服务器的端口必须是一个介于 1 到 65535 之间的整数"
msgid "iSCSI target username must be a string"
msgstr "iSCSI 目标用户名必须是字符串"
msgid "iSCSI target password must be a string"
msgstr "iSCSI 目标密码必须是字符串"
msgid "Specify name and type to create a storage pool"
msgstr "指定名称和类型以创建存储池"
#, python-format
msgid ""
"%(disk)s is not a valid disk/partition. Could not add it to the pool "
"%(pool)s."
msgstr "%(disk)s 是无效磁盘/分区。无法将其添加至池 %(pool)s。"
#, python-format
msgid "Unable to extend logical pool %(pool)s. Details: %(err)s"
msgstr "无法扩展逻辑池 %(pool)s。详细信息:%(err)s"
msgid "The parameter disks only can be updated for logical storage pool."
msgstr "只能更新逻辑存储池的参数磁盘。"
msgid "The SCSI host adapter name must be a string."
msgstr "SCSI 主机适配器名称必须是字符串。"
msgid "The storage pool kimchi_isos is reserved for internal use"
msgstr "存储池 kimchi_isos 已保留供内部使用"
#, python-format
msgid ""
"Unable to activate NFS storage pool %(name)s. NFS server %(server)s is "
"unreachable."
msgstr "无法激活 NFS 存储池 %(name)s。NFS 服务器 %(server)s不可访问。"
#, python-format
msgid ""
"Unable to deactivate NFS storage pool %(name)s. NFS server %(server)s is "
"unreachable."
msgstr "无法取消激活 NFS 存储池 %(name)s。NFS 服务器 %(server)s不可访问。"
#, python-format
msgid ""
"Unable to deactivate pool %(name)s as it is associated with some templates"
msgstr "无法取消激活池 %(name)s,因为它与某些模板相关联"
#, python-format
msgid "Unable to delete pool %(name)s as it is associated with some templates"
msgstr "无法删除池 %(name)s,因为该池与某些模板关联"
#, python-format
msgid ""
"A volume group named '%(name)s' already exists. Please, choose another name "
"to create the logical pool."
msgstr "名为“%(name)s”的卷组已存在。请选择另一名称以创建逻辑池。"
#, python-format
msgid "Unable to update database with deep scan information due error: %(err)s"
msgstr "无法使用深度扫描信息更新数据库,因为发生了错误:%(err)s"
#, python-format
msgid ""
"No volume group '%(name)s' found. Please, specify an existing volume group "
"to create the logical pool from."
msgstr "找不到卷组“%(name)s”。请指定现有卷组以通过其创建逻辑池。"
#, python-format
msgid "Unable to delete pool %(name)s as it is associated with guests: %(vms)s"
msgstr "无法删除池 %(name)s,因为它与访客 %(vms)s 相关联"
#, python-format
msgid "Storage volume %(name)s already exists"
msgstr "存储卷 %(name)s 已存在"
#, python-format
msgid "Storage volume %(name)s does not exist in storage pool %(pool)s"
msgstr "存储卷 %(name)s 在存储池 %(pool)s 中不存在"
#, python-format
msgid ""
"Unable to create storage volume %(volume)s because storage pool %(pool)s is "
"not active"
msgstr "无法创建存储卷 %(volume)s,因为存储池 %(pool)s 处于不活动状态"
#, python-format
msgid "Specify %(item)s in order to create storage volume %(volume)s"
msgstr "指定 %(item)s 以创建存储卷 %(volume)s"
#, python-format
msgid ""
"Unable to list storage volumes because storage pool %(pool)s is not active"
msgstr "无法列示存储卷,因为存储池 %(pool)s 处于不活动状态"
#, python-format
msgid ""
"Unable to create storage volume %(name)s in storage pool %(pool)s. Details: "
"%(err)s"
msgstr "无法在以下存储池中创建存储卷 %(name)s:%(pool)s。详细信息:%(err)s"
#, python-format
msgid "Unable to wipe storage volumes %(name)s. Details: %(err)s"
msgstr "无法清除存储卷 %(name)s。详细信息:%(err)s"
#, python-format
msgid "Unable to delete storage volume %(name)s. Details: %(err)s"
msgstr "无法删除存储卷 %(name)s。详细信息:%(err)s"
#, python-format
msgid "Unable to resize storage volume %(name)s. Details: %(err)s"
msgstr "无法调整存储卷 %(name)s 的大小。详细信息:%(err)s"
#, python-format
msgid "Storage type %(type)s does not support volume create and delete"
msgstr "存储类型 %(type)s 不支持创建和删除卷"
msgid "Storage volume name must be a string"
msgstr "存储卷名称必须是字符串"
msgid "Storage volume allocation must be an integer number"
msgstr "存储卷分配必须是一个整数数字"
msgid ""
"Storage volume format not supported. Valid formats: qcow, qcow2, qed, raw, "
"vmdk, vpc."
msgstr "存储卷格式不受支持。有效格式为:qcow、qcow2、qed、raw、vmdk 和 vpc。"
msgid "Storage volume requires a volume name"
msgstr "存储卷需要卷名"
#, python-format
msgid ""
"Unable to update database with storage volume information due error: %(err)s"
msgstr "无法使用存储卷信息更新数据库,因为错误:%(err)s"
#, python-format
msgid "Only one of parameter %(param)s can be specified"
msgstr "只能指定一个 %(param)s 参数"
#, python-format
msgid "Create volume from %(param)s is not supported"
msgstr "不支持根据 %(param)s 创建卷"
msgid "Storage volume capacity must be an integer number."
msgstr "存储卷容量必须是整数。"
msgid "Storage volume URL must be http://, https://, ftp:// or ftps://."
msgstr "存储卷 URL 必须是 http://、https://、ftp:// 或 ftps://。"
#, python-format
msgid "Unable to access file %(url)s. Please, check it."
msgstr "无法访问文件 %(url)s。请检查该文件。"
#, python-format
msgid ""
"Unable to clone storage volume '%(name)s' in pool '%(pool)s'. Details: "
"%(err)s"
msgstr ""
"无法对以下池中的存储卷“%(name)s”进行克隆:“%(pool)s”。详细信息:%(err)s"
msgid "Specify chunk data and its size to upload a file."
msgstr "指定区块数据及其大小以上载文件。"
msgid "In order to upload a storage volume, specify the 'upload' parameter."
msgstr "要上载存储卷,请指定“upload”参数。"
msgid ""
"Unable to upload chunk data as it does not match with requested chunk size."
msgstr "无法上载区块数据,因为它与所请求的区块大小不匹配。"
#, python-format
msgid "The storage volume %(vol)s is not under an upload process."
msgstr "存储卷 %(vol)s 未包括在上载过程中。"
msgid "The upload chunk data will exceed the storage volume size."
msgstr "上载区块数据将超过存储卷大小。"
#, python-format
msgid "Unable to upload chunk data to storage volume. Details: %(err)s."
msgstr "无法将区块数据上载至存储卷。详细信息:%(err)s。"
#, python-format
msgid "Interface %(name)s does not exist"
msgstr "接口 %(name)s 不存在"
#, python-format
msgid ""
"Failed to list interfaces. Invalid _inuse parameter. Supported options for "
"_inuse are: %(supported_inuse)s"
msgstr ""
"无法列示接口。无效 _inuse 参数。_inuse 的受支持选项为:%(supported_inuse)s"
#, python-format
msgid "Network %(name)s already exists"
msgstr "网络 %(name)s 已存在"
#, python-format
msgid "Network %(name)s does not exist"
msgstr "网络 %(name)s 不存在"
#, python-format
msgid "Subnet %(subnet)s specified for network %(network)s is not valid."
msgstr "对网络 %(network)s 指定的子网 %(subnet)s 无效。"
msgid "Specify a network interface to create bridged or macvtap networks."
msgstr "指定用于创建桥接网络或 macvtap 网络的网络接口。"
#, python-format
msgid "Unable to delete or update active network %(name)s"
msgstr "无法删除或更新活动网络 %(name)s"
#, python-format
msgid "Interface %(iface)s specified for network %(network)s is already in use"
msgstr "为网络 %(network)s 指定的接口 %(iface)s 已在使用中"
msgid "Interface should be bare NIC, bonding or bridge device."
msgstr "接口应该是空的 NIC、bonding 或网桥设备。"
#, python-format
msgid "Unable to create or update network %(name)s. Details: %(err)s"
msgstr "无法创建或更新网络 %(name)s。详细信息:%(err)s"
#, python-format
msgid "Unable to find a free IP address for network '%(name)s'"
msgstr "找不到网络“%(name)s”的可用 IP 地址"
#, python-format
msgid "The interface %(iface)s already exists."
msgstr "接口 %(iface)s 已存在。"
msgid "Network name must be a string without slashes (/) or quotes (\")"
msgstr "网络名必须是不带斜杠 (/) 或引号 (\") 的字符串"
msgid ""
"Supported network types are isolated, NAT, macvtap, bridge, vepa and "
"passthrough."
msgstr ""
"受支持的网络类型为:isolated、NAT、macvtap、bridge、vepa 和 passthrough。"
msgid "Network subnet must be a string with IP address and prefix or netmask"
msgstr "网络子网必须是具有 IP 地址以及前缀或网络掩码的字符串"
msgid "Network interfaces must be an array."
msgstr "网络接口必须为数组。"
msgid "Network VLAN ID must be an integer between 1 and 4094"
msgstr "网络 VLAN 标识必须为 1 到 4094 之间的整数"
msgid "Specify name and type to create a Network"
msgstr "指定名称和类型以创建网络"
#, python-format
msgid ""
"Unable to delete or update network %(name)s as it is linked to some virtual "
"machines (%(vms)s) and/or templates (%(tmpls)s)."
msgstr ""
#, python-format
msgid ""
"Unable to deactivate network %(name)s as it is linked to are some virtual "
"machines (%(vms)s) and/or templates (%(tmpls)s)."
msgstr ""
#, python-format
msgid "Bridge device %(name)s can not be the trunk device of a VLAN."
msgstr "网桥设备 %(name)s 不能是 VLAN 的主要设备。"
#, python-format
msgid "Failed to activate interface %(iface)s: %(err)s."
msgstr "未能激活接口 %(iface)s:%(err)s。"
#, python-format
msgid ""
"Failed to activate interface %(iface)s. Please check the physical link "
"status."
msgstr "未能激活接口 %(iface)s。请检查物理链路状态。"
#, python-format
msgid "Failed to start network %(name)s. Details: %(err)s"
msgstr "未能启动网络 %(name)s。详细信息:%(err)s"
#, python-format
msgid "Unable to redefine interface %(name)s. Details: %(err)s"
msgstr "无法重新定义接口 %(name)s。详细信息:%(err)s"
#, python-format
msgid "Unable to create bridge %(name)s. Details: %(err)s"
msgstr "无法创建网桥 %(name)s。详细信息:%(err)s"
msgid ""
"Unable to create bridge with NetworkManager enabled. Disable it and try "
"again."
msgstr "无法创建已启用网络管理器的网桥。请禁用它并重试。"
msgid "Interface should be bare NIC or bonding."
msgstr "接口应该是裸 NIC 或 bonding。"
msgid "Network interfaces parameter must contain at least one interface."
msgstr "网络接口参数必须包含至少一个接口。"
msgid "Only one interface is allowed for 'bridge' and 'macvtap' networks."
msgstr "“bridge”和“macvtap”网络只允许使用一个接口。"
msgid "Subnet is not a valid parameter for this type of virtual network."
msgstr "子网对于此类型的虚拟网络是无效参数。"
msgid ""
"VLAN ID and interfaces are not valid parameters for this type of virtual "
"network."
msgstr "VLAN 标识和接口对于此类型的虚拟网络是无效参数。"
#, python-format
msgid "Storage server %(server)s was not used by Kimchi"
msgstr "Kimchi 未使用存储服务器 %(server)s"
#, python-format
msgid "Distro '%(name)s' does not exist"
msgstr "Distro“%(name)s”不存在"
#, python-format
msgid "Node device '%(name)s' not found"
msgstr "找不到节点设备“%(name)s”"
msgid "Conflicting flag filters specified."
msgstr "指定的标志过滤器有冲突。"
msgid "Unable to choose a virtual machine name"
msgstr "无法选择虚拟机名称"
msgid "Cannot upgrade objectstore data."
msgstr "无法升级对象库数据。"
msgid "Invalid storage type. Types supported: 'cdrom', 'disk'"
msgstr "无效存储类型。受支持的类型为:“cdrom”和“disk”"
#, python-format
msgid "The path '%(value)s' is not a valid local/remote path for the device"
msgstr "路径“%(value)s”不是设备的有效本地/远程路径"
msgid "Only CDROM path can be update."
msgstr "只能更新 CDROM 路径。"
#, python-format
msgid ""
"The storage device %(dev_name)s does not exist in the virtual machine "
"%(vm_name)s"
msgstr "存储设备 %(dev_name)s 在虚拟机 %(vm_name)s 中不存在"
#, python-format
msgid "Error while creating new storage device: %(error)s"
msgstr "创建新存储设备时出错:%(error)s"
#, python-format
msgid "Error while updating storage device: %(error)s"
msgstr "更新存储设备时出错:%(error)s"
#, python-format
msgid "Error while removing storage device: %(error)s"
msgstr "除去存储设备时出错:%(error)s"
msgid "Do not support IDE device hot plug"
msgstr "不支持 IDE 设备热插拔"
msgid ""
"Specify type and path or type and pool/volume to add a new virtual machine "
"disk"
msgstr "指定类型和路径或者类型和池/卷以添加新的虚拟机磁盘"
msgid "Specify path to update virtual machine disk"
msgstr "指定路径以更新虚拟机磁盘"
#, python-format
msgid "Controller type %(type)s limitation of %(limit)s devices reached"
msgstr "已达到控制器类型 %(type)s 限制 %(limit)s"
#, python-format
msgid "Cannot retrieve disk path information for given pool/volume: %(error)s"
msgstr "无法检索给定池/卷的磁盘路径信息:%(error)s"
msgid "Volume already in use by other virtual machine."
msgstr "其他虚拟机已在使用卷。"
msgid ""
"Only one of path or pool/volume can be specified to add a new virtual "
"machine disk"
msgstr "只能指定路径或池/卷中的一个以添加新的虚拟机磁盘"
#, python-format
msgid ""
"Volume chosen with format %(format)s does not fit in the storage type "
"%(type)s"
msgstr "格式为 %(format)s 的所选卷无法拟合存储类型 %(type)s"
msgid "On s390x arch one of pool, path of dir_path must be specified"
msgstr "在 s390x 体系结构上,必须指定池和路径 dir_path 的其中之一"
msgid ""
"On s390x arch 'format' must be specified while attaching disk to virtual "
"machine"
msgstr "在 s390x 体系结构上,将磁盘连接至虚拟机时必须指定“format”"
#, python-format
msgid "Virtual disk already exists on the system: %(disk_path)s"
msgstr "虚拟盘已存在于系统上:%(disk_path)s"
#, python-format
msgid ""
"Unable to create snapshot '%(name)s' on virtual machine '%(vm)s'. Details: "
"%(err)s"
msgstr "无法在以下虚拟机上创建快照“%(name)s”:“%(vm)s”。详细信息:%(err)s"
#, python-format
msgid "Snapshot '%(name)s' does not exist on virtual machine '%(vm)s'."
msgstr "快照“%(name)s”在虚拟机“%(vm)s”上不存在。"
#, python-format
msgid ""
"Unable to retrieve snapshot '%(name)s' on virtual machine '%(vm)s'. Details: "
"%(err)s"
msgstr "无法在以下虚拟机上检索快照“%(name)s”:“%(vm)s”。详细信息:%(err)s"
#, python-format
msgid "Unable to list snapshots on virtual machine '%(vm)s'. Details: %(err)s"
msgstr "无法列示虚拟机“%(vm)s”上的快照。详细信息:%(err)s"
#, python-format
msgid ""
"Unable to delete snapshot '%(name)s' on virtual machine '%(vm)s'. Details: "
"%(err)s"
msgstr "无法删除以下虚拟机上的快照“%(name)s”:“%(vm)s”。详细信息:%(err)s"
#, python-format
msgid ""
"Unable to retrieve current snapshot of virtual machine '%(vm)s'. Details: "
"%(err)s"
msgstr "无法检索虚拟机“%(vm)s”的当前快照。详细信息:%(err)s"
#, python-format
msgid ""
"Unable to revert virtual machine '%(vm)s' to snapshot '%(name)s'. Details: "
"%(err)s"
msgstr "无法将虚拟机“%(vm)s”还原到快照“%(name)s”。详细信息:%(err)s"
#, python-format
msgid ""
"Unable to create snapshot of virtual machine '%(vm)s' because it contains a "
"disk with format '%(format)s'; only 'qcow2' is supported."
msgstr ""
"无法创建虚拟机“%(vm)s”的快照,因为它包含格式为“%(format)s”的磁盘;仅“qcow2”受"
"支持。"
msgid ""
"The number of vCPUs must be less than or equal the maximum number of vCPUs "
"specified."
msgstr "vCPU 数必须小于或等于所指定最大 vCPU 数。"
msgid ""
"When CPU topology is defined, maximum number of vCPUs must be a product of "
"sockets, cores, and threads."
msgstr "定义 CPU 拓扑后,最大 vCPU 数必须为套接字数、核心数和线程数的乘积。"
msgid "This host (or current configuration) does not allow CPU topology."
msgstr "此主机(或当前配置)不允许使用 CPU 拓扑。"
msgid "The maximum number of vCPUs is too large for this system."
msgstr "最大 vCPU 数对于此系统太大。"
msgid ""
"When CPU topology is defined, CPUs must be a multiple of the 'threads' "
"number defined."
msgstr ""
msgid ""
"When CPU topology is specified, sockets, cores and threads are required "
"paramaters."
msgstr "指定 CPU 拓扑后,sockets、cores 和 threads 是必需参数。"
msgid ""
"Parameter 'cpu_info' expects an object with fields among: 'vcpus', "
"'maxvcpus', 'topology'."
msgstr ""
"参数“cpu_info”需要带有以下字段的对象:“vcpus”、“maxvcpus”和“topology”。"
msgid ""
"Parameter 'topology' expects an object with fields among: 'sockets', "
"'cores', 'threads'."
msgstr "参数“topology”需要带有以下字段的对象:“sockets”、“cores”和“threads”。"
msgid "Unable to update Max CPU or CPU topology when guest is running."
msgstr ""
#, python-format
msgid "Unable to hot plug/unplug CPUs. Details: %(err)s"
msgstr "无法列示存储池。详细信息:%(err)s"
#, python-format
msgid "Invalid volume group name parameter: %(name)s."
msgstr "无效卷组名称参数:%(name)s。"
msgid ""
"Unable to establish connection with libvirt. Please check your libvirt URI "
"which is often defined in /etc/libvirt/libvirt.conf"
msgstr ""
"无法建立与 libvirt 的连接。请检查 libvirt URI,它通常是在 /etc/libvirt/"
"libvirt.conf 中定义的"
msgid ""
"Libvirt service is not active. Please start the libvirt service in your host "
"system."
msgstr "Libvirt 服务不活动。请在主机系统中启动 libvirt 服务。"
msgid "Failed to register the default event implementation."
msgstr "无法注册缺省事件实现。"
msgid "Failed to register timeout event."
msgstr "无法注册超时事件。"
msgid "Failed to Run the default event implementation."
msgstr "无法运行缺省事件实现。"
#, python-format
msgid ""
"I/O error on guest '%(vm)s': storage pool out of space for %(devAlias)s "
"(%(srcPath)s)."
msgstr ""
"访客“%(vm)s”上发生 I/O 错误:存储池空间不足,无法供 %(devAlias)s "
"(%(srcPath)s) 使用。"
#, python-format
msgid "Create virtual network '%(name)s' type '%(connection)s'"
msgstr "创建虚拟网络“%(name)s”类型“%(connection)s”"
#, python-format
msgid "Remove virtual network '%(ident)s'"
msgstr "移除虚拟网络“%(ident)s”"
#, python-format
msgid "Update virtual network '%(ident)s'"
msgstr "更新虚拟网络“%(ident)s”"
#, python-format
msgid "Activate virtual network '%(ident)s'"
msgstr "激活虚拟网络“%(ident)s”"
#, python-format
msgid "Deactivate virtual network '%(ident)s'"
msgstr "取消激活虚拟网络“%(ident)s”"
#, python-format
msgid "Create storage pool '%(name)s' type '%(type)s'"
msgstr "创建存储池“%(name)s”类型“%(type)s”"
#, python-format
msgid "Remove storage pool '%(ident)s'"
msgstr "移除存储池“%(ident)s”"
#, python-format
msgid "Update storage pool '%(ident)s'"
msgstr "更新存储池“%(ident)s”"
#, python-format
msgid "Activate storage pool '%(ident)s'"
msgstr "激活存储池“%(ident)s”"
#, python-format
msgid "Deactivate storage pool '%(ident)s'"
msgstr "取消激活存储池“%(ident)s”"
#, python-format
msgid "Create snapshot '%(name)s' at guest '%(vm)s'"
msgstr "在访客“%(vm)s”上创建快照“%(name)s”"
#, python-format
msgid "Remove snapshot '%(ident)s' from guest '%(vm)s'"
msgstr "从访客“%(vm)s”中移除快照“%(ident)s”"
#, python-format
msgid "Revert guest '%(vm)s' to snapshot '%(ident)s'"
msgstr "将访客“%(vm)s”还原至快照“%(ident)s”"
#, python-format
msgid "Create template '%(name)s'"
msgstr "创建模板“%(name)s”"
#, python-format
msgid "Remove template '%(ident)s'"
msgstr "移除模板“%(ident)s”"
#, python-format
msgid "Update template '%(ident)s'"
msgstr "更新模板“%(ident)s”"
#, python-format
msgid "Clone template '%(ident)s'"
msgstr "克隆模板“%(ident)s”"
#, python-format
msgid "Create guest '%(name)s' from template '%(template)s'"
msgstr "通过模板“%(template)s”创建访客“%(name)s”"
#, python-format
msgid "Remove guest '%(ident)s'"
msgstr "移除访客“%(ident)s”"
#, python-format
msgid "Edit guest '%(ident)s'"
msgstr "编辑访客“%(ident)s”"
#, python-format
msgid "Start guest '%(ident)s'"
msgstr "启动访客“%(ident)s”"
#, python-format
msgid "Power off guest '%(ident)s'"
msgstr "关闭访客“%(ident)s”电源"
#, python-format
msgid "Shutdown guest '%(ident)s'"
msgstr "关闭访客“%(ident)s”"
#, python-format
msgid "Restart guest '%(ident)s'"
msgstr "重新启动访客“%(ident)s”"
#, python-format
msgid "Connect to guest '%(ident)s' through novnc/spice"
msgstr "通过 novnc/spice 连接至访客“%(ident)s”"
#, python-format
msgid "Clone guest '%(ident)s'"
msgstr "克隆访客“%(ident)s”"
#, python-format
msgid "Migrate guest '%(ident)s' to '%(remote_host)s'"
msgstr "将访客“%(ident)s”迁移至“%(remote_host)s”"
#, python-format
msgid "Suspend guest '%(ident)s'"
msgstr "暂挂访客“%(ident)s”"
#, python-format
msgid "Resume guest '%(ident)s'"
msgstr "恢复访客“%(ident)s”"
#, python-format
msgid "Connect to guest '%(ident)s' through serial"
msgstr "通过串行线路连接至访客“%(ident)s”"
#, python-format
msgid "Attach host device '%(name)s' to guest '%(vmid)s'"
msgstr "将主机设备“%(name)s”连接至访客“%(vmid)s”"
#, python-format
msgid "Detach host device '%(ident)s' from guest '%(vmid)s'"
msgstr "从访客“%(vmid)s”拆离主机设备“%(ident)s”"
#, python-format
msgid "Attach network interface '%(network)s' to guest '%(vm)s'"
msgstr "将网络接口“%(network)s”连接至访客“%(vm)s”"
#, python-format
msgid "Detach network interface '%(ident)s' from guest '%(vm)s'"
msgstr "从访客“%(vm)s”拆离网络接口“%(ident)s”"
#, python-format
msgid "Update network interface '%(ident)s' at guest '%(vm)s'"
msgstr "更新访客“%(vm)s”上的网络接口“%(ident)s”"
#, python-format
msgid "Attach %(type)s storage '%(path)s' to guest '%(vm)s'"
msgstr "将 %(type)s 存储器“%(path)s”连接至访客“%(vm)s”"
#, python-format
msgid "Remove storage '%(ident)s' from guest '%(vm)s'"
msgstr "从访客“%(vm)s”中移除存储器“%(ident)s”"
#, python-format
msgid "Update storage '%(ident)s' at guest '%(vm)s'"
msgstr "更新访客“%(vm)s”上的存储器“%(ident)s”"
#, python-format
msgid "Create storage volume '%(name)s' at pool '%(pool)s'"
msgstr "在池“%(pool)s”上创建存储卷“%(name)s”"
#, python-format
msgid "Remove storage volume '%(ident)s' from pool '%(pool)s'"
msgstr "从池“%(pool)s”中移除存储卷“%(ident)s”"
#, python-format
msgid "Update storage volume '%(ident)s' at pool '%(pool)s'"
msgstr "在池“%(pool)s”上更新存储卷“%(ident)s”"
#, python-format
msgid "Wipe storage volume '%(ident)s' off pool '%(pool)s'"
msgstr "从池“%(pool)s”中擦除存储卷“%(ident)s”"
#, python-format
msgid "Resize storage volume '%(ident)s' at pool '%(pool)s' with size %(size)s"
msgstr "将池“%(pool)s”上的存储卷“%(ident)s”调整为 %(size)s 大小"
#, python-format
msgid "Clone storage volume '%(ident)s' at pool '%(pool)s'"
msgstr "在池“%(pool)s”上克隆存储卷“%(ident)s”"
msgid "Create a New Virtual Machine"
msgstr "创建新虚拟机"
msgid "Virtual Machine Name"
msgstr "虚拟机名称"
msgid ""
"The name used to identify the virtual machine. If omitted, a name will be "
"chosen based on the template used."
msgstr "用于标识虚拟机的名称。如果省略,那么将根据所使用模板选择名称。"
msgid "Please create a template first."
msgstr "请先创建模板。"
msgid "Create a Template"
msgstr "创建模板"
msgid "Please choose a template."
msgstr "请选择模板。"
msgid "This template has invalid parameters."
msgstr "此模板具有无效参数。"
msgid "This template has invalid parameters"
msgstr "此模板具有无效参数"
msgid "OS"
msgstr "操作系统"
msgid "Version"
msgstr "版本"
msgid "Current CPUs"
msgstr "当前 CPU 数"
msgid "Memory"
msgstr "内存"
msgid "Create"
msgstr "创建"
msgid "Creating..."
msgstr "正在创建..."
msgid "Cancel"
msgstr "取消"
msgid "Clone a Guest"
msgstr "克隆访客"
msgid ""
"When the target guest has SCSI or iSCSI volumes, they will be cloned on the "
"default storage pool. The same will happen when the target pool does not "
"have enough space to clone the volumes. Do you want to continue?"
msgstr ""
"目标访客具有 SCSI 或 iSCSI 卷时,将在缺省存储池上克隆这些卷。如果目标池没有足"
"够空间来克隆这些卷,那么会发生同样的事情。要继续吗?"
msgid "Number of times to clone"
msgstr "要克隆的次数"
msgid "Continue"
msgstr "继续"
msgid "Edit Guest"
msgstr "编辑访客"
msgid "General"
msgstr "常规"
msgid "Storage"
msgstr "存储器"
msgid "Interface"
msgstr "接口"
msgid "Permission"
msgstr "许可权"
msgid "Pci"
msgstr "PCI"
msgid "Snapshot"
msgstr "快照"
msgid "Processor"
msgstr "处理器"
msgid "Name"
msgstr "名称"
msgid "Memory (MB)"
msgstr "内存 (MB)"
msgid "More"
msgstr "更多"
msgid "Max Memory (MB)"
msgstr "最大内存 (MB)"
msgid "Host does not support memory hotplug"
msgstr "主机不支持内存热插拔"
msgid "Icon"
msgstr "图标"
msgid "Console"
msgstr "控制台"
msgid "Nothing selected"
msgstr "未选择任何内容"
msgid "sclp"
msgstr "sclp"
msgid "virtio"
msgstr "virtio"
msgid ""
"Select which items for boot order and grad them when needed to order them. "
"At least one option must be selected."
msgstr ""
msgid "Add"
msgstr "添加"
msgid "Device"
msgstr "设备"
msgid "Path"
msgstr "路径"
msgid "Actions"
msgstr "操作"
msgid "Network"
msgstr "网络"
msgid "Type"
msgstr "类型"
msgid "MAC Address"
msgstr "MAC 地址"
msgid "IP Address"
msgstr "IP 地址"
msgid "Network/Interface"
msgstr "网络/接口"
msgid "Mode"
msgstr "方式"
msgid "Available system users and groups"
msgstr "可用的系统用户和组"
msgid "Users"
msgstr "用户"
msgid "Groups"
msgstr "组"
msgid "Selected system users and groups"
msgstr "所选系统用户和组"
msgid "User"
msgstr "用户"
msgid "All"
msgstr "所有"
msgid "To Add"
msgstr "待添加"
msgid "Added"
msgstr "已添加"
msgid "Filter"
msgstr "过滤器"
msgid "Status"
msgstr "状态"
msgid "Product"
msgstr "产品"
msgid "Vendor"
msgstr "供应商"
msgid "Loading"
msgstr "正在装入"
msgid "Created"
msgstr "已创建"
msgid "Current CPU Number"
msgstr "当前 CPU 数"
msgid ""
"Current CPU must be equal or lower than the Maximum CPU value. If a topology "
"is set, it must be also be a multiple of the 'threads' value."
msgstr ""
msgid "Max CPU"
msgstr "最大 CPU 数"
msgid ""
"Unable to edit maximum CPU or CPU topology when editing a running or paused "
"virtual machine."
msgstr ""
msgid ""
"If a topology is set, this value will be the product of sockets * times * "
"cores."
msgstr ""
msgid "Manually set CPU topology"
msgstr "手动设置 CPU 拓扑"
msgid "Sockets"
msgstr ""
msgid "Cores"
msgstr "核心数"
msgid "Threads"
msgstr "线程数"
msgid "Save"
msgstr "保存"
msgid "Replace"
msgstr "替换"
msgid "Detach"
msgstr "拆离"
msgid "Remove"
msgstr "移除"
msgid "Edit"
msgstr "编辑"
msgid "LDAP User ID,e.g.foo@foo.com"
msgstr "LDAP 用户标识,如 foo@foo.com"
msgid "Revert"
msgstr "还原"
msgid "Running"
msgstr "正在运行"
msgid "Disconnected"
msgstr "已断开连接"
msgid "Starting"
msgstr "正在启动"
msgid "Crashed"
msgstr "已崩溃"
msgid "Unknown"
msgstr "未知"
msgid "Paused"
msgstr "已暂停"
msgid "Suspended"
msgstr "已暂挂"
msgid "Resetting"
msgstr "正在重置"
msgid "View Console"
msgstr "查看控制台"
msgid "View Serial"
msgstr "查看序列号"
msgid "Clone"
msgstr "克隆"
msgid "Migrate"
msgstr "迁移"
msgid "Reset"
msgstr "重置"
msgid "Pause"
msgstr "暂停"
msgid "Resume"
msgstr "恢复"
msgid "Shut Down"
msgstr "关闭"
msgid "Start"
msgstr "启动"
msgid "Power Off"
msgstr "断电"
msgid "Delete"
msgstr "删除"
msgid "No Data Available"
msgstr "没有可用数据"
msgid "Processors Utilization"
msgstr "处理器利用率"
msgid "Memory Utilization"
msgstr "内存利用率"
msgid "Storage I/O"
msgstr "存储器 I/O"
msgid "Network I/O"
msgstr "网络 I/O"
msgid "Migrate a Guest"
msgstr "迁移访客"
msgid ""
"Disclaimer: This process cannot be stopped after started, can take a long "
"time to complete and will turn off the VM on this Hypervisor when it is "
"successfully migrated to the remote destination."
msgstr ""
"免责声明:此进程启动后无法停止,可能需要很长时间完成,成功迁移至远程目标后将"
"在此管理程序上关闭 VM。"
msgid "Remote Server"
msgstr "远程服务器"
msgid "IP Address or Hostname"
msgstr "IP 地址或主机名"
msgid ""
"The following fields are optional. Fill them if you want Kimchi to setup a "
"password-less ssh session between the localhost and the remote host. The "
"setup process will only be successful if the user has 'SUDO ALL' permission "
"in the remote machine."
msgstr ""
"下列字段是可选的。如果希望 Kimchi 设置本地主机与远程主机之间的无密码 ssh 会"
"话,请填写这些字段。仅当用户在远程机器中具有“SUDO ALL”许可权时,此设置过程才"
"会成功。"
msgid "Username of the remote host"
msgstr "远程主机的用户名"
msgid "Password"
msgstr "密码"
msgid "Password of the user in the remote host"
msgstr "远程主机中的用户的密码"
msgid "Use RDMA transport"
msgstr ""
msgid ""
"Check this option only if RDMA is properly configured in both source and "
"destination hosts, otherwise migration will fail."
msgstr ""
msgid "Delete this VM when the migration is completed"
msgstr "迁移完成时删除此 VM"
msgid "Add a Storage Device to VM"
msgstr "将存储设备添加至 VM"
msgid "Device Type"
msgstr "设备类型"
msgid ""
"The device type. Currently, \"cdrom\" and \"disk\" are supported. If the "
"guest is running, only \"disk\" is supported."
msgstr ""
"设备类型。目前,“cdrom”和“disk”受支持。如果访客正在运行,那么仅“disk”受支持。"
msgid "Create a new disk"
msgstr "创建新的磁盘"
msgid "Select an existing disk"
msgstr "选择现有磁盘"
msgid "Source"
msgstr "源"
msgid "Storage based on Libvirt pool or direct block device"
msgstr "基于 Libvirt 池的存储器或直接块设备"
msgid "Storage Pool"
msgstr "存储池"
msgid "Storage pool to create the volume in"
msgstr "用于创建卷的存储池"
msgid "Disk Size (GB)"
msgstr "磁盘大小 (GB)"
msgid "New disk size to be created"
msgstr "要创建的新磁盘大小"
msgid "Format"
msgstr "格式"
msgid "Format of the new disk to be created"
msgstr "要创建的新磁盘的格式"
msgid "Directory Path"
msgstr "目录路径"
msgid "Provide a directory path"
msgstr "提供目录路径"
msgid "Storage pool in which the volume is located in"
msgstr "卷所在的存储池"
msgid "Storage Volume"
msgstr "存储卷"
msgid "Storage volume to be attached"
msgstr "要连接的存储卷"
msgid "Disk Path"
msgstr "磁盘路径"
msgid "Provide a block device"
msgstr "提供块设备"
msgid "File Path"
msgstr "文件路径"
msgid "The ISO file path in the server for CDROM."
msgstr "CDROM 服务器中的 ISO 文件。"
msgid "Attach"
msgstr "连接"
msgid "Host"
msgstr "主机"
msgid "Guests"
msgstr "访客"
msgid "Templates"
msgstr "模板"
msgid "This is not a valid Linux path"
msgstr "这是无效 Linux 路径"
msgid "Unable to read file."
msgstr "无法读取文件。"
msgid "Error while uploading file."
msgstr "上载文件时出错。"
msgid "Delete Confirmation"
msgstr "删除确认"
msgid "OK"
msgstr "确定"
msgid "Confirm"
msgstr "确认"
msgid "Warning"
msgstr "警告"
msgid "Cloning..."
msgstr "正在克隆..."
msgid "Saving..."
msgstr "正在保存..."
msgid "Migrating..."
msgstr "正在迁移..."
msgid "No ISO found"
msgstr "找不到 ISO"
msgid "Add Template"
msgstr "添加模板"
msgid "This may take a long time. Do you want to continue?"
msgstr "可能需要较长时间。要继续吗?"
msgid ""
"This will permanently delete the %1 template. Would you like to continue?"
msgstr "这将永久删除 %1 模板。要继续吗?"
msgid "View Table"
msgstr "查看表"
msgid "View Gallery"
msgstr "查看库"
msgid "Not Available"
msgstr "不可用"
msgid "Please check the invalid Storage Pools"
msgstr "请检查无效存储池"
msgid "Please check the invalid Storage Pools or Paths"
msgstr "请检查无效存储池或路径"
msgid "macvtap"
msgstr "macvtap"
msgid "ovs"
msgstr "ovs"
msgid "network"
msgstr "网络"
msgid ""
"This will delete the %1 virtual machine and its virtual disks. This "
"operation cannot be undone. Would you like to continue?"
msgstr "这将删除 %1 虚拟机及其虚拟盘。此操作无法撤销。要继续吗?"
msgid "Power off Confirmation"
msgstr "断电确认"
msgid ""
"This action may produce undesirable results, for example unflushed disk "
"cache in the %1 guest. Would you like to continue?"
msgstr ""
"此操作可能产生意外结果,例如,%1 访客中出现未刷新的磁盘高速缓存。要继续吗?"
msgid "Reset Confirmation"
msgstr "重置确认"
msgid ""
"There is a risk of data loss caused by reset without the %1 guest OS "
"shutdown. Would you like to continue?"
msgstr ""
"如果不关闭 %1 访客操作系统,那么会有因为重置而导致的数据丢失风险。要继续吗?"
msgid "Shut Down Confirmation"
msgstr "关闭确认"
msgid ""
"Note the %1 guest OS may ignore this request. Would you like to continue?"
msgstr "注意,%1 访客操作系统可能会忽略此请求。要继续吗?"
msgid "Virtual Machine delete Confirmation"
msgstr "虚拟机删除确认"
msgid ""
"The %1 virtual machine is not persistent. Power Off will delete it. Continue?"
msgstr "%1 虚拟机不是持久虚拟机。断电会将其删除。要继续吗?"
msgid "Add Guest"
msgstr ""
msgid "Input is not a number"
msgstr "输入不是数字"
msgid "Memory value cannot be higher than Max Memory value"
msgstr "内存值不能高于最大内存值"
msgid ""
"For better performance it is recommended a threads per core value not "
"greater than %1."
msgstr ""
msgid ""
"This CDROM will be detached permanently and you can re-attach it. Continue "
"to detach it?"
msgstr "此 CDROM 将永久拆离,您可重新连接该 CDROM。要继续拆离吗?"
msgid "Attaching..."
msgstr "正在连接..."
msgid ""
"This disk will be detached permanently and you can re-attach it. Continue to "
"detach it?"
msgstr "此磁盘将永久拆离,您可重新连接该磁盘。要继续拆离吗?"
msgid "interface:"
msgstr "接口:"
msgid "address:"
msgstr "地址:"
msgid "link_type:"
msgstr "链接类型:"
msgid "block:"
msgstr "块:"
msgid "drive_type:"
msgstr "驱动类型:"
msgid "model:"
msgstr "型号:"
msgid "Affected devices:"
msgstr "受影响的设备:"
msgid "Less"
msgstr "更少"
msgid "Successfully attached device to VM"
msgstr "已将设备成功连接至 VM"
msgid "Successfully detached device from VM"
msgstr "已成功从 VM 拆离设备"
msgid "Following devices will be affected, confirm?"
msgstr "以下设备将受影响,是否确认?"
msgid "Bridge"
msgstr "网桥"
msgid "Vepa"
msgstr "Vepa"
msgid "None"
msgstr "无"
msgid "unavailable"
msgstr "不可用"
msgid ""
"This action will interrupt network connectivity for any virtual machine that "
"depend on the %1 network."
msgstr "此操作将中断依赖于 %1 网络的任何虚拟机的网络连接。"
msgid "Add Network"
msgstr ""
msgid ""
"The %1 network is not persistent. Instead of stop, this action will "
"permanently delete it. Would you like to continue?"
msgstr ""
"%1 网络不是持久网络。此操作将永久删除此网络,而不是停止此网络。要继续吗?"
msgid ""
"The bridged VLAN tag may not work well with NetworkManager enabled. You "
"should consider disabling it."
msgstr ""
"在启用了网络管理器的情况下,桥接 VLAN 标记的工作情况可能不良。应考虑将其禁"
"用。"
msgid ""
"This will permanently delete the %1 storage pool. Would you like to continue?"
msgstr "这将永久删除 %1 存储池。要继续吗?"
msgid "This storage pool is empty."
msgstr "此存储池为空。"
msgid ""
"It will format your disk and you will loose any data in there, are you sure "
"to continue? "
msgstr "它将格式化磁盘,并且您将丢失其中的所有数据,确定要继续吗?"
msgid "SCSI Fibre Channel"
msgstr "SCSI 光纤通道"
msgid "No SCSI adapters found."
msgstr "找不到任何 SCSI 适配器。"
msgid "Loading iSCSI targets..."
msgstr "正在装入 iSCSI 目标..."
msgid "No iSCSI found. Please input one."
msgstr "找不到 iSCSI。请输入一个。"
msgid "Failed to load iSCSI targets."
msgstr "无法装入 iSCSI 目标。"
msgid "Would you like to continue?"
msgstr "要继续吗?"
msgid "This will permanently delete the following storage volumes: %1"
msgstr "这将永久删除以下存储卷:%1"
msgid "No available partitions found."
msgstr "找不到任何可用分区。"
msgid ""
"The %1 storage pool is not persistent. Instead of deactivate, this action "
"will permanently delete it. Would you like to continue?"
msgstr ""
"%1 存储池不是持久存储池。此操作将永久删除此存储池,而不是取消激活此存储池。要"
"继续吗?"
msgid "Unable to retrieve partitions information."
msgstr "无法检索分区信息。"
msgid "In progress..."
msgstr "正在进行..."
msgid "Failed!"
msgstr "失败!"
msgid "No LVM found in the system."
msgstr "在系统中找不到 LVM。"
msgid "This will permanently wipe the following storage volumes: %1"
msgstr "这将永久擦除以下存储卷:%1"
msgid "Wipe Confirmation"
msgstr "擦除确认"
msgid "Select one or more partitions to be added to the logical pool %1:"
msgstr "选择一个或多个要添加到逻辑池 %1 的分区:"
msgid "Add Storage"
msgstr "添加存储器"
msgid "DIR"
msgstr "DIR"
msgid "NFS"
msgstr "NFS"
msgid "iSCSI"
msgstr "iSCSI"
msgid "LOGICAL"
msgstr "LOGICAL"
msgid "device"
msgstr "设备"
msgid "path"
msgstr "路径"
msgid "size (GiB)"
msgstr "大小 (GiB)"
msgid "free size (GiB)"
msgstr "可用大小 (GiB)"
msgid "Invalid NFS mount path."
msgstr "NFS 安装路径无效。"
msgid "No logical device selected."
msgstr "未选择任何逻辑设备。"
msgid "This is not a valid Server Name or IP. Please, modify it."
msgstr "这不是有效的服务器名称或 IP。请对其进行修改。"
msgid "CDROM path needs to be a valid local/remote path and cannot be blank."
msgstr "CDROM 路径必须是有效的本地/远程路径,并且不能为空白。"
msgid "Disk pool or volume cannot be blank."
msgstr "磁盘池或卷不能为空白。"
msgid ""
"Disk size or Format or Directory path cannot be blank and Directory path "
"needs to be a valid local/remote path."
msgstr "磁盘大小、格式或目录路径不能为空白,目录路径必须为有效本地/远程路径。"
msgid "Disk path needs to be a valid local/remote path and cannot be blank."
msgstr "磁盘路径必须是有效的本地/远程路径,并且不能为空白。"
msgid "Storage pool or Disk size or Format cannot be blank."
msgstr "存储池、磁盘大小或格式不能为空白。"
msgid "cdrom"
msgstr "cdrom"
msgid "disk"
msgstr "磁盘"
msgid "Pool"
msgstr "池"
msgid "qcow"
msgstr "qcow"
msgid "qcow2"
msgstr "qcow2"
msgid "qed"
msgstr "qed"
msgid "raw"
msgstr "原始"
msgid "vmdk"
msgstr "vmdk"
msgid "vpc"
msgstr "vpc"
msgid "Create a network"
msgstr "创建网络"
msgid "Network Name"
msgstr "网络名称"
msgid "Name should not contain '/' and '\"'."
msgstr "名称不应包含“/”和“\"”。"
msgid "Network Type"
msgstr "网络类型"
msgid "Isolated: no external network connection"
msgstr "隔离:没有外部网络连接"
msgid "NAT: outbound physical network connection only"
msgstr "NAT:仅适用于出站物理网络连接"
msgid "Macvtap: Virtual machines are connected to physical network directly"
msgstr "Macvtap:虚拟机直接连接至物理网络"
msgid ""
"Passthrough: Virtual machines are connected using a macvtap connection in "
"passthrough mode."
msgstr "Passthrough:虚拟机以传递方式使用 macvtap 连接进行连接。"
msgid ""
"VEPA: special mode where virtual machines are connected to a VEPA-enabled "
"switch"
msgstr "VEPA:特殊方式,虚拟机以此方式连接至支持 VEPA 的交换机"
msgid "Bridged: Virtual machines are connected through a network bridge"
msgstr "Bridged:虚拟机通过网桥连接"
msgid "Destination"
msgstr "目标"
msgid "Select an Interface"
msgstr "选择接口"
msgid "Enable VLAN"
msgstr "启用 VLAN"
msgid "VLAN ID"
msgstr "VLAN 标识"
msgid "Edit Network"
msgstr "编辑网络"
msgid "Address Space"
msgstr "地址空间"
msgid "Define a New Storage Pool"
msgstr "定义新存储池"
msgid "Storage Pool Name"
msgstr "存储池名称"
msgid ""
"The name used to identify the storage pools, and it should not be empty."
msgstr "用于标识存储池的名称,且该名称不能为空。"
msgid "Storage Pool Type"
msgstr "存储池类型"
msgid "Storage Path"
msgstr "存储路径"
msgid ""
"The path of the Storage Pool. Each Storage Pool must have a unique path."
msgstr "存储池的路径。每个存储池必须具有唯一路径。"
msgid ""
"Kimchi will try to create the directory when it does not already exist in "
"your system."
msgstr "Kimchi 将尝试创建目录(如果您的系统中还没有目录)。"
msgid "NFS Server IP"
msgstr "NFS 服务器 IP"
msgid "NFS server IP or hostname. It can be input or chosen from history."
msgstr "NFS 服务器 IP 或主机名。您可输入,也可从历史记录中选择。"
msgid "NFS Path"
msgstr "NFS 路径"
msgid "The NFS exported path on NFS server."
msgstr "NFS 服务器中的 NFS 已导出的路径。"
msgid "Create from existing LVM"
msgstr "通过现有 LVM 创建"
msgid "Create from raw disk"
msgstr "通过原始磁盘创建"
msgid "Looking for existing lvms ..."
msgstr "正在查找现有 lvm..."
msgid "Looking for available partitions ..."
msgstr "正在查找可用分区..."
msgid "iSCSI Server"
msgstr "iSCSI 服务器"
msgid "Server"
msgstr "服务器"
msgid "Port"
msgstr "端口"
msgid "iSCSI server IP or hostname. It should not be empty."
msgstr "iSCSI 服务器 IP 或主机名。它不应为空。"
msgid "Target"
msgstr "目标"
msgid "The iSCSI target on iSCSI server"
msgstr "iSCSI 服务器上的 iSCSI 目标"
msgid "Add iSCSI Authentication"
msgstr "添加 iSCSI 认证"
msgid "User Name"
msgstr "用户名"
msgid "SCSI Adapter"
msgstr "SCSI 适配器"
msgid "Please, wait..."
msgstr "请稍等..."
msgid "Add a Volume to Storage Pool"
msgstr "将卷添加至存储池"
msgid "Fetch from remote URL"
msgstr "从远程 URL 中访存"
msgid "Enter the remote URL here."
msgstr "在此处输入远程 URL。"
msgid "Upload a file"
msgstr "上载文件"
msgid "Choose the file you want to upload."
msgstr "选择要上载的文件。"
msgid "Resize Volume"
msgstr "调整卷大小"
msgid "Size"
msgstr "大小"
msgid "The total space which can be used to store data. The unit is megabytes."
msgstr "可用于存储数据的总空间。单位为兆字节。"
msgid "Ok"
msgstr "确定"
msgid "Template Name"
msgstr "模板"
msgid ""
"The name used to identify the template. If omitted, a name will be "
"automatically chosen."
msgstr "用于标识虚拟机的名称。如果省略,那么将根据所使用的模板选择一个名称。"
msgid ""
"When selecting more than one Image Template, a name will be automatically "
"chosen for each Image Template selected."
msgstr ""
msgid "Where is the source media for this template? "
msgstr "此模板的源介质在哪里?"
msgid "Image Template"
msgstr "映像模板"
msgid "Netboot Template"
msgstr "网络引导模板"
msgid "File Path:"
msgstr "文件路径:"
msgid "Search ISOs"
msgstr "搜索 ISO"
msgid "The following ISOs are available:"
msgstr "以下 ISO 可用:"
msgid "QEMU does not have enough permission to work with this file"
msgstr "QEMU 没有足够的许可权来处理此文件"
msgid "Search more ISOs"
msgstr "搜索更多 ISO"
msgid "Loading..."
msgstr "正在装入..."
msgid "Edit Template"
msgstr "编辑模板"
msgid "CDROM"
msgstr "CDROM"
msgid "Image File"
msgstr "映像文件"
msgid "Graphics"
msgstr "图形"
msgid "Disk(GB)"
msgstr "磁盘 (GB)"
msgid "Disk Format"
msgstr "磁盘格式"
msgid "Add Interface"
msgstr "添加接口"
msgid "pool"
msgstr "池"
msgid "bridge"
msgstr "网桥"
msgid "vepa"
msgstr "vepa"
msgid "State"
msgstr "状态"
msgid "Guest Name ID"
msgstr "访客名称标识"
msgid "OS Type"
msgstr "操作系统类型"
msgid "VNC"
msgstr "VNC"
msgid "No guests found."
msgstr "找不到访客。"
msgid "Stop"
msgstr ""
msgid "Location"
msgstr "位置"
msgid "%Used"
msgstr "使用百分比"
msgid "Allocated"
msgstr "已分配"
msgid "Capacity"
msgstr "容量"
msgid "Disks"
msgstr "磁盘"
msgid "Extending logical pool"
msgstr "正在扩展逻辑池"
msgid "%"
msgstr "%"
msgid "Deactivate"
msgstr "取消激活"
msgid "Activate"
msgstr "激活"
msgid "Extend"
msgstr "扩展"
msgid "Undefine"
msgstr "取消定义"
msgid "Add Volume"
msgstr "添加卷"
msgid "Resize"
msgstr "调整大小"
msgid "Wipe"
msgstr "擦除"
msgid "Filter:"
msgstr "过滤器:"
msgid "Used By"
msgstr "使用者"
msgid "Used"
msgstr "使用率"
msgid "Progress"
msgstr "进度"
msgid "Used by the following VMs:"
msgstr "由以下 VM 使用:"
msgid "Allocation"
msgstr "分配"
msgid "Template Name (ID)"
msgstr "模板名称(标识)"
msgid "No templates found."
msgstr "找不到模板。"
msgid "M"
msgstr "M"
#~ msgid "Peers"
#~ msgstr "同级"
================================================
FILE: po/zh_TW.po
================================================
# Chinese (zh_TW) translations for kimchi package.
# Copyright IBM Corp, 2014-2017
# Adam Litke , 2013.
#
msgid ""
msgstr ""
"Project-Id-Version: kimchi 0.1\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2017-06-30 10:27-0300\n"
"PO-Revision-Date: 2013-07-11 17:32-0400\n"
"Last-Translator: Crístian Viana \n"
"Language-Team: English\n"
"Language: zh_TW\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: pygettext.py 1.5\n"
"Plural-Forms: nplurals=1; plural=0;\n"
#, python-format
msgid "Unknown parameter %(value)s"
msgstr "不明參數 %(value)s"
#, python-format
msgid "User %(user_id)s not found with given LDAP settings."
msgstr "找不到具有給定 LDAP 設定的使用者 %(user_id)s。"
#, python-format
msgid "Partition %(name)s does not exist in the host"
msgstr "分割區 %(name)s 不在主機中"
msgid "Error while accessing dev mapper device, %(err)s"
msgstr ""
msgid "Block device not found."
msgstr ""
msgid "Block device %(device)s not found."
msgstr ""
msgid "Unable to retrieve LVM information. Details: %(err)s"
msgstr ""
msgid "Unknown \"_cap\" specified"
msgstr "指定的 \"_cap\" 不明"
msgid "\"_passthrough\" should be \"true\" or \"false\""
msgstr "\"_passthrough\" 應該是 \"true\" 或 \"false\""
msgid "\"_passthrough_affected_by\" should be a device name string"
msgstr "\"_passthrough_affected_by\" 應該是裝置名稱字串"
msgid "\"_available_only\" should be \"true\" or \"false\""
msgstr "\"_available_only\" 應該是 \"true\" 或 \"false\""
#, python-format
msgid "Unable to find distro file: %(filename)s"
msgstr "找不到 distro 檔:%(filename)s"
#, python-format
msgid ""
"Unable to parse distro file: %(filename)s. Make sure, it is a JSON file."
msgstr "無法剖析 distro 檔:%(filename)s。請確保該檔案是 JSON 檔。"
#, python-format
msgid "Unable to login to iSCSI host target %(portal)s. Details: %(err)s"
msgstr "無法登入 iSCSI 主機目標 %(portal)s。詳細資料:%(err)s"
#, python-format
msgid "Unable to login to iSCSI host %(host)s target %(target)s"
msgstr "無法登入 iSCSI 主機 %(host)s 目標 %(target)s"
#, python-format
msgid "Unable to find ISO file %(filename)s"
msgstr "找不到 ISO 檔 %(filename)s"
#, python-format
msgid "The ISO file %(filename)s is not bootable"
msgstr "ISO 檔 %(filename)s 不可啟動"
#, python-format
msgid "The ISO file %(filename)s does not have a valid El Torito boot record"
msgstr "ISO 檔 %(filename)s 沒有有效的 El Torito 啟動記錄"
#, python-format
msgid "Invalid El Torito validation entry in ISO %(filename)s"
msgstr "ISO %(filename)s 中有無效的 El Torito 驗證項目"
#, python-format
msgid "Invalid El Torito boot indicator in ISO %(filename)s"
msgstr "ISO %(filename)s 中有無效的 El Torito 啟動指示器"
#, python-format
msgid "Unexpected volume type for primary volume in ISO %(filename)s"
msgstr "ISO %(filename)s 中主要磁區有非預期磁區類型"
#, python-format
msgid "Bad format while reading volume descriptor in ISO %(filename)s"
msgstr "讀取 ISO %(filename)s 中的磁區描述子時格式錯誤"
#, python-format
msgid ""
"The hypervisor doesn't have permission to use this ISO %(filename)s. "
"Consider moving it under /var/lib/libvirt, or set the search permission to "
"file access control lists for '%(user)s' user if possible, or add the "
"'%(user)s' to the ISO path group, or (not recommended) 'chmod -R o+x "
"'path_to_iso'.Details: %(err)s"
msgstr ""
"Hypervisor 無權使用此 ISO %(filename)s。請考量將其在 /var/lib/libvirt 下面移"
"動,或者為 '%(user)s' 使用者設定檔案存取控制清單的搜尋權限(如果可能的話),"
"或者將 '%(user)s' 新增至 ISO 路徑群組,或者(不建議)執行 'chmod -R o+x "
"'path_to_iso' 指令。詳細資料:%(err)s"
#, python-format
msgid "Unable to access remote ISO. Details: %(err)s"
msgstr "無法存取遠端 ISO。詳細資料:%(err)s"
#, python-format
msgid "Error probing image OS information: %(err)s"
msgstr ""
#, python-format
msgid "Unable to read image file %(filename)s"
msgstr "無法讀取映像檔 %(filename)s"
#, python-format
msgid ""
"Image file must be an existing file on system. %(filename)s is not a valid "
"input."
msgstr "映像檔必須是系統上的現有檔案。%(filename)s 不是有效的輸入。"
#, python-format
msgid "Virtual machine %(name)s already exists"
msgstr "虛擬機器 %(name)s 已經存在"
#, python-format
msgid "Virtual machine %(name)s does not exist"
msgstr "虛擬機器 %(name)s 不存在"
#, python-format
msgid "Unable to retrieve screenshot for stopped virtual machine %(name)s"
msgstr "無法擷取已停止虛擬機器 %(name)s 的畫面"
msgid "Remote ISO image is not supported by this server."
msgstr "此伺服器不支援遠端 ISO 映像檔。"
#, python-format
msgid "Screenshot is not supported on virtual machine %(name)s"
msgstr "擷取畫面在虛擬機器 %(name)s 上不受支援"
#, python-format
msgid "Unable to create virtual machine %(name)s. Details: %(err)s"
msgstr "無法建立虛擬機器 %(name)s。詳細資料:%(err)s"
#, python-format
msgid "Unable to update virtual machine %(name)s. Details: %(err)s"
msgstr "無法更新虛擬機器 %(name)s。詳細資料:%(err)s"
#, python-format
msgid "Unable to retrieve virtual machine %(name)s. Details: %(err)s"
msgstr "無法擷取虛擬機器 %(name)s。詳細資料:%(err)s"
#, python-format
msgid "Unable to connect to powered off virtual machine %(name)s."
msgstr "無法連接至已關閉電源的虛擬機器 %(name)s。"
msgid "Virtual machine name must be a string without slashes (/)"
msgstr "虛擬機器名稱必須是不含斜線 (/) 的字串"
#, python-format
msgid "Invalid template URI %(value)s specified for virtual machine"
msgstr "為虛擬機器指定的範本 URI %(value)s 無效"
#, python-format
msgid "Invalid storage pool URI %(value)s specified for virtual machine"
msgstr "為虛擬機器指定的儲存區 URI %(value)s 無效"
msgid "Supported virtual machine graphics are Spice or VNC"
msgstr "受支援的虛擬機器圖形是 Spice 或 VNC"
msgid "Graphics address to listen on must be IPv4 or IPv6"
msgstr "要接聽的圖形位址必須是 IPv4 或 IPv6"
msgid "Specify a template to create a virtual machine from"
msgstr "指定範本,以根據該範本建立虛擬機器"
#, python-format
msgid "Unable to start virtual machine %(name)s. Details: %(err)s"
msgstr "無法啟動虛擬機器 %(name)s。詳細資料:%(err)s"
#, python-format
msgid "Unable to power off virtual machine %(name)s. Details: %(err)s"
msgstr "無法關閉虛擬機器 %(name)s 的電源。詳細資料:%(err)s"
#, python-format
msgid "Unable to delete virtual machine %(name)s. Details: %(err)s"
msgstr "無法刪除虛擬機器 %(name)s。詳細資料:%(err)s"
#, python-format
msgid "Unable to reset virtual machine %(name)s. Details: %(err)s"
msgstr "無法重設虛擬機器 %(name)s。詳細資料:%(err)s"
msgid "User name list must be an array"
msgstr "使用者名稱清單必須是陣列"
msgid "User name must be a string"
msgstr "使用者名稱必須是字串"
msgid "Group name list must be an array"
msgstr "群組名稱清單必須是陣列"
msgid "Group name must be a string"
msgstr "群組名稱必須是字串"
#, python-format
msgid "User(s) '%(users)s' do not exist"
msgstr "使用者 '%(users)s' 不存在"
#, python-format
msgid "Group(s) '%(groups)s' do not exist"
msgstr "群組 '%(groups)s' 不存在"
#, python-format
msgid "Unable to shutdown virtual machine %(name)s. Details: %(err)s"
msgstr "無法關閉虛擬機器 %(name)s。詳細資料:%(err)s"
msgid "The guest console password must be a string."
msgstr "客體主控台密碼必須是字串。"
msgid "The life time for the guest console password must be a number."
msgstr "客體主控台密碼的生命期限必須是數字。"
#, python-format
msgid "Virtual machine '%(name)s' must be stopped before cloning it."
msgstr "必須先停止虛擬機器 '%(name)s',然後再複製該虛擬機器。"
#, python-format
msgid "Insufficient disk space to clone virtual machine '%(name)s'"
msgstr "磁碟空間不足,無法複製虛擬機器 '%(name)s'"
#, python-format
msgid "Unable to clone VM '%(name)s'. Details: %(err)s"
msgstr "無法複製 VM '%(name)s'。詳細資料:%(err)s"
#, python-format
msgid "Invalid operation for non-persistent virtual machine %(name)s"
msgstr "針對非持續性虛擬機器 %(name)s 的作業無效"
#, python-format
msgid "Cannot suspend VM '%(name)s' because it is not running."
msgstr "無法暫停 VM '%(name)s',因為該 VM 未處於執行中狀態。"
#, python-format
msgid "Unable to suspend VM '%(name)s'. Details: %(err)s"
msgstr "無法暫停 VM '%(name)s'。詳細資料:%(err)s"
#, python-format
msgid "Cannot resume VM '%(name)s' because it is not paused."
msgstr "無法回復 VM '%(name)s',因為該 VM 未處於暫停狀態。"
#, python-format
msgid "Unable to resume VM '%(name)s'. Details: %(err)s"
msgstr "無法回復 VM '%(name)s'。詳細資料:%(err)s"
#, python-format
msgid ""
"Memory assigned is higher then the maximum allowed in the host: "
"%(maxmem)sMib."
msgstr "指派的記憶體高於主機中容許的上限:%(maxmem)sMib。"
#, python-format
msgid ""
"Guest '%(name)s' does not support live memory update. Please, with the guest "
"offline, set Maximum Memory with a value greater then Memory to enable this "
"feature."
msgstr ""
"客體 '%(name)s' 不支援即時記憶體更新。請在客體處於離線狀態的情況下,將「記憶"
"體上限」設定為大於「記憶體」的值,以啟用此功能。"
msgid "Only increase memory is allowed in active VMs"
msgstr "作用中的 VM 只容許增加記憶體"
msgid "There are not enough free slots to add a new memory device."
msgstr "可用插槽不足,無法新增記憶體裝置。"
msgid ""
"Host's libvirt or qemu version does not support memory devices and memory "
"hotplug. Libvirt must be >= 1.2.14 and QEMU must be >= 2.1."
msgstr ""
"主機的 libvirt 或 qemu 版本不支援記憶體裝置及記憶體熱插拔。Libvirt 必須至少"
"是 1.2.14,且 QEMU 必須至少是 2.1。"
#, python-format
msgid "Error attaching memory device. Details: %(error)s"
msgstr "連接記憶體裝置時發生錯誤。詳細資料:%(error)s"
#, python-format
msgid "Cannot start %(name)s. Virtual machine is already running."
msgstr "無法啟動 %(name)s。虛擬機器已在執行中。"
#, python-format
msgid "Cannot power off %(name)s. Virtual machine is shut off."
msgstr "無法關閉 %(name)s。虛擬機器已關閉。"
#, python-format
msgid "Cannot shutdown %(name)s. Virtual machine is shut off."
msgstr "無法關閉 %(name)s。虛擬機器已關閉。"
#, python-format
msgid "Cannot reset %(name)s. Virtual machine is already shut off."
msgstr "無法重設 %(name)s。虛擬機器已關閉。"
msgid "Boot order must be a list. Devices accepted: hd, cdrom, fd or network."
msgstr "開機順序必須是清單。接受的裝置:硬碟、CDROM、FD 或網路。"
msgid "Bootmenu must be boolean. Values accepted: true of false."
msgstr "開機功能表必須是布林值。接受的值:true 或 false。"
msgid "Graphic type not valid. Values accepted: vnc or spice."
msgstr "圖形類型無效。接受的值:VNC 或 Spice。"
#, python-format
msgid "Migrate to localhost %(host)s is not allowed."
msgstr "不容許移轉至本端主機 %(host)s。"
#, python-format
msgid ""
"To migrate a virtual machine to the remote host %(host)s the user %(user)s "
"must have password-less login to the remote host."
msgstr ""
"如果要將虛擬機器移轉至遠端主機 %(host)s,使用者 %(user)s 必須具有遠端主機的無"
"密碼登入權限。"
#, python-format
msgid "Can not migrate virtual machine %(name)s when its in %(state)s state."
msgstr "當虛擬機器 %(name)s 處於%(state)s狀態時,無法移轉該虛擬機器。"
#, python-format
msgid "Failed to migrate virtual machine %(name)s due error: %(err)s"
msgstr "由於下列錯誤,無法移轉虛擬機器 %(name)s:%(err)s"
msgid "User name of the remote server must be a string."
msgstr "遠端伺服器的使用者名稱必須是字串。"
msgid "Destination host of the migration must be a string."
msgstr "移轉的目的地主機必須是字串。"
#, python-format
msgid "Unable to create file %(path)s at %(host)s using user %(user)s."
msgstr "無法利用使用者 %(user)s 在 %(host)s 處建立檔案 %(path)s。"
#, python-format
msgid "Unable to read disk size of %(path)s, error: %(error)s"
msgstr "無法讀取 %(path)s 的磁碟大小,錯誤:%(error)s"
#, python-format
msgid ""
"Unable to create disk image %(path)s at %(host)s using user %(user)s. Error: "
"%(error)s"
msgstr ""
"無法利用使用者 %(user)s 在 %(host)s 處建立磁碟映像檔 %(path)s。錯誤:"
"%(error)s"
#, python-format
msgid ""
"Unable to migrate virtual machine to remote host %(host)s with arch "
"%(destarch)s using localhost with arch %(srcarch)s."
msgstr ""
"無法使用架構為 %(srcarch)s 的本端主機,將虛擬機器移轉至架構為 %(destarch)s 的"
"遠端主機 %(host)s。"
#, python-format
msgid ""
"Unable to migrate virtual machine to remote host %(host)s with hypervisor "
"%(desthyp)s because localhost uses hypervisor %(srchyp)s."
msgstr ""
"無法將虛擬機器移轉至 Hypervisor 為 %(desthyp)s 的遠端主機 %(host)s,因為本端"
"主機使用 Hypervisor %(srchyp)s。"
#, python-format
msgid ""
"Unable to determine remote host hypervisor and architecture. Error: %(error)s"
msgstr "無法判定遠端主機 Hypervisor 及架構。錯誤:%(error)s"
#, python-format
msgid ""
"Unable to migrate virtual machine: subcores per core setting from "
"localhostand remote host %(host)s differs."
msgstr ""
"無法移轉虛擬機器:本端主機與遠端主機 %(host)s 中每個核心的子核心數目設定不"
"同。"
#, python-format
msgid ""
"Unable to setup password-less login at remote host %(host)s using user "
"%(user)s. Error: %(error)s"
msgstr ""
"無法利用使用者 %(user)s 在遠端主機 %(host)s 處設定無密碼登入。錯誤:%(error)s"
msgid "Password field must be a string."
msgstr "密碼欄位必須是字串。"
msgid "Error creating local host ssh rsa key of user 'root'."
msgstr "建立使用者 'root' 的本端主機 SSH RSA 金鑰時發生錯誤。"
#, python-format
msgid "%(param)s value (%(mem)sMiB) must be aligned to %(alignment)sMiB."
msgstr "%(param)s 值 (%(mem)sMiB) 必須與 %(alignment)sMiB 相同。"
#, python-format
msgid ""
"Unable to update the following parameters while the VM is offline: %(params)s"
msgstr "當 VM 處於離線狀態時,無法更新下列參數:%(params)s"
#, python-format
msgid ""
"Unable to update the following parameters while the VM is online: %(params)s"
msgstr "當 VM 處於線上狀態時,無法更新下列參數:%(params)s"
#, python-format
msgid ""
"VM %(name)s must have serial and console defined to open a web serial console"
msgstr "VM %(name)s 必須已定義了序列和主控台,才能開啟 Web 序列主控台"
#, python-format
msgid "Impossible to get the serial console of %(name)s"
msgstr "無法取得 %(name)s 的序列主控台"
#, python-format
msgid ""
"Memory or Maximum Memory value is higher than amount supported by the host: "
"%(memHost)sMiB."
msgstr "「記憶體」或「記憶體上限」值大於主機支援的數量:%(memHost)sMiB。"
#, python-format
msgid ""
"Memory or Maximum Memory value is higher than maximum amount recommended: "
"%(value)sTiB"
msgstr "「記憶體」或「記憶體上限」值大於建議的數量上限:%(value)sTiB"
msgid "Cannot update Maximum Memory when guest is running."
msgstr "當客體處於執行中狀態時,無法更新「記憶體上限」。"
#, python-format
msgid "Impossible to create %(dir)s directory."
msgstr "無法建立 %(dir)s 目錄。"
#, python-format
msgid ""
"Either the guest %(name)s did not start to listen to the serial or it is not "
"configured to use the serial console."
msgstr "客體 %(name)s 未開始接聽序列,或者未將其配置成使用序列主控台。"
#, python-format
msgid ""
"Unable to retrieve Virt Viewer file for stopped virtual machine %(name)s"
msgstr "無法擷取已停止虛擬機器 %(name)s 的「Virt 檢視器」檔案"
#, python-format
msgid ""
"Error occured while retrieving the Virt Viewer file for virtual machine "
"%(name)s : %(err)s"
msgstr "擷取虛擬機器 %(name)s 的「Virt 檢視器」檔案時發生錯誤:%(err)s"
msgid "Virtual machine title must be a string"
msgstr "虛擬機器標題必須是字串"
msgid "Virtual machine description must be a string"
msgstr "虛擬機器說明必須是字串"
msgid "console parameter is only supported for s390x/s390 architecture."
msgstr "只有 s390x/s390 架構才支援主控台參數。"
msgid "invalid console type, supported types are sclp/virtio."
msgstr "主控台類型無效,支援的類型為 sclp/virtio。"
#, python-format
msgid ""
"Unable to setup password-less login at remote host %(host)s using user "
"%(user)s: remote directory %(sshdir)s does not exist."
msgstr ""
"無法利用使用者 %(user)s 在遠端主機 %(host)s 處設定無密碼登入:遠端目錄 "
"%(sshdir)s 不存在。"
#, python-format
msgid ""
"Unable to create a password-less libvirt connection to the remote libvirt "
"daemon at host %(host)s with the user %(user)s. Please verify the remote "
"server libvirt configuration. More information: http://libvirt.org/auth."
"html ."
msgstr ""
"藉由使用者 %(user)s,無法與主機 %(host)s 處的遠端 libvirt 常駐程式建立無密碼 "
"libvirt 連線。請驗證遠端伺服器 libvirt 配置。相關資訊:http://libvirt.org/"
"auth.html。"
msgid "'enable_rdma' must be of type boolean (true or false)."
msgstr ""
#, python-format
msgid ""
"VM %(vmid)s does not contain directly assigned host device %(dev_name)s."
msgstr "VM %(vmid)s 不包含直接指派的主機裝置 %(dev_name)s。"
#, python-format
msgid "The host device %(dev_name)s is not allowed to directly assign to VM."
msgstr "不容許將主機裝置 %(dev_name)s 直接指派給 VM。"
msgid ""
"No IOMMU groups found. Host PCI pass through needs IOMMU group to function "
"correctly. Please enable Intel VT-d or AMD IOMMU in your BIOS, then verify "
"the Kernel is compiled with IOMMU support. For Intel CPU, add "
"'intel_iommu=on' to GRUB_CMDLINE_LINUX parameter in /etc/default/grub file. "
"For AMD CPU, add 'iommu=pt iommu=1'."
msgstr ""
"找不到 IOMMU 群組。主機 PCI 透通需要 IOMMU 群組才能正常運作。請在 BIOS 中啟"
"用 Intel VT-d 或 AMD IOMMU,然後確認已使用 IOMMU 支援編譯了核心。若為 Intel "
"CPU,請在 /etc/default/grub 檔中,將 'intel_iommu=on' 新增至 "
"GRUB_CMDLINE_LINUX 參數。若為 AMD CPU,請新增 'iommu=pt iommu=1'。"
msgid "\"name\" should be a device name string"
msgstr "\"name\" 應該是裝置名稱字串"
#, python-format
msgid ""
"The device %(name)s is probably in use by the host. Unable to attach it to "
"the guest."
msgstr "主機可能正在使用裝置 %(name)s。無法將該裝置連接至客體。"
#, python-format
msgid "Hot-(un)plug of device %(name)s is not supported."
msgstr "不支援裝置 %(name)s 的熱插拔。"
#, python-format
msgid "Failed to attach %(device)s to %(vm)s"
msgstr "無法將 %(device)s 連接至 %(vm)s"
#, python-format
msgid "VM %(vmid)s does not have a USB controller to accept PCI hotplug."
msgstr ""
#, python-format
msgid "Interface %(iface)s does not exist in virtual machine %(name)s"
msgstr "介面 %(iface)s 不在虛擬機器 %(name)s 中"
#, python-format
msgid ""
"Network %(network)s specified for virtual machine %(name)s does not exist"
msgstr "為虛擬機器 %(name)s 指定的網路 %(network)s 不存在"
msgid ""
"Supported virtual machine interfaces type are network, ovs and macvtap.Type "
"ovs and macvtap are only supported for s390x/s390 architecture."
msgstr ""
"支援的虛擬機器介面類型為網路、OVS 和 macvtap。只有 s390x/s390 架構才支援類型 "
"OVS 和 macvtap。"
msgid "Network name for virtual machine interface must be a string"
msgstr "虛擬機器介面的網路名稱必須是字串"
msgid "Invalid network model card specified for virtual machine interface"
msgstr "為虛擬機器介面指定的網路模型卡無效"
msgid "Specify type and network to add a new virtual machine interface"
msgstr "指定類型和網路以新增虛擬機器介面"
msgid "MAC Address must respect this format FF:FF:FF:FF:FF:FF"
msgstr "「MAC 位址」必須遵循下列格式:FF:FF:FF:FF:FF:FF"
#, python-format
msgid "MAC Address %(mac)s already exists in virtual machine %(name)s"
msgstr "「MAC 位址」%(mac)s 已經存在於虛擬機器 %(name)s 中"
msgid "Invalid MAC Address"
msgstr "MAC 位址無效"
msgid "Cannot change MAC address of a running virtual machine"
msgstr "無法變更執行中虛擬機器的 MAC 位址"
msgid "Type macvtap and ovs are only supported on s390x/s390 architecture."
msgstr "類型 macvtap 和 OVS 只在 s390x/s390 架構上受支援。"
msgid "Source attribute is only supported on s390x/s390 architecture."
msgstr "來源屬性只在 s390x/s390 架構上受支援。"
msgid "If source is provided, only type supported are macvtap and ovs."
msgstr "如果提供了來源,則僅支援類型 macvtap 和 OVS。"
msgid "For type macvtap and ovs, source has to be provided"
msgstr "若為類型 macvtap 和 OVS,必須提供來源"
msgid "Source name for virtual machine interface must be string"
msgstr "虛擬機器介面的來源名稱必須是字串"
msgid "Invalid source mode. Valid options are: bridge or vepa."
msgstr "來源模式無效。有效的選項為:橋接器或 VEPA。"
#, python-format
msgid "Template %(name)s already exists"
msgstr "範本 %(name)s 已經存在"
#, python-format
msgid "Source media %(path)s not found"
msgstr "找不到來源媒體 %(path)s"
#, python-format
msgid ""
"Network '%(network)s' specified for template %(template)s does not exist"
msgstr "為範本 %(template)s 指定的網路 '%(network)s' 不存在"
#, python-format
msgid ""
"Storage pool %(pool)s specified for template %(template)s does not exist"
msgstr "為範本 %(template)s 指定的儲存區 %(pool)s 不存在"
#, python-format
msgid "Invalid parameter '%(param)s' specified for CDROM."
msgstr "為 CDROM 指定的參數 '%(param)s' 無效。"
#, python-format
msgid "Network %(network)s specified for template %(template)s is not active"
msgstr "為範本 %(template)s 指定的網路 %(network)s 未處於作用中狀態"
msgid "Template name must be a string"
msgstr "範本名稱必須是字串"
msgid "Template icon must be a path to the image"
msgstr "範本圖示必須是映像檔的路徑"
msgid "Template distribution must be a string"
msgstr "範本發行套件必須是字串"
msgid "Template distribution version must be a string"
msgstr "範本發行版本必須是字串"
msgid "The number of CPUs must be an integer greater than 0"
msgstr "CPU 數目必須是大於 0 的整數"
msgid ""
"Amount of memory and maximum memory (MB) must be an integer greater than 512"
msgstr "記憶體及記憶體上限的數量 (MB) 必須是大於 512 的整數"
msgid "Template CDROM must be a local or remote ISO file"
msgstr "範本 CDROM 必須是本端或遠端 ISO 檔"
#, python-format
msgid "Invalid storage pool URI %(value)s specified for template"
msgstr "為範本指定的儲存區 URI %(value)s 無效"
msgid ""
"Specify a path to source media (ISO, disk or remote ISO) to create a template"
msgstr "指定來源媒體(ISO、磁碟或遠端 ISO)的路徑,以建立範本"
msgid "All networks for the template must be specified in a list."
msgstr "範本的所有網路都必須在清單中指定。"
msgid "Specify a volume to a template when storage pool is iSCSI or SCSI"
msgstr "當儲存區是 iSCSI 或 SCSI 時,請將磁區指定給範本"
#, python-format
msgid "The volume %(volume)s is not in storage pool %(pool)s"
msgstr "磁區 %(volume)s 不在儲存區 %(pool)s 中"
#, python-format
msgid "Unable to create template due error: %(err)s"
msgstr "由於下列錯誤,無法建立範本:%(err)s"
#, python-format
msgid "Unable to delete template due error: %(err)s"
msgstr "由於下列錯誤,無法刪除範本:%(err)s"
msgid "Disk size must be an integer greater than 1GB."
msgstr "磁碟大小必須是大於 1GB 的整數。"
#, python-format
msgid "Cannot identify base image %(path)s format"
msgstr "無法識別基本映像檔 %(path)s 格式"
msgid ""
"When specifying CPU topology, each element must be an integer greater than "
"zero."
msgstr "指定 CPU 拓蹼時,每一個元素都必須是大於 0 的整數。"
msgid ""
"Invalid disk image format. Valid formats: qcow, qcow2, qed, raw, vmdk, vpc."
msgstr "磁碟映像檔格式無效。有效的格式:qcow、qcow2、qed、raw、vmdk、vpc。"
msgid ""
"When setting template disks, following parameters are required: 'index', "
"'pool name', 'format', 'size' or 'volume' (for scsi/iscsi pools)"
msgstr ""
"設定範本磁碟時,下列參數是必要的:「索引」、「儲存區名稱」、「格式」、「大"
"小」或「磁區」(適用於 SCSI/iSCSI 儲存區)"
msgid "Disk format must be 'raw', for logical, iscsi, and scsi pools."
msgstr "若為邏輯儲存區、iSCSI 儲存區和 SCSI 儲存區,磁碟格式必須是 'raw'。"
msgid ""
"Memory expects an object with one or both parameters: 'current' and "
"'maxmemory'"
msgstr "記憶體預期具有「現行」參數及/或「最大記憶體」參數的物件"
#, python-format
msgid ""
"Memory value (%(mem)sMiB) must be equal or lesser than maximum memory value "
"(%(maxmem)sMiB)"
msgstr "記憶體值 (%(mem)sMiB) 必須等於或小於記憶體上限值 (%(maxmem)sMiB)"
#, python-format
msgid "Unable to update template due error: %(err)s"
msgstr "由於下列錯誤,無法更新範本:%(err)s"
msgid "Parameter 'disks' requires at least one disk object"
msgstr "參數「磁碟」需要至少一個磁碟物件"
msgid ""
"Invalid interface type. Type should be 'macvtap' for host network interface "
"(Ethernet, Bond, VLAN) to be connected as direct MacVTap or 'ovs' for "
"openvswitch host network interface to be connected as virtual switch to a VM."
msgstr ""
"介面類型無效。對於要作為直接 MacVTap 進行連接的主機網路介面(乙太網路、Bond、"
"VLAN),類型應該是 'macvtap';或者,對於要作為虛擬交換器而連接至 VM 的 Open "
"vSwitch 主機橋接器介面,類型應該是 'ovs'。"
msgid "Interface name should be string."
msgstr "介面名稱應該是字串。"
msgid "Invalid interface mode. Valid options are: bridge or vepa."
msgstr "介面模式無效。有效的選項為:橋接器或 VEPA。"
msgid ""
"Interfaces should be list of interfaces. Each interface should have name, "
"type and mode(optional, only applicable for interfcae type 'macvtap'."
msgstr ""
"介面應該是一個介面清單。每一個介面都應該具有名稱、類型和模式(選用項目,僅適"
"用於介面類型 'macvtap')。"
msgid ""
"Interface expects an object with parameters: 'name', 'type' and 'mode'. Name "
"should be name of host network interface (Ethernet, Bond, VLAN) for type "
"'macvtap' or the name of host openvswitch bridge interface for type 'ovs'. "
"Mode (optional) is only applicable for interface type 'macvtap' to indicates "
"whether packets will be delivered directly to target device (bridge) or to "
"the external bridge (vepa-capable bridge)."
msgstr ""
"介面預期具有下列參數的物件:「名稱」、「類型」和「模式」。「名稱」應該是主機"
"網路介面(乙太網路、Bond、VLAN)的名稱(適用於類型 'macvtap')或主機 Open "
"vSwitch 橋接器介面的名稱(適用於類型 'ovs')。「模式」(選用)僅適用於介面類"
"型 'macvtap',以指示是將封包直接遞送至目標裝置(橋接器),還是遞送至外部橋接"
"器(支援 VEPA 的橋接器)。"
msgid "Interfaces parameter only supported on s390x or s390 architecture."
msgstr "介面參數只在 s390x 或 s390 架構上受支援。"
msgid "Storage without libvirt pool is not supported on this architecture"
msgstr "這種架構不支援不含 libvirt 儲存區的儲存體"
#, python-format
msgid "Error while creating the virtual disk for the guest. Details: %(err)s"
msgstr "為客體建立虛擬磁碟時發生錯誤。詳細資料:%(err)s"
msgid ""
"When setting template disks without libvirt, following parameters are "
"required: 'index', 'format', 'path', 'size'"
msgstr ""
"設定不含 libvirt 的範本磁碟時,下列參數是必要的:「索引」、「格式」、「路"
"徑」、「大小」"
#, python-format
msgid "Storage pool %(name)s already exists"
msgstr "儲存區 %(name)s 已經存在"
#, python-format
msgid "Storage pool %(name)s does not exist"
msgstr "儲存區 %(name)s 不存在"
#, python-format
msgid "Specify %(item)s in order to create the storage pool %(name)s"
msgstr "指定 %(item)s 以建立儲存區 %(name)s"
#, python-format
msgid "Unable to delete active storage pool %(name)s"
msgstr "無法刪除作用中的儲存區 %(name)s"
#, python-format
msgid "Unable to list storage pools. Details: %(err)s"
msgstr "無法列出儲存區。詳細資料:%(err)s"
#, python-format
msgid "Unable to create storage pool %(name)s. Details: %(err)s"
msgstr "無法建立儲存區 %(name)s。詳細資料:%(err)s"
#, python-format
msgid "Unable to activate storage pool %(name)s. Details: %(err)s"
msgstr "無法啟動儲存區 %(name)s。詳細資料:%(err)s"
#, python-format
msgid "Unable to deactivate storage pool %(name)s. Details: %(err)s"
msgstr "無法取消啟動儲存區 %(name)s。詳細資料:%(err)s"
#, python-format
msgid "Unable to delete storage pool %(name)s. Details: %(err)s"
msgstr "無法刪除儲存區 %(name)s。詳細資料:%(err)s"
#, python-format
msgid ""
"Unable to create NFS Pool as export path %(path)s may block during mount"
msgstr "無法建立 NFS 儲存區,因為在裝載期間,匯出路徑 %(path)s 可能會封鎖"
#, python-format
msgid "Unable to create NFS Pool as export path %(path)s mount failed"
msgstr "無法建立 NFS 儲存區,因為匯出路徑 %(path)s 裝載失敗"
#, python-format
msgid "Unsupported storage pool type: %(type)s"
msgstr "不受支援的儲存區類型:%(type)s"
#, python-format
msgid "Error while retrieving storage pool XML to %(pool)s"
msgstr "擷取儲存區 XML 至 %(pool)s 時發生錯誤"
msgid "Storage pool name must be a string without slashes (/)"
msgstr "儲存區名稱必須是不含斜線 (/) 的字串"
msgid ""
"Supported storage pool types are dir, netfs, logical, iscsi, isci and kimchi-"
"iso"
msgstr "支援的儲存區類型為 dir、netfs、邏輯、iscsi、isci 及 kimchi-iso"
msgid "Storage pool path must be a string"
msgstr "儲存區路徑必須是字串"
msgid "Storage pool host must be a IP or hostname"
msgstr "儲存區主機必須是 IP 或主機名稱"
msgid "Storage pool device must be the absolute path to the block device"
msgstr "儲存區裝置必須是區塊裝置的絕對路徑"
msgid "Storage pool devices parameter must be a list"
msgstr "儲存區裝置參數必須是清單"
msgid "Target IQN of an iSCSI pool must be a string"
msgstr "iSCSI 儲存區的目標 IQN 必須是字串"
msgid "Port of a remote storage server must be an integer between 1 and 65535"
msgstr "遠端儲存體伺服器的埠必須是介於 1 和 65535 之間的整數"
msgid "iSCSI target username must be a string"
msgstr "iSCSI 目標使用者名稱必須是字串"
msgid "iSCSI target password must be a string"
msgstr "iSCSI 目標密碼必須是字串"
msgid "Specify name and type to create a storage pool"
msgstr "指定名稱和類型以建立儲存區"
#, python-format
msgid ""
"%(disk)s is not a valid disk/partition. Could not add it to the pool "
"%(pool)s."
msgstr "%(disk)s 不是有效的磁碟/分割區。無法將其新增至儲存區 %(pool)s。"
#, python-format
msgid "Unable to extend logical pool %(pool)s. Details: %(err)s"
msgstr "無法延伸邏輯儲存區 %(pool)s。詳細資料:%(err)s"
msgid "The parameter disks only can be updated for logical storage pool."
msgstr "只能針對邏輯儲存區更新參數磁碟。"
msgid "The SCSI host adapter name must be a string."
msgstr "SCSI 主機配接卡名稱必須是字串。"
msgid "The storage pool kimchi_isos is reserved for internal use"
msgstr "已保留儲存區 kimchi_isos 供內部使用"
#, python-format
msgid ""
"Unable to activate NFS storage pool %(name)s. NFS server %(server)s is "
"unreachable."
msgstr "無法啟動 NFS 儲存區 %(name)s。無法呼叫到 NFS 伺服器 %(server)s。"
#, python-format
msgid ""
"Unable to deactivate NFS storage pool %(name)s. NFS server %(server)s is "
"unreachable."
msgstr "無法取消啟動 NFS 儲存區 %(name)s。無法呼叫到 NFS 伺服器 %(server)s。"
#, python-format
msgid ""
"Unable to deactivate pool %(name)s as it is associated with some templates"
msgstr "無法取消啟動儲存區 %(name)s,因為它與部分範本相關聯"
#, python-format
msgid "Unable to delete pool %(name)s as it is associated with some templates"
msgstr "無法刪除儲存區 %(name)s,因為它與部分範本相關聯"
#, python-format
msgid ""
"A volume group named '%(name)s' already exists. Please, choose another name "
"to create the logical pool."
msgstr "名為 '%(name)s' 的磁區群組已經存在。請選擇另一個名稱來建立邏輯儲存區。"
#, python-format
msgid "Unable to update database with deep scan information due error: %(err)s"
msgstr "由於下列錯誤,無法使用深層掃描資訊來更新資料庫:%(err)s"
#, python-format
msgid ""
"No volume group '%(name)s' found. Please, specify an existing volume group "
"to create the logical pool from."
msgstr ""
"找不到磁區群組 '%(name)s'。請指定現有磁區群組,以根據該磁區群組建立邏輯儲存"
"區。"
#, python-format
msgid "Unable to delete pool %(name)s as it is associated with guests: %(vms)s"
msgstr "無法刪除儲存區 %(name)s,因為它與下列客體相關聯:%(vms)s"
#, python-format
msgid "Storage volume %(name)s already exists"
msgstr "儲存磁區 %(name)s 已經存在"
#, python-format
msgid "Storage volume %(name)s does not exist in storage pool %(pool)s"
msgstr "儲存磁區 %(name)s 不在儲存區 %(pool)s 中"
#, python-format
msgid ""
"Unable to create storage volume %(volume)s because storage pool %(pool)s is "
"not active"
msgstr "無法建立儲存磁區 %(volume)s,因為儲存區 %(pool)s未處於作用中狀態"
#, python-format
msgid "Specify %(item)s in order to create storage volume %(volume)s"
msgstr "指定 %(item)s 以建立儲存磁區 %(volume)s"
#, python-format
msgid ""
"Unable to list storage volumes because storage pool %(pool)s is not active"
msgstr "無法列出儲存磁區,因為儲存區 %(pool)s 未處於作用中狀態"
#, python-format
msgid ""
"Unable to create storage volume %(name)s in storage pool %(pool)s. Details: "
"%(err)s"
msgstr "無法在儲存區 %(pool)s 中建立儲存磁區 %(name)s。詳細資料:%(err)s"
#, python-format
msgid "Unable to wipe storage volumes %(name)s. Details: %(err)s"
msgstr "無法清除儲存磁區 %(name)s。詳細資料:%(err)s"
#, python-format
msgid "Unable to delete storage volume %(name)s. Details: %(err)s"
msgstr "無法刪除儲存磁區 %(name)s。詳細資料:%(err)s"
#, python-format
msgid "Unable to resize storage volume %(name)s. Details: %(err)s"
msgstr "無法調整儲存磁區 %(name)s 的大小。詳細資料:%(err)s"
#, python-format
msgid "Storage type %(type)s does not support volume create and delete"
msgstr "儲存體類型 %(type)s 不支援磁區建立和刪除"
msgid "Storage volume name must be a string"
msgstr "儲存磁區名稱必須是字串"
msgid "Storage volume allocation must be an integer number"
msgstr "儲存磁區配置必須是整數"
msgid ""
"Storage volume format not supported. Valid formats: qcow, qcow2, qed, raw, "
"vmdk, vpc."
msgstr "儲存磁區格式不受支援。有效的格式:qcow、qcow2、qed、raw、vmdk、vpc。"
msgid "Storage volume requires a volume name"
msgstr "儲存磁區需要磁區名稱"
#, python-format
msgid ""
"Unable to update database with storage volume information due error: %(err)s"
msgstr "由於下列錯誤,無法使用儲存磁區資訊來更新資料庫:%(err)s"
#, python-format
msgid "Only one of parameter %(param)s can be specified"
msgstr "只能指定其中一個參數 %(param)s"
#, python-format
msgid "Create volume from %(param)s is not supported"
msgstr "不支援透過 %(param)s 建立磁區"
msgid "Storage volume capacity must be an integer number."
msgstr "儲存磁區容量必須是整數。"
msgid "Storage volume URL must be http://, https://, ftp:// or ftps://."
msgstr "儲存磁區 URL 必須是 http://、https://、ftp:// 或 ftps://。"
#, python-format
msgid "Unable to access file %(url)s. Please, check it."
msgstr "無法存取檔案 %(url)s。請檢查該檔案。"
#, python-format
msgid ""
"Unable to clone storage volume '%(name)s' in pool '%(pool)s'. Details: "
"%(err)s"
msgstr "無法複製儲存區 '%(pool)s' 中的儲存磁區 '%(name)s'。詳細資料:%(err)s"
msgid "Specify chunk data and its size to upload a file."
msgstr "指定區塊資料及其大小以上傳檔案。"
msgid "In order to upload a storage volume, specify the 'upload' parameter."
msgstr "若要上傳儲存磁區,請指定「上傳」參數。"
msgid ""
"Unable to upload chunk data as it does not match with requested chunk size."
msgstr "無法上傳區塊資料,因為該區塊資料與所要求的區塊大小不符。"
#, python-format
msgid "The storage volume %(vol)s is not under an upload process."
msgstr "未在上傳儲存磁區 %(vol)s。"
msgid "The upload chunk data will exceed the storage volume size."
msgstr "上傳區塊資料將超過儲存磁區大小。"
#, python-format
msgid "Unable to upload chunk data to storage volume. Details: %(err)s."
msgstr "無法將區塊資料上傳至儲存磁區。詳細資料:%(err)s。"
#, python-format
msgid "Interface %(name)s does not exist"
msgstr "介面 %(name)s 不存在"
#, python-format
msgid ""
"Failed to list interfaces. Invalid _inuse parameter. Supported options for "
"_inuse are: %(supported_inuse)s"
msgstr ""
"無法列出介面。_inuse 參數無效。_inuse 支援的選項為:%(supported_inuse)s"
#, python-format
msgid "Network %(name)s already exists"
msgstr "網路 %(name)s 已經存在"
#, python-format
msgid "Network %(name)s does not exist"
msgstr "網路 %(name)s 不存在"
#, python-format
msgid "Subnet %(subnet)s specified for network %(network)s is not valid."
msgstr "為網路 %(network)s 指定的子網路 %(subnet)s 無效。"
msgid "Specify a network interface to create bridged or macvtap networks."
msgstr "指定網路介面,以建立橋接或 macvtap 網路。"
#, python-format
msgid "Unable to delete or update active network %(name)s"
msgstr "無法刪除或更新作用中網路 %(name)s"
#, python-format
msgid "Interface %(iface)s specified for network %(network)s is already in use"
msgstr "為網路 %(network)s 指定的介面 %(iface)s 已在使用中"
msgid "Interface should be bare NIC, bonding or bridge device."
msgstr "介面應該是裸露 NIC、bonding 或橋接器裝置。"
#, python-format
msgid "Unable to create or update network %(name)s. Details: %(err)s"
msgstr "無法建立或更新網路 %(name)s。詳細資料:%(err)s"
#, python-format
msgid "Unable to find a free IP address for network '%(name)s'"
msgstr "找不到網路 '%(name)s' 的可用 IP 位址"
#, python-format
msgid "The interface %(iface)s already exists."
msgstr "介面 %(iface)s 已經存在。"
msgid "Network name must be a string without slashes (/) or quotes (\")"
msgstr "網路名稱必須是不含斜線 (/) 或引號 (\") 的字串"
msgid ""
"Supported network types are isolated, NAT, macvtap, bridge, vepa and "
"passthrough."
msgstr "支援的網路類型為:已隔離、NAT、macvtap、橋接器、VEPA 和透通。"
msgid "Network subnet must be a string with IP address and prefix or netmask"
msgstr "網路的子網路必須是含有 IP 位址、字首或網路遮罩的字串"
msgid "Network interfaces must be an array."
msgstr "網路介面必須是陣列。"
msgid "Network VLAN ID must be an integer between 1 and 4094"
msgstr "網路 VLAN ID 必須是介於 1 和 4094 之間的整數"
msgid "Specify name and type to create a Network"
msgstr "指定名稱和類型以建立網路"
#, python-format
msgid ""
"Unable to delete or update network %(name)s as it is linked to some virtual "
"machines (%(vms)s) and/or templates (%(tmpls)s)."
msgstr ""
#, python-format
msgid ""
"Unable to deactivate network %(name)s as it is linked to are some virtual "
"machines (%(vms)s) and/or templates (%(tmpls)s)."
msgstr ""
#, python-format
msgid "Bridge device %(name)s can not be the trunk device of a VLAN."
msgstr "橋接器裝置 %(name)s 不能是 VLAN 的幹線裝置。"
#, python-format
msgid "Failed to activate interface %(iface)s: %(err)s."
msgstr "無法啟動介面 %(iface)s:%(err)s。"
#, python-format
msgid ""
"Failed to activate interface %(iface)s. Please check the physical link "
"status."
msgstr "無法啟動介面 %(iface)s。請檢查實體鏈結狀態。"
#, python-format
msgid "Failed to start network %(name)s. Details: %(err)s"
msgstr "無法啟動網路 %(name)s。詳細資料:%(err)s"
#, python-format
msgid "Unable to redefine interface %(name)s. Details: %(err)s"
msgstr "無法重新定義介面 %(name)s。詳細資料:%(err)s"
#, python-format
msgid "Unable to create bridge %(name)s. Details: %(err)s"
msgstr "無法建立橋接器 %(name)s。詳細資料:%(err)s"
msgid ""
"Unable to create bridge with NetworkManager enabled. Disable it and try "
"again."
msgstr "啟用網路管理程式時,無法建立橋接器。請將其停用,然後再試一次。"
msgid "Interface should be bare NIC or bonding."
msgstr "介面應該是裸露 NIC 或 Bonding。"
msgid "Network interfaces parameter must contain at least one interface."
msgstr "網路介面參數必須包含至少一個介面。"
msgid "Only one interface is allowed for 'bridge' and 'macvtap' networks."
msgstr "對於 'bridge' 和 'macvtap' 網路,只容許一個介面。"
msgid "Subnet is not a valid parameter for this type of virtual network."
msgstr "對於這種類型的虛擬網路,子網路不是有效參數。"
msgid ""
"VLAN ID and interfaces are not valid parameters for this type of virtual "
"network."
msgstr "對於這種類型的虛擬網路,VLAN ID 和介面不是有效參數。"
#, python-format
msgid "Storage server %(server)s was not used by Kimchi"
msgstr "Kimchi 未使用儲存體伺服器 %(server)s"
#, python-format
msgid "Distro '%(name)s' does not exist"
msgstr "Distro '%(name)s' 不存在"
#, python-format
msgid "Node device '%(name)s' not found"
msgstr "找不到節點裝置 '%(name)s'"
msgid "Conflicting flag filters specified."
msgstr "指定的旗標過濾器有衝突。"
msgid "Unable to choose a virtual machine name"
msgstr "無法選擇虛擬機器名稱"
msgid "Cannot upgrade objectstore data."
msgstr "無法升級物件儲存庫資料。"
msgid "Invalid storage type. Types supported: 'cdrom', 'disk'"
msgstr "儲存體類型無效。支援的類型:'cdrom'、'disk'"
#, python-format
msgid "The path '%(value)s' is not a valid local/remote path for the device"
msgstr "路徑 '%(value)s' 不是該裝置的有效本端/遠端路徑"
msgid "Only CDROM path can be update."
msgstr "只能更新 CDROM 路徑。"
#, python-format
msgid ""
"The storage device %(dev_name)s does not exist in the virtual machine "
"%(vm_name)s"
msgstr "儲存裝置 %(dev_name)s 不在虛擬機器 %(vm_name)s 中"
#, python-format
msgid "Error while creating new storage device: %(error)s"
msgstr "建立新的儲存裝置時發生錯誤:%(error)s"
#, python-format
msgid "Error while updating storage device: %(error)s"
msgstr "更新儲存裝置時發生錯誤:%(error)s"
#, python-format
msgid "Error while removing storage device: %(error)s"
msgstr "移除儲存裝置時發生錯誤:%(error)s"
msgid "Do not support IDE device hot plug"
msgstr "請勿支援 IDE 裝置熱插拔"
msgid ""
"Specify type and path or type and pool/volume to add a new virtual machine "
"disk"
msgstr "指定類型與路徑或類型與儲存區/磁區,以新增虛擬機器磁碟"
msgid "Specify path to update virtual machine disk"
msgstr "指定路徑以更新虛擬機器磁碟"
#, python-format
msgid "Controller type %(type)s limitation of %(limit)s devices reached"
msgstr "已達到控制器類型 %(type)s 限制(%(limit)s 個裝置)"
#, python-format
msgid "Cannot retrieve disk path information for given pool/volume: %(error)s"
msgstr "無法擷取給定儲存區/磁區的磁碟路徑資訊:%(error)s"
msgid "Volume already in use by other virtual machine."
msgstr "其他虛擬機器已在使用該磁區。"
msgid ""
"Only one of path or pool/volume can be specified to add a new virtual "
"machine disk"
msgstr "只能指定其中一個路徑或儲存區/磁區,以新增虛擬機器磁碟"
#, python-format
msgid ""
"Volume chosen with format %(format)s does not fit in the storage type "
"%(type)s"
msgstr "所選格式為 %(format)s 的磁區不適合儲存體類型%(type)s"
msgid "On s390x arch one of pool, path of dir_path must be specified"
msgstr "在 s390x 架構上,必須指定其中一個儲存區和 dir_path 的路徑"
msgid ""
"On s390x arch 'format' must be specified while attaching disk to virtual "
"machine"
msgstr "在 s390x 架構上,將磁碟連接至虛擬機器時,必須指定「格式」"
#, python-format
msgid "Virtual disk already exists on the system: %(disk_path)s"
msgstr "虛擬磁碟已經在系統上:%(disk_path)s"
#, python-format
msgid ""
"Unable to create snapshot '%(name)s' on virtual machine '%(vm)s'. Details: "
"%(err)s"
msgstr "無法在虛擬機器 '%(vm)s' 上建立 Snapshot '%(name)s'。詳細資料:%(err)s"
#, python-format
msgid "Snapshot '%(name)s' does not exist on virtual machine '%(vm)s'."
msgstr "Snapshot '%(name)s' 不在虛擬機器 '%(vm)s' 上。"
#, python-format
msgid ""
"Unable to retrieve snapshot '%(name)s' on virtual machine '%(vm)s'. Details: "
"%(err)s"
msgstr "無法擷取虛擬機器 '%(vm)s' 上的 Snapshot '%(name)s'。詳細資料:%(err)s"
#, python-format
msgid "Unable to list snapshots on virtual machine '%(vm)s'. Details: %(err)s"
msgstr "無法列出虛擬機器 '%(vm)s' 上的 Snapshot。詳細資料:%(err)s"
#, python-format
msgid ""
"Unable to delete snapshot '%(name)s' on virtual machine '%(vm)s'. Details: "
"%(err)s"
msgstr "無法刪除虛擬機器 '%(vm)s' 上的 Snapshot '%(name)s'。詳細資料:%(err)s"
#, python-format
msgid ""
"Unable to retrieve current snapshot of virtual machine '%(vm)s'. Details: "
"%(err)s"
msgstr "無法擷取虛擬機器 '%(vm)s' 的現行 Snapshot。詳細資料:%(err)s"
#, python-format
msgid ""
"Unable to revert virtual machine '%(vm)s' to snapshot '%(name)s'. Details: "
"%(err)s"
msgstr "無法將虛擬機器 '%(vm)s' 回復至 Snapshot '%(name)s'。詳細資料:%(err)s"
#, python-format
msgid ""
"Unable to create snapshot of virtual machine '%(vm)s' because it contains a "
"disk with format '%(format)s'; only 'qcow2' is supported."
msgstr ""
"無法建立虛擬機器 '%(vm)s' 的 Snapshot,因為該虛擬機器包含格式為 '%(format)s' "
"的磁碟;但卻僅支援 'qcow2'。"
msgid ""
"The number of vCPUs must be less than or equal the maximum number of vCPUs "
"specified."
msgstr "vCPU 數目必須小於或等於指定的 vCPU 數目上限。"
msgid ""
"When CPU topology is defined, maximum number of vCPUs must be a product of "
"sockets, cores, and threads."
msgstr ""
"定義 CPU 拓蹼時,vCPU 數目上限必須是 Socket 數目、核心數目與執行緒數目的乘"
"積。"
msgid "This host (or current configuration) does not allow CPU topology."
msgstr "此主機(或現行配置)不容許使用 CPU 拓蹼。"
msgid "The maximum number of vCPUs is too large for this system."
msgstr "這個系統的 vCPU 數目上限太大。"
msgid ""
"When CPU topology is defined, CPUs must be a multiple of the 'threads' "
"number defined."
msgstr ""
msgid ""
"When CPU topology is specified, sockets, cores and threads are required "
"paramaters."
msgstr "指定 CPU 拓蹼時,Socket、核心及執行緒是必要參數。"
msgid ""
"Parameter 'cpu_info' expects an object with fields among: 'vcpus', "
"'maxvcpus', 'topology'."
msgstr ""
"參數 'cpu_info' 預期具有下列欄位的物件:'vcpus'、'maxvcpus'、'topology'。"
msgid ""
"Parameter 'topology' expects an object with fields among: 'sockets', "
"'cores', 'threads'."
msgstr "參數「拓蹼」預期具有下列欄位的物件:'sockets'、'cores'、'threads'。"
msgid "Unable to update Max CPU or CPU topology when guest is running."
msgstr ""
#, python-format
msgid "Unable to hot plug/unplug CPUs. Details: %(err)s"
msgstr "無法列出儲存區。詳細資料:%(err)s"
#, python-format
msgid "Invalid volume group name parameter: %(name)s."
msgstr "磁區群組名稱參數無效:%(name)s。"
msgid ""
"Unable to establish connection with libvirt. Please check your libvirt URI "
"which is often defined in /etc/libvirt/libvirt.conf"
msgstr ""
"無法與 libvirt 建立連線。請檢查 libvirt URI,該 URI 通常是在 /etc/libvirt/"
"libvirt.conf 中予以定義"
msgid ""
"Libvirt service is not active. Please start the libvirt service in your host "
"system."
msgstr "libvirt 服務處於非作用中狀態。請在主機系統中啟動 libvirt 服務。"
msgid "Failed to register the default event implementation."
msgstr "無法登錄預設事件實作。"
msgid "Failed to register timeout event."
msgstr "無法登錄逾時事件。"
msgid "Failed to Run the default event implementation."
msgstr "無法執行預設事件實作。"
#, python-format
msgid ""
"I/O error on guest '%(vm)s': storage pool out of space for %(devAlias)s "
"(%(srcPath)s)."
msgstr ""
"客體 '%(vm)s' 上發生 I/O 錯誤:%(devAlias)s (%(srcPath)s) 的儲存區空間已用"
"完。"
#, python-format
msgid "Create virtual network '%(name)s' type '%(connection)s'"
msgstr "建立虛擬網路 '%(name)s' 類型 '%(connection)s'"
#, python-format
msgid "Remove virtual network '%(ident)s'"
msgstr "移除虛擬網路 '%(ident)s'"
#, python-format
msgid "Update virtual network '%(ident)s'"
msgstr "更新虛擬網路 '%(ident)s'"
#, python-format
msgid "Activate virtual network '%(ident)s'"
msgstr "啟動虛擬網路 '%(ident)s'"
#, python-format
msgid "Deactivate virtual network '%(ident)s'"
msgstr "取消啟動虛擬網路 '%(ident)s'"
#, python-format
msgid "Create storage pool '%(name)s' type '%(type)s'"
msgstr "建立儲存區 '%(name)s' 類型 '%(type)s'"
#, python-format
msgid "Remove storage pool '%(ident)s'"
msgstr "移除儲存區 '%(ident)s'"
#, python-format
msgid "Update storage pool '%(ident)s'"
msgstr "更新儲存區 '%(ident)s'"
#, python-format
msgid "Activate storage pool '%(ident)s'"
msgstr "啟動儲存區 '%(ident)s'"
#, python-format
msgid "Deactivate storage pool '%(ident)s'"
msgstr "取消啟動儲存區 '%(ident)s'"
#, python-format
msgid "Create snapshot '%(name)s' at guest '%(vm)s'"
msgstr "在客體 '%(vm)s' 處建立 Snapshot '%(name)s'"
#, python-format
msgid "Remove snapshot '%(ident)s' from guest '%(vm)s'"
msgstr "從客體 '%(vm)s' 中移除 Snapshot '%(ident)s'"
#, python-format
msgid "Revert guest '%(vm)s' to snapshot '%(ident)s'"
msgstr "將客體 '%(vm)s' 回復至 Snapshot '%(ident)s'"
#, python-format
msgid "Create template '%(name)s'"
msgstr "建立範本 '%(name)s'"
#, python-format
msgid "Remove template '%(ident)s'"
msgstr "移除範本 '%(ident)s'"
#, python-format
msgid "Update template '%(ident)s'"
msgstr "更新範本 '%(ident)s'"
#, python-format
msgid "Clone template '%(ident)s'"
msgstr "複製範本 '%(ident)s'"
#, python-format
msgid "Create guest '%(name)s' from template '%(template)s'"
msgstr "根據範本 '%(template)s' 建立客體 '%(name)s'"
#, python-format
msgid "Remove guest '%(ident)s'"
msgstr "移除客體 '%(ident)s'"
#, python-format
msgid "Edit guest '%(ident)s'"
msgstr "編輯客體 '%(ident)s'"
#, python-format
msgid "Start guest '%(ident)s'"
msgstr "啟動客體 '%(ident)s'"
#, python-format
msgid "Power off guest '%(ident)s'"
msgstr "關閉客體 '%(ident)s' 的電源"
#, python-format
msgid "Shutdown guest '%(ident)s'"
msgstr "關閉客體 '%(ident)s'"
#, python-format
msgid "Restart guest '%(ident)s'"
msgstr "重新啟動客體 '%(ident)s'"
#, python-format
msgid "Connect to guest '%(ident)s' through novnc/spice"
msgstr "透過 novnc/spice 連接至客體 '%(ident)s'"
#, python-format
msgid "Clone guest '%(ident)s'"
msgstr "複製客體 '%(ident)s'"
#, python-format
msgid "Migrate guest '%(ident)s' to '%(remote_host)s'"
msgstr "將客體 '%(ident)s' 移轉至 '%(remote_host)s'"
#, python-format
msgid "Suspend guest '%(ident)s'"
msgstr "暫停客體 '%(ident)s'"
#, python-format
msgid "Resume guest '%(ident)s'"
msgstr "回復客體 '%(ident)s'"
#, python-format
msgid "Connect to guest '%(ident)s' through serial"
msgstr "透過序列連接至客體 '%(ident)s'"
#, python-format
msgid "Attach host device '%(name)s' to guest '%(vmid)s'"
msgstr "將主機裝置 '%(name)s' 連接至客體 '%(vmid)s'"
#, python-format
msgid "Detach host device '%(ident)s' from guest '%(vmid)s'"
msgstr "將主機裝置 '%(ident)s' 從客體 '%(vmid)s' 分離"
#, python-format
msgid "Attach network interface '%(network)s' to guest '%(vm)s'"
msgstr "將網路介面 '%(network)s' 連接至客體 '%(vm)s'"
#, python-format
msgid "Detach network interface '%(ident)s' from guest '%(vm)s'"
msgstr "將網路介面 '%(ident)s' 從客體 '%(vm)s' 分離"
#, python-format
msgid "Update network interface '%(ident)s' at guest '%(vm)s'"
msgstr "更新客體 '%(vm)s' 處的網路介面 '%(ident)s'"
#, python-format
msgid "Attach %(type)s storage '%(path)s' to guest '%(vm)s'"
msgstr "將 %(type)s 儲存體 '%(path)s' 連接至客體 '%(vm)s'"
#, python-format
msgid "Remove storage '%(ident)s' from guest '%(vm)s'"
msgstr "從客體 '%(vm)s' 中移除儲存體 '%(ident)s'"
#, python-format
msgid "Update storage '%(ident)s' at guest '%(vm)s'"
msgstr "更新客體 '%(vm)s' 處的儲存體 '%(ident)s'"
#, python-format
msgid "Create storage volume '%(name)s' at pool '%(pool)s'"
msgstr "在儲存區 '%(pool)s' 處建立儲存磁區 '%(name)s'"
#, python-format
msgid "Remove storage volume '%(ident)s' from pool '%(pool)s'"
msgstr "從儲存區 '%(pool)s' 中移除儲存磁區 '%(ident)s'"
#, python-format
msgid "Update storage volume '%(ident)s' at pool '%(pool)s'"
msgstr "在儲存區 '%(pool)s' 處更新儲存磁區 '%(ident)s'"
#, python-format
msgid "Wipe storage volume '%(ident)s' off pool '%(pool)s'"
msgstr "從儲存區 '%(pool)s' 中清除儲存磁區 '%(ident)s'"
#, python-format
msgid "Resize storage volume '%(ident)s' at pool '%(pool)s' with size %(size)s"
msgstr "將儲存區 '%(pool)s' 處儲存磁區 '%(ident)s' 的大小調整為 %(size)s"
#, python-format
msgid "Clone storage volume '%(ident)s' at pool '%(pool)s'"
msgstr "在儲存區 '%(pool)s' 處複製儲存磁區 '%(ident)s'"
msgid "Create a New Virtual Machine"
msgstr "建立新的虛擬機器"
msgid "Virtual Machine Name"
msgstr "虛擬機器名稱"
msgid ""
"The name used to identify the virtual machine. If omitted, a name will be "
"chosen based on the template used."
msgstr "用於識別虛擬機器的名稱。如果省略,則將根據所使用的範本來選擇一個名稱。"
msgid "Please create a template first."
msgstr "請先建立範本。"
msgid "Create a Template"
msgstr "建立範本"
msgid "Please choose a template."
msgstr "請選擇範本。"
msgid "This template has invalid parameters."
msgstr "這個範本具有無效參數。"
msgid "This template has invalid parameters"
msgstr "這個範本具有無效參數"
msgid "OS"
msgstr "作業系統"
msgid "Version"
msgstr "版本"
msgid "Current CPUs"
msgstr "現行 CPU 數目"
msgid "Memory"
msgstr "記憶體"
msgid "Create"
msgstr "建立"
msgid "Creating..."
msgstr "正在建立..."
msgid "Cancel"
msgstr "取消"
msgid "Clone a Guest"
msgstr "複製客體"
msgid ""
"When the target guest has SCSI or iSCSI volumes, they will be cloned on the "
"default storage pool. The same will happen when the target pool does not "
"have enough space to clone the volumes. Do you want to continue?"
msgstr ""
"當目標客體具有 SCSI 或 iSCSI 磁區時,將在預設儲存區上複製這些磁區。當目標儲存"
"區沒有足夠的空間來複製磁區時,也會發生相同的事件。要繼續嗎?"
msgid "Number of times to clone"
msgstr "複製的次數"
msgid "Continue"
msgstr "繼續"
msgid "Edit Guest"
msgstr "編輯客體"
msgid "General"
msgstr "一般"
msgid "Storage"
msgstr "儲存體"
msgid "Interface"
msgstr "介面"
msgid "Permission"
msgstr "許可權"
msgid "Pci"
msgstr "PCI"
msgid "Snapshot"
msgstr "Snapshot"
msgid "Processor"
msgstr "處理器"
msgid "Name"
msgstr "名稱"
msgid "Memory (MB)"
msgstr "記憶體 (MB)"
msgid "More"
msgstr "更多"
msgid "Max Memory (MB)"
msgstr "記憶體上限 (MB)"
msgid "Host does not support memory hotplug"
msgstr "主機不支援記憶體熱插拔"
msgid "Icon"
msgstr "圖示"
msgid "Console"
msgstr "主控台"
msgid "Nothing selected"
msgstr "未選取任何項目"
msgid "sclp"
msgstr "sclp"
msgid "virtio"
msgstr "virtio"
msgid ""
"Select which items for boot order and grad them when needed to order them. "
"At least one option must be selected."
msgstr ""
msgid "Add"
msgstr "新增"
msgid "Device"
msgstr "裝置"
msgid "Path"
msgstr "路徑"
msgid "Actions"
msgstr "動作"
msgid "Network"
msgstr "網路"
msgid "Type"
msgstr "類型"
msgid "MAC Address"
msgstr "MAC 位址"
msgid "IP Address"
msgstr "IP 位址"
msgid "Network/Interface"
msgstr "網路/介面"
msgid "Mode"
msgstr "模式"
msgid "Available system users and groups"
msgstr "可用的系統使用者及群組"
msgid "Users"
msgstr "使用者"
msgid "Groups"
msgstr "群組"
msgid "Selected system users and groups"
msgstr "選定的系統使用者及群組"
msgid "User"
msgstr "使用者"
msgid "All"
msgstr "全部"
msgid "To Add"
msgstr "要新增"
msgid "Added"
msgstr "已新增"
msgid "Filter"
msgstr "過濾器"
msgid "Status"
msgstr "狀態"
msgid "Product"
msgstr "產品"
msgid "Vendor"
msgstr "供應商"
msgid "Loading"
msgstr "載入中"
msgid "Created"
msgstr "已建立"
msgid "Current CPU Number"
msgstr "現行 CPU 數目"
msgid ""
"Current CPU must be equal or lower than the Maximum CPU value. If a topology "
"is set, it must be also be a multiple of the 'threads' value."
msgstr ""
msgid "Max CPU"
msgstr "CPU 數目上限"
msgid ""
"Unable to edit maximum CPU or CPU topology when editing a running or paused "
"virtual machine."
msgstr ""
msgid ""
"If a topology is set, this value will be the product of sockets * times * "
"cores."
msgstr ""
msgid "Manually set CPU topology"
msgstr "手動設定 CPU 拓蹼"
msgid "Sockets"
msgstr ""
msgid "Cores"
msgstr "核心數目"
msgid "Threads"
msgstr "執行緒數目"
msgid "Save"
msgstr "儲存"
msgid "Replace"
msgstr "取代"
msgid "Detach"
msgstr "分離"
msgid "Remove"
msgstr "移除"
msgid "Edit"
msgstr "編輯"
msgid "LDAP User ID,e.g.foo@foo.com"
msgstr "LDAP 使用者 ID,例如 foo@foo.com"
msgid "Revert"
msgstr "回復"
msgid "Running"
msgstr "執行中"
msgid "Disconnected"
msgstr "已斷線"
msgid "Starting"
msgstr "啟動中"
msgid "Crashed"
msgstr "已當機"
msgid "Unknown"
msgstr "不明"
msgid "Paused"
msgstr "已暫停"
msgid "Suspended"
msgstr "已暫停"
msgid "Resetting"
msgstr "正在重設"
msgid "View Console"
msgstr "檢視主控台"
msgid "View Serial"
msgstr "檢視序列"
msgid "Clone"
msgstr "複製"
msgid "Migrate"
msgstr "移轉"
msgid "Reset"
msgstr "重設"
msgid "Pause"
msgstr "暫停"
msgid "Resume"
msgstr "回復"
msgid "Shut Down"
msgstr "關閉"
msgid "Start"
msgstr "啟動"
msgid "Power Off"
msgstr "關閉電源"
msgid "Delete"
msgstr "刪除"
msgid "No Data Available"
msgstr "沒有資料可用"
msgid "Processors Utilization"
msgstr "處理器使用率 "
msgid "Memory Utilization"
msgstr "記憶體使用率"
msgid "Storage I/O"
msgstr "儲存體 I/O"
msgid "Network I/O"
msgstr "網路 I/O"
msgid "Migrate a Guest"
msgstr "移轉客體"
msgid ""
"Disclaimer: This process cannot be stopped after started, can take a long "
"time to complete and will turn off the VM on this Hypervisor when it is "
"successfully migrated to the remote destination."
msgstr ""
"免責聲明:此程序在啟動之後無法停止,可能花費較長的時間才能完成,並且將在順利"
"移轉至遠端目的地時關閉在 Hypervisor 上的 VM。"
msgid "Remote Server"
msgstr "遠端伺服器"
msgid "IP Address or Hostname"
msgstr "IP 位址或主機名稱"
msgid ""
"The following fields are optional. Fill them if you want Kimchi to setup a "
"password-less ssh session between the localhost and the remote host. The "
"setup process will only be successful if the user has 'SUDO ALL' permission "
"in the remote machine."
msgstr ""
"下列欄位是選用項目。如果您要讓 Kimchi 在本端主機與遠端主機之間設定無密碼 SSH "
"階段作業,請填寫這些欄位。設定程序將只在使用者於遠端機器中具有 'SUDO ALL' 權"
"限時才會成功。"
msgid "Username of the remote host"
msgstr "遠端主機的使用者名稱"
msgid "Password"
msgstr "密碼"
msgid "Password of the user in the remote host"
msgstr "遠端主機中使用者的密碼"
msgid "Use RDMA transport"
msgstr ""
msgid ""
"Check this option only if RDMA is properly configured in both source and "
"destination hosts, otherwise migration will fail."
msgstr ""
msgid "Delete this VM when the migration is completed"
msgstr "在移轉完成時刪除此 VM"
msgid "Add a Storage Device to VM"
msgstr "將儲存裝置新增至 VM"
msgid "Device Type"
msgstr "裝置類型"
msgid ""
"The device type. Currently, \"cdrom\" and \"disk\" are supported. If the "
"guest is running, only \"disk\" is supported."
msgstr ""
"裝置類型。目前,支援 \"cdrom\" 和「磁碟」。如果客體處於執行中狀態,則僅支援"
"「磁碟」。"
msgid "Create a new disk"
msgstr "建立新磁碟"
msgid "Select an existing disk"
msgstr "選取現有磁碟"
msgid "Source"
msgstr "來源"
msgid "Storage based on Libvirt pool or direct block device"
msgstr "基於 libvirt 儲存區的儲存體或直接區塊裝置"
msgid "Storage Pool"
msgstr "儲存區"
msgid "Storage pool to create the volume in"
msgstr "要在其中建立磁區的儲存區"
msgid "Disk Size (GB)"
msgstr "磁碟大小 (GB)"
msgid "New disk size to be created"
msgstr "要建立的新磁碟大小"
msgid "Format"
msgstr "格式"
msgid "Format of the new disk to be created"
msgstr "要建立之新磁碟的格式"
msgid "Directory Path"
msgstr "目錄路徑"
msgid "Provide a directory path"
msgstr "提供目錄路徑"
msgid "Storage pool in which the volume is located in"
msgstr "磁區所在的儲存區"
msgid "Storage Volume"
msgstr "儲存磁區"
msgid "Storage volume to be attached"
msgstr "要連接的儲存磁區"
msgid "Disk Path"
msgstr "磁碟路徑"
msgid "Provide a block device"
msgstr "提供區塊裝置"
msgid "File Path"
msgstr "檔案路徑"
msgid "The ISO file path in the server for CDROM."
msgstr "CDROM 的 ISO 檔在伺服器中的路徑。"
msgid "Attach"
msgstr "連接"
msgid "Host"
msgstr "主機"
msgid "Guests"
msgstr "客體"
msgid "Templates"
msgstr "範本"
msgid "This is not a valid Linux path"
msgstr "這不是有效的 Linux 路徑"
msgid "Unable to read file."
msgstr "無法讀取檔案。"
msgid "Error while uploading file."
msgstr "上傳檔案時發生錯誤。"
msgid "Delete Confirmation"
msgstr "確認刪除"
msgid "OK"
msgstr "確定"
msgid "Confirm"
msgstr "確認"
msgid "Warning"
msgstr "警告"
msgid "Cloning..."
msgstr "正在複製..."
msgid "Saving..."
msgstr "正在儲存..."
msgid "Migrating..."
msgstr "正在移轉..."
msgid "No ISO found"
msgstr "找不到 ISO"
msgid "Add Template"
msgstr "新增範本"
msgid "This may take a long time. Do you want to continue?"
msgstr "這可能花費較長時間。要繼續嗎?"
msgid ""
"This will permanently delete the %1 template. Would you like to continue?"
msgstr "這將永久地刪除 %1 範本。您要繼續嗎?"
msgid "View Table"
msgstr "檢視表格"
msgid "View Gallery"
msgstr "檢視展示區"
msgid "Not Available"
msgstr "無法使用"
msgid "Please check the invalid Storage Pools"
msgstr "請檢查無效的儲存區"
msgid "Please check the invalid Storage Pools or Paths"
msgstr "請檢查無效的「儲存區」或「路徑」"
msgid "macvtap"
msgstr "macvtap"
msgid "ovs"
msgstr "ovs"
msgid "network"
msgstr "網路"
msgid ""
"This will delete the %1 virtual machine and its virtual disks. This "
"operation cannot be undone. Would you like to continue?"
msgstr "這將刪除 %1 虛擬機器及其虛擬磁碟。這項作業將無法復原。您要繼續嗎?"
msgid "Power off Confirmation"
msgstr "確認關閉電源"
msgid ""
"This action may produce undesirable results, for example unflushed disk "
"cache in the %1 guest. Would you like to continue?"
msgstr ""
"此動作可能會產生不想要的結果,例如取消清除 %1 客體中的磁碟快取。您要繼續嗎?"
msgid "Reset Confirmation"
msgstr "確認重設"
msgid ""
"There is a risk of data loss caused by reset without the %1 guest OS "
"shutdown. Would you like to continue?"
msgstr ""
"如果在不關閉 %1 客體作業系統的情況下進行重設,則可能會導致資料流失。您要繼續"
"嗎?"
msgid "Shut Down Confirmation"
msgstr "確認關閉"
msgid ""
"Note the %1 guest OS may ignore this request. Would you like to continue?"
msgstr "請注意,%1 客體作業系統可能會忽略此要求。您要繼續嗎?"
msgid "Virtual Machine delete Confirmation"
msgstr "虛擬機器刪除確認"
msgid ""
"The %1 virtual machine is not persistent. Power Off will delete it. Continue?"
msgstr "%1 虛擬機器不是持續性的。「關閉電源」會將其刪除。要繼續嗎?"
msgid "Add Guest"
msgstr ""
msgid "Input is not a number"
msgstr "輸入不是數字"
msgid "Memory value cannot be higher than Max Memory value"
msgstr "「記憶體」值不能高於「記憶體上限」值"
msgid ""
"For better performance it is recommended a threads per core value not "
"greater than %1."
msgstr ""
msgid ""
"This CDROM will be detached permanently and you can re-attach it. Continue "
"to detach it?"
msgstr "此 CDROM 將永久予以分離,並且您可以重新連接它。要繼續分離它嗎?"
msgid "Attaching..."
msgstr "正在連接..."
msgid ""
"This disk will be detached permanently and you can re-attach it. Continue to "
"detach it?"
msgstr "此磁碟將永久予以分離,並且您可以重新連接它。要繼續分離它嗎?"
msgid "interface:"
msgstr "介面:"
msgid "address:"
msgstr "位址:"
msgid "link_type:"
msgstr "鏈結類型:"
msgid "block:"
msgstr "區塊:"
msgid "drive_type:"
msgstr "磁碟機類型:"
msgid "model:"
msgstr "型號:"
msgid "Affected devices:"
msgstr "受影響的裝置:"
msgid "Less"
msgstr "更少"
msgid "Successfully attached device to VM"
msgstr "已順利將裝置連接至 VM"
msgid "Successfully detached device from VM"
msgstr "已順利從 VM 分離裝置"
msgid "Following devices will be affected, confirm?"
msgstr "下列裝置將受影響,要確認嗎?"
msgid "Bridge"
msgstr "橋接器"
msgid "Vepa"
msgstr "VEPA"
msgid "None"
msgstr "無"
msgid "unavailable"
msgstr "無法使用"
msgid ""
"This action will interrupt network connectivity for any virtual machine that "
"depend on the %1 network."
msgstr "這個動作將岔斷依賴於 %1 網路之任何虛擬機器的網路連線。"
msgid "Add Network"
msgstr ""
msgid ""
"The %1 network is not persistent. Instead of stop, this action will "
"permanently delete it. Would you like to continue?"
msgstr ""
"%1 網路不是持續性的。這個動作會將其永久地刪除,而不是將其停止。您要繼續嗎?"
msgid ""
"The bridged VLAN tag may not work well with NetworkManager enabled. You "
"should consider disabling it."
msgstr "啟用網路管理程式時,橋接 VLAN 標籤可能不正常工作。應該考量將其停用。"
msgid ""
"This will permanently delete the %1 storage pool. Would you like to continue?"
msgstr "這將永久地刪除 %1 儲存區。您要繼續嗎?"
msgid "This storage pool is empty."
msgstr "此儲存區是空的。"
msgid ""
"It will format your disk and you will loose any data in there, are you sure "
"to continue? "
msgstr "它會將磁碟進行格式化,並且您會遺失該磁碟中的所有資料,您確定要繼續嗎?"
msgid "SCSI Fibre Channel"
msgstr "SCSI 光纖通道"
msgid "No SCSI adapters found."
msgstr "找不到 SCSI 配接卡。"
msgid "Loading iSCSI targets..."
msgstr "正在載入 iSCSI 目標..."
msgid "No iSCSI found. Please input one."
msgstr "找不到 iSCSI。請輸入一個。"
msgid "Failed to load iSCSI targets."
msgstr "無法載入 iSCSI 目標。"
msgid "Would you like to continue?"
msgstr "您要繼續嗎?"
msgid "This will permanently delete the following storage volumes: %1"
msgstr "這將永久地刪除下列儲存磁區:%1"
msgid "No available partitions found."
msgstr "找不到可用的分割區。"
msgid ""
"The %1 storage pool is not persistent. Instead of deactivate, this action "
"will permanently delete it. Would you like to continue?"
msgstr ""
"%1 儲存區不是持續性的。這個動作會將其永久地刪除,而不是將其取消啟動。您要繼續"
"嗎?"
msgid "Unable to retrieve partitions information."
msgstr "無法擷取分割區資訊。"
msgid "In progress..."
msgstr "進行中..."
msgid "Failed!"
msgstr "失敗!"
msgid "No LVM found in the system."
msgstr "在系統中找不到 LVM。"
msgid "This will permanently wipe the following storage volumes: %1"
msgstr "這將永久地清除下列儲存磁區:%1"
msgid "Wipe Confirmation"
msgstr "確認清除"
msgid "Select one or more partitions to be added to the logical pool %1:"
msgstr "選取要新增至邏輯儲存區 %1 的一個以上分割區:"
msgid "Add Storage"
msgstr "新增儲存體"
msgid "DIR"
msgstr "DIR"
msgid "NFS"
msgstr "NFS"
msgid "iSCSI"
msgstr "iSCSI"
msgid "LOGICAL"
msgstr "邏輯"
msgid "device"
msgstr "裝置"
msgid "path"
msgstr "路徑"
msgid "size (GiB)"
msgstr "大小 (GiB)"
msgid "free size (GiB)"
msgstr "可用大小 (GiB)"
msgid "Invalid NFS mount path."
msgstr "NFS 裝載路徑無效。"
msgid "No logical device selected."
msgstr "未選取邏輯裝置。"
msgid "This is not a valid Server Name or IP. Please, modify it."
msgstr "這不是有效的「伺服器名稱」或 IP。請進行修改。"
msgid "CDROM path needs to be a valid local/remote path and cannot be blank."
msgstr "CDROM 路徑需要是有效的本端/遠端路徑,並且不能空白。"
msgid "Disk pool or volume cannot be blank."
msgstr "磁碟儲存區或磁區不能空白。"
msgid ""
"Disk size or Format or Directory path cannot be blank and Directory path "
"needs to be a valid local/remote path."
msgstr ""
"「磁碟大小」、「格式」或「目錄路徑」不能空白,並且「目錄路徑」需要是有效的本"
"端/遠端路徑。"
msgid "Disk path needs to be a valid local/remote path and cannot be blank."
msgstr "磁碟路徑需要是有效的本端/遠端路徑,並且不能空白。"
msgid "Storage pool or Disk size or Format cannot be blank."
msgstr "「儲存區」、「磁碟大小」或「格式」不能空白。"
msgid "cdrom"
msgstr "CDROM"
msgid "disk"
msgstr "磁碟"
msgid "Pool"
msgstr "儲存區"
msgid "qcow"
msgstr "qcow"
msgid "qcow2"
msgstr "qcow2"
msgid "qed"
msgstr "qed"
msgid "raw"
msgstr "原始"
msgid "vmdk"
msgstr "vmdk"
msgid "vpc"
msgstr "vpc"
msgid "Create a network"
msgstr "建立網路"
msgid "Network Name"
msgstr "網路名稱"
msgid "Name should not contain '/' and '\"'."
msgstr "名稱不應包含 '/' 及 '\"'。"
msgid "Network Type"
msgstr "網路類型"
msgid "Isolated: no external network connection"
msgstr "已隔離:沒有外部網路連線"
msgid "NAT: outbound physical network connection only"
msgstr "NAT:僅限出埠實體網路連線"
msgid "Macvtap: Virtual machines are connected to physical network directly"
msgstr "Macvtap:虛擬機器直接連接至實體網路"
msgid ""
"Passthrough: Virtual machines are connected using a macvtap connection in "
"passthrough mode."
msgstr "透通:在透通模式下,使用 macvtap 連線連接虛擬機器。"
msgid ""
"VEPA: special mode where virtual machines are connected to a VEPA-enabled "
"switch"
msgstr "VEPA:特殊模式,虛擬機器在其中連接至支援 VEPA 的交換器"
msgid "Bridged: Virtual machines are connected through a network bridge"
msgstr "橋接:透過網路橋接器來連接虛擬機器"
msgid "Destination"
msgstr "目的地"
msgid "Select an Interface"
msgstr "選取介面"
msgid "Enable VLAN"
msgstr "啟用 VLAN"
msgid "VLAN ID"
msgstr "VLAN ID"
msgid "Edit Network"
msgstr "編輯網路"
msgid "Address Space"
msgstr "位址空間"
msgid "Define a New Storage Pool"
msgstr "定義新的儲存區"
msgid "Storage Pool Name"
msgstr "儲存區名稱"
msgid ""
"The name used to identify the storage pools, and it should not be empty."
msgstr "該名稱用來識別儲存區,並且不應該是空的。"
msgid "Storage Pool Type"
msgstr "儲存區類型"
msgid "Storage Path"
msgstr "儲存體路徑"
msgid ""
"The path of the Storage Pool. Each Storage Pool must have a unique path."
msgstr "儲存區的路徑。每一個儲存區都必須具有唯一的路徑。"
msgid ""
"Kimchi will try to create the directory when it does not already exist in "
"your system."
msgstr "當系統中還不存在目錄時,Kimchi 將嘗試建立該目錄。"
msgid "NFS Server IP"
msgstr "NFS 伺服器 IP"
msgid "NFS server IP or hostname. It can be input or chosen from history."
msgstr ""
"NFS 伺服器 IP 或主機名稱。可以輸入該 IP 或主機名稱,也可以從歷程中進行選擇。"
msgid "NFS Path"
msgstr "NFS 路徑"
msgid "The NFS exported path on NFS server."
msgstr "NFS 伺服器上 NFS 匯出的路徑。"
msgid "Create from existing LVM"
msgstr "從現有 LVM 進行建立"
msgid "Create from raw disk"
msgstr "從原始磁碟進行建立"
msgid "Looking for existing lvms ..."
msgstr "正在尋找現有 LVM ..."
msgid "Looking for available partitions ..."
msgstr "正在尋找可用的分割區 ..."
msgid "iSCSI Server"
msgstr "iSCSI 伺服器"
msgid "Server"
msgstr "伺服器"
msgid "Port"
msgstr "埠"
msgid "iSCSI server IP or hostname. It should not be empty."
msgstr "iSCSI 伺服器 IP 或主機名稱。它不應是空的。"
msgid "Target"
msgstr "目標"
msgid "The iSCSI target on iSCSI server"
msgstr "iSCSI 伺服器上的 iSCSI 目標"
msgid "Add iSCSI Authentication"
msgstr "新增 iSCSI 鑑別"
msgid "User Name"
msgstr "使用者名稱"
msgid "SCSI Adapter"
msgstr "SCSI 配接卡"
msgid "Please, wait..."
msgstr "請稍候..."
msgid "Add a Volume to Storage Pool"
msgstr "將磁區新增至儲存區"
msgid "Fetch from remote URL"
msgstr "從遠端 URL 提取"
msgid "Enter the remote URL here."
msgstr "在這裡輸入遠端 URL。"
msgid "Upload a file"
msgstr "上傳檔案"
msgid "Choose the file you want to upload."
msgstr "選擇要上傳的檔案。"
msgid "Resize Volume"
msgstr "調整磁區的大小"
msgid "Size"
msgstr "大小"
msgid "The total space which can be used to store data. The unit is megabytes."
msgstr "可用於儲存資料的總計空間。單位是 MB。"
msgid "Ok"
msgstr "確定"
msgid "Template Name"
msgstr "範本"
msgid ""
"The name used to identify the template. If omitted, a name will be "
"automatically chosen."
msgstr "用來識別虛擬機器的名稱。如果省略,則會根據所用的範本選擇名稱。"
msgid ""
"When selecting more than one Image Template, a name will be automatically "
"chosen for each Image Template selected."
msgstr ""
msgid "Where is the source media for this template? "
msgstr "此範本的來源媒體位於何處?"
msgid "Image Template"
msgstr "映像範本"
msgid "Netboot Template"
msgstr "網路開機範本"
msgid "File Path:"
msgstr "檔案路徑:"
msgid "Search ISOs"
msgstr "搜尋 ISO"
msgid "The following ISOs are available:"
msgstr "下列 ISO 可用:"
msgid "QEMU does not have enough permission to work with this file"
msgstr "QEMU 沒有足夠的權限,無法使用此檔案"
msgid "Search more ISOs"
msgstr "搜尋更多 ISO"
msgid "Loading..."
msgstr "載入中..."
msgid "Edit Template"
msgstr "編輯範本"
msgid "CDROM"
msgstr "CDROM"
msgid "Image File"
msgstr "映像檔"
msgid "Graphics"
msgstr "圖形"
msgid "Disk(GB)"
msgstr "磁碟 (GB)"
msgid "Disk Format"
msgstr "磁碟格式"
msgid "Add Interface"
msgstr "新增介面"
msgid "pool"
msgstr "儲存區"
msgid "bridge"
msgstr "橋接器"
msgid "vepa"
msgstr "VEPA"
msgid "State"
msgstr "狀態"
msgid "Guest Name ID"
msgstr "客體名稱 ID"
msgid "OS Type"
msgstr "作業系統類型"
msgid "VNC"
msgstr "VNC"
msgid "No guests found."
msgstr "找不到客體。"
msgid "Stop"
msgstr "停止"
msgid "Location"
msgstr "位置"
msgid "%Used"
msgstr "已用百分比"
msgid "Allocated"
msgstr "已配置"
msgid "Capacity"
msgstr "容量"
msgid "Disks"
msgstr "磁碟"
msgid "Extending logical pool"
msgstr "延伸邏輯儲存區"
msgid "%"
msgstr "%"
msgid "Deactivate"
msgstr "取消啟動"
msgid "Activate"
msgstr "啟動"
msgid "Extend"
msgstr "延伸"
msgid "Undefine"
msgstr "取消定義"
msgid "Add Volume"
msgstr "新增磁區"
msgid "Resize"
msgstr "調整大小"
msgid "Wipe"
msgstr "清除"
msgid "Filter:"
msgstr "過濾:"
msgid "Used By"
msgstr "使用者"
msgid "Used"
msgstr "已用"
msgid "Progress"
msgstr "進度"
msgid "Used by the following VMs:"
msgstr "已由下列 VM 使用:"
msgid "Allocation"
msgstr "配置"
msgid "Template Name (ID)"
msgstr "範本名稱 (ID)"
msgid "No templates found."
msgstr "找不到範本。"
msgid "M"
msgstr "M"
#~ msgid "Peers"
#~ msgstr "同層級"
================================================
FILE: requirements-FEDORA.txt
================================================
================================================
FILE: requirements-OPENSUSE-LEAP.txt
================================================
pyparted
================================================
FILE: requirements-UBUNTU.txt
================================================
================================================
FILE: requirements-dev.txt
================================================
cython
libsass
pre-commit
================================================
FILE: root.py
================================================
#
# Project Kimchi
#
# Copyright IBM Corp, 2015-2017
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
import json
import os
import tempfile
import cherrypy
from wok.plugins.kimchi import config
from wok.plugins.kimchi import mockmodel
from wok.plugins.kimchi.control import sub_nodes
from wok.plugins.kimchi.i18n import messages
from wok.plugins.kimchi.model import model as kimchiModel
from wok.plugins.kimchi.utils import upgrade_objectstore_data
from wok.plugins.kimchi.utils import upgrade_objectstore_memory
from wok.plugins.kimchi.utils import upgrade_objectstore_template_disks
from wok.root import WokRoot
from wok.utils import upgrade_objectstore_schema
class Kimchi(WokRoot):
def __init__(self, wok_options):
make_dirs = [
os.path.dirname(os.path.abspath(config.get_object_store())),
os.path.abspath(config.get_distros_store()),
os.path.abspath(config.get_screenshot_path()),
os.path.abspath(config.get_virtviewerfiles_path()),
]
for directory in make_dirs:
if not os.path.isdir(directory):
os.makedirs(directory)
# When running on test mode, specify the objectstore location to
# remove the file on server shutting down. That way, the system will
# not suffer any change while running on test mode
if wok_options.test and (
wok_options.test is True or wok_options.test.lower() == 'true'
):
self.objectstore_loc = tempfile.mktemp()
self.model = mockmodel.MockModel(self.objectstore_loc)
def remove_objectstore():
if os.path.exists(self.objectstore_loc):
os.unlink(self.objectstore_loc)
cherrypy.engine.subscribe('exit', remove_objectstore)
else:
self.model = kimchiModel.Model()
dev_env = wok_options.environment != 'production'
super(Kimchi, self).__init__(self.model, dev_env)
for ident, node in sub_nodes.items():
setattr(self, ident, node(self.model))
with open(
os.path.join(os.path.dirname(
os.path.abspath(__file__)), 'API.json')
) as fd:
self.api_schema = json.load(fd)
self.paths = config.kimchiPaths
self.domain = 'kimchi'
self.messages = messages
# Some paths or URI's present in the objectstore have changed after
# Kimchi 2.0.0 release. Check here if an upgrade in the schema and data
# are necessary.
if upgrade_objectstore_schema(config.get_object_store(), 'version'):
upgrade_objectstore_data('icon', 'images', 'plugins/kimchi/')
upgrade_objectstore_data(
'storagepool', '/storagepools', '/plugins/kimchi')
upgrade_objectstore_template_disks(self.model.conn)
# Upgrade memory data, if necessary
upgrade_objectstore_memory()
def get_custom_conf(self):
return config.KimchiConfig()
================================================
FILE: scan.py
================================================
#
# Project Kimchi
#
# Copyright IBM Corp, 2015-2016
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
#
import glob
import hashlib
import os.path
import shutil
import tempfile
import time
from wok.plugins.kimchi.isoinfo import IsoImage
from wok.plugins.kimchi.isoinfo import probe_iso
from wok.utils import wok_log
SCAN_IGNORE = ['/tmp/kimchi-scan-*']
class Scanner(object):
SCAN_TTL = 300
def __init__(self, record_clean_cb):
self.clean_cb = record_clean_cb
def delete(self):
self.clean_stale(-1)
def clean_stale(self, window=SCAN_TTL):
"""
Clear scan pools generated before time window,
Clear all scan pools if window is -1.
"""
try:
now = time.time()
clean_list = glob.glob('/tmp/kimchi-scan-*')
for d in clean_list:
transient_pool = os.path.basename(
d).replace('kimchi-scan-', '')[0:-6]
if now - os.path.getmtime(d) > window:
shutil.rmtree(d)
self.clean_cb(transient_pool)
except OSError as e:
msg = f'Exception {e} occured when cleaning stale pool, ignore'
wok_log.debug(msg)
def scan_dir_prepare(self, name):
# clean stale scan storage pools
self.clean_stale()
return tempfile.mkdtemp(prefix='kimchi-scan-' + name, dir='/tmp')
def start_scan(self, cb, params):
def updater(iso_info):
iso_name = os.path.basename(iso_info['path'])[:-3]
duplicates = '%s/%s*' % (params['pool_path'], iso_name)
for f in glob.glob(duplicates):
iso_img = IsoImage(f)
if (iso_info['distro'], iso_info['version']) == iso_img.probe():
return
iso_path = (
iso_name +
hashlib.md5(iso_info['path'].encode('utf-8')).hexdigest() +
'.iso'
)
link_name = os.path.join(
params['pool_path'], os.path.basename(iso_path))
os.symlink(iso_info['path'], link_name)
ignore_paths = params.get('ignore_list', [])
scan_params = dict(
path=params['scan_path'],
updater=updater,
ignore_list=ignore_paths + SCAN_IGNORE,
)
probe_iso(None, scan_params)
cb('', True)
================================================
FILE: screenshot.py
================================================
#
# Project Kimchi
#
# Copyright IBM Corp, 2015-2016
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
#
import glob
import os
import signal
import tempfile
import time
import uuid
try:
from PIL import Image
except ImportError:
import Image
from wok.utils import wok_log
from wok.plugins.kimchi import config
(fd, pipe) = tempfile.mkstemp()
stream_test_result = None
class VMScreenshot(object):
OUTDATED_SECS = 5
THUMBNAIL_SIZE = (256, 256)
LIVE_WINDOW = 60
MAX_STREAM_ATTEMPTS = 10
def __init__(self, args):
self.vm_uuid = args['uuid']
args.setdefault('thumbnail',
os.path.join(config.get_screenshot_path(),
'%s-%s.png' %
(self.vm_uuid, str(uuid.uuid4()))))
self.info = args
@staticmethod
def get_stream_test_result():
return stream_test_result
def lookup(self):
now = time.time()
try:
last_update = os.path.getmtime(self.info['thumbnail'])
except OSError:
last_update = 0
if now - last_update > self.OUTDATED_SECS:
self._clean_extra(self.LIVE_WINDOW)
self._generate_thumbnail()
return 'plugins/kimchi/data/screenshots/%s' %\
os.path.basename(self.info['thumbnail'])
def _clean_extra(self, window=-1):
"""
Clear screenshots before time specified by window,
Clear all screenshots if window is -1.
"""
try:
now = time.time()
clear_list = glob.glob('%s/%s-*.png' %
(config.get_screenshot_path(),
self.vm_uuid))
for f in clear_list:
if now - os.path.getmtime(f) > window:
os.unlink(f)
except OSError:
pass
def delete(self):
return self._clean_extra()
def _generate_scratch(self, thumbnail):
"""
Generate screenshot of given vm.
Override me in child class.
"""
pass
def _create_black_image(self, thumbnail):
image = Image.new('RGB', self.THUMBNAIL_SIZE, 'black')
image.save(thumbnail)
def _watch_stream_creation(self, thumbnail):
"""
This is a verification test for libvirt stream functionality.
It is necessary to avoid the server hangs while creating the screenshot
image using libvirt stream API.
This problem was found in libvirt 0.9.6 for SLES11 SP2.
This test consists in running the screeshot creation with a timeout.
If timeout occurs, the libvirt is taking too much time to create the
screenshot image and the stream must be disabled it if happens
successively (to avoid blocking server requests).
"""
pid = os.fork()
if pid == 0:
try:
self._generate_scratch(thumbnail)
os._exit(0)
except Exception:
os._exit(1)
else:
counter = 0
ret = os.waitpid(pid, os.WNOHANG)
while ret == (0, 0) and counter < 3:
counter += 1
time.sleep(1)
ret = os.waitpid(pid, os.WNOHANG)
fd = open(pipe, 'a')
if ret != (pid, 0):
fd.write('-')
if ret[0] != pid:
os.kill(int(pid), signal.SIGKILL)
os.waitpid(pid, 0)
else:
fd.write('+')
fd.close()
def _get_test_result(self):
if not os.path.exists(pipe):
return
fd = open(pipe, 'r')
data = fd.read()
fd.close()
if len(data) >= self.MAX_STREAM_ATTEMPTS or bool('+' in data):
global stream_test_result
stream_test_result = bool('+' in data)
os.remove(pipe)
def _generate_thumbnail(self):
thumbnail = os.path.join(config.get_screenshot_path(), '%s-%s.png' %
(self.vm_uuid, str(uuid.uuid4())))
self._get_test_result()
if stream_test_result is None:
self._watch_stream_creation(thumbnail)
elif stream_test_result:
try:
self._generate_scratch(thumbnail)
except Exception:
wok_log.error('screenshot_creation: Unable to create '
'screenshot image %s.' % thumbnail)
else:
self._create_black_image(thumbnail)
if os.path.getsize(thumbnail) == 0:
self._create_black_image(thumbnail)
else:
im = Image.open(thumbnail)
try:
# Prevent Image lib from lazy load,
# work around pic truncate validation in thumbnail generation
im.thumbnail(self.THUMBNAIL_SIZE)
except Exception as e:
wok_log.warning('Image load with warning: %s.' % e)
im.save(thumbnail, 'PNG')
self.info['thumbnail'] = thumbnail
================================================
FILE: serialconsole.py
================================================
#
# Project Kimchi
#
# Copyright IBM Corp, 2016
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
#
import os
import socket
import sys
import threading
import time
from multiprocessing import Process
import libvirt
from wok.config import config as wok_config
from wok.plugins.kimchi import model
from wok.utils import wok_log
SOCKET_QUEUE_BACKLOG = 0
CTRL_Q = '\x11'
BASE_DIRECTORY = '/run'
class SocketServer(Process):
"""Unix socket server for guest console access.
Implements a unix socket server for each guest, this server will receive
data from a particular client, forward that data to the guest console,
receive the response from the console and send the response back to the
client.
Features:
- one socket server per client connection;
- server listens to unix socket;
- exclusive connection per guest;
- websockity handles the proxy between the client websocket to the
local unix socket;
Note:
- old versions (< 0.6.0)of websockify don't handle their children
processes accordingly, leaving a zombie process behind (this also
happens with novnc).
"""
def __init__(self, guest_name, URI):
"""Constructs a unix socket server.
Listens to connections on /run/.
"""
Process.__init__(self)
self._guest_name = guest_name
self._uri = URI
self._server_addr = os.path.join(BASE_DIRECTORY, guest_name)
if os.path.exists(self._server_addr):
raise RuntimeError(
'There is an existing connection to %s' % guest_name)
self._socket = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
self._socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
self._socket.bind(self._server_addr)
self._socket.listen(SOCKET_QUEUE_BACKLOG)
wok_log.info('[%s] socket server to guest %s created',
self.name, guest_name)
def run(self):
"""Implements customized run method from Process.
"""
self.listen()
def _is_vm_listening_serial(self, console):
"""Checks if the guest is listening (reading/writing) to the serial
console.
"""
is_listening = []
def _test_output(stream, event, opaque):
is_listening.append(1)
def _event_loop():
while not is_listening:
libvirt.virEventRunDefaultImpl()
console.eventAddCallback(
libvirt.VIR_STREAM_EVENT_READABLE, _test_output, None)
libvirt_loop = threading.Thread(target=_event_loop)
libvirt_loop.start()
console.send(b'\n')
libvirt_loop.join(1)
if not libvirt_loop.is_alive():
console.eventRemoveCallback()
return True
console.eventRemoveCallback()
return False
def _send_to_client(self, stream, event, opaque):
"""Handles libvirt stream readable events.
Each event will be send back to the client socket.
"""
try:
data = stream.recv(1024)
except Exception as e:
wok_log.info(
'[%s] Error when reading from console: %s', self.name, str(e))
return
# return if no data received or client socket(opaque) is not valid
if not data or not opaque:
return
opaque.send(data)
def libvirt_event_loop(self, guest, client):
"""Runs libvirt event loop.
"""
# stop the event loop when the guest is not running
while guest.is_running():
libvirt.virEventRunDefaultImpl()
# shutdown the client socket to unblock the recv and stop the
# server as soon as the guest shuts down
client.shutdown(socket.SHUT_RD)
def listen(self):
"""Prepares the environment before starts to accept connections
Initializes and destroy the resources needed to accept connection.
"""
libvirt.virEventRegisterDefaultImpl()
try:
guest = LibvirtGuest(self._guest_name, self._uri, self.name)
except Exception as e:
wok_log.error(
'[%s] Cannot open the guest %s due to %s',
self.name,
self._guest_name,
str(e),
)
self._socket.close()
sys.exit(1)
except (KeyboardInterrupt, SystemExit):
self._socket.close()
sys.exit(1)
console = None
try:
console = guest.get_console()
if console is None:
wok_log.error(
'[%s] Cannot get the console to %s', self.name, self._guest_name
)
return
if not self._is_vm_listening_serial(console):
sys.exit(1)
self._listen(guest, console)
# clear resources aquired when the process is killed
except (KeyboardInterrupt, SystemExit):
pass
finally:
wok_log.info(
'[%s] Shutting down the socket server to %s console',
self.name,
self._guest_name,
)
self._socket.close()
if os.path.exists(self._server_addr):
os.unlink(self._server_addr)
try:
console.eventRemoveCallback()
except Exception as e:
wok_log.info(
'[%s] Callback is probably removed: %s', self.name, str(e))
guest.close()
def _listen(self, guest, console):
"""Accepts client connections.
Each connection is directly linked to the desired guest console. Thus
any data received from the client can be send to the guest console as
well as any response from the guest console can be send back to the
client console.
"""
client, client_addr = self._socket.accept()
session_timeout = wok_config.get('server', 'session_timeout')
client.settimeout(int(session_timeout) * 60)
wok_log.info('[%s] Client connected to %s',
self.name, self._guest_name)
# register the callback to receive any data from the console
console.eventAddCallback(
libvirt.VIR_STREAM_EVENT_READABLE, self._send_to_client, client
)
# start the libvirt event loop in a python thread
libvirt_loop = threading.Thread(
target=self.libvirt_event_loop, args=(guest, client)
)
libvirt_loop.start()
while True:
data = ''
try:
data = client.recv(1024)
except Exception as e:
wok_log.info(
'[%s] Client disconnected from %s: %s',
self.name,
self._guest_name,
str(e),
)
break
if not data or data == CTRL_Q:
break
# if the console can no longer be accessed, close everything
# and quits
try:
console.send(data)
except Exception:
wok_log.info(
'[%s] Console of %s is not accessible', self.name, self._guest_name
)
break
# clear used resources when the connection is closed and, if possible,
# tell the client the connection was lost.
try:
client.send(b'\\r\\n\\r\\nClient disconnected\\r\\n')
except Exception:
pass
# socket_server
class LibvirtGuest(object):
def __init__(self, guest_name, uri, process_name):
"""
Constructs a guest object that opens a connection to libvirt and
searchs for a particular guest, provided by the caller.
"""
self._proc_name = process_name
try:
libvirt = model.libvirtconnection.LibvirtConnection(uri)
self._guest = model.vms.VMModel.get_vm(guest_name, libvirt)
except Exception as e:
wok_log.error(
'[%s] Cannot open guest %s: %s', self._proc_name, guest_name, str(
e)
)
raise
self._libvirt = libvirt.get()
self._name = guest_name
self._stream = None
def is_running(self):
"""
Checks if this guest is currently in a running state.
"""
return (
self._guest.state(0)[0] == libvirt.VIR_DOMAIN_RUNNING or
self._guest.state(0)[0] == libvirt.VIR_DOMAIN_PAUSED
)
def get_console(self):
"""
Opens a console to this guest and returns a reference to it.
Note: If another instance (eg: virsh) has an existing console opened
to this guest, this code will steal that console.
"""
# guest must be in a running state to get its console
counter = 10
while not self.is_running():
wok_log.info(
'[%s] Guest %s is not running, waiting for it',
self._proc_name,
self._name,
)
counter -= 1
if counter <= 0:
return None
time.sleep(1)
# attach a stream in the guest console so we can read from/write to it
if self._stream is None:
wok_log.info(
'[%s] Opening the console for guest %s', self._proc_name, self._name
)
self._stream = self._libvirt.newStream(libvirt.VIR_STREAM_NONBLOCK)
self._guest.openConsole(
None,
self._stream,
libvirt.VIR_DOMAIN_CONSOLE_FORCE | libvirt.VIR_DOMAIN_CONSOLE_SAFE,
)
return self._stream
def close(self):
"""Closes the libvirt connection.
"""
self._libvirt.close()
# guest
def main(guest_name, URI='qemu:///system'):
"""Main entry point to create a socket server.
Starts a new socket server to listen messages to/from the guest.
"""
server = None
try:
server = SocketServer(guest_name, URI)
except Exception as e:
wok_log.error('Cannot create the socket server: %s', str(e))
raise
server.start()
return server
if __name__ == '__main__':
"""Executes a stand alone instance of the socket server.
This may be useful for testing/debugging.
In order to debug, add the path before importing kimchi/wok code:
sys.path.append('../../../')
start the server:
python serialconsole.py
and, on another terminal, run:
netcat -U /run/
"""
argc = len(sys.argv)
if argc != 2:
print(f'usage: ./{sys.argv[0]} ')
sys.exit(1)
main(sys.argv[1])
================================================
FILE: setup.cfg
================================================
[pycodestyle]
ignore = E226,E302,E41,W503,W504,E741
max-line-length = 88
================================================
FILE: template.conf
================================================
#
# Configuration file for Kimchi Templates
#
[main]
# List of networks separated by comma
# Represents the virtual network interfaces to be assigned to guest
#networks = default,
[memory]
# Memory in MB
# current = 1024
# Maximum value of memory to be assigned to guest in MB
# maxmemory = 1024
[storage]
# Specify multiple [[disk.X]] sub-sections to add multiples disks to guest
# Each disk files will be created in respective storage pool set
[[disk.0]]
# Disk size in GB
#size = 10
# Disk format
#format = qcow2
# Storage pool used to handle the guest disk
#pool = default
# Only Applicable for s390x. Storage path used to handle the guest disk.
# In Each disk, pool and path are mutually exclusive parameters and
# pool will be ignored in case of both specified.
#path = /var/lib/libvirt/images
[graphics]
# Graphics type
# Valid options: vnc | spice
#type = vnc
# The network which the vnc/spice server listens on
#listen = 127.0.0.1
[processor]
# Number of vcpus
# When specifying CPU topology, make sure maxvcpus value is equal to the
# product of sockets, cores, and threads.
#vcpus = 1
#maxvcpus = 1
# Number of sockets (not set by default)
#sockets =
# Number of cores per socket (not set by default)
#cores =
# Number of threads per core (not set by default)
#threads =
================================================
FILE: tests/Makefile.am
================================================
#
# Kimchi
#
# Copyright IBM Corp, 2013-2016
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
EXTRA_DIST = \
Makefile.am \
run_tests.sh.in \
test_config.py.in \
$(filter-out test_config.py, $(wildcard *.py)) \
$(NULL)
noinst_SCRIPTS = run_tests.sh
do_substitution = \
sed -e 's,[@]HAVE_PYMOD_UNITTEST[@],$(HAVE_PYMOD_UNITTEST),g' \
-e 's,[@]prefix[@],$(prefix),g' \
-e 's,[@]datadir[@],$(datadir),g' \
-e 's,[@]PYTHON_VERSION[@],$(PYTHON_VERSION),g' \
-e 's,[@]wokdir[@],$(pythondir)/wok,g' \
-e 's,[@]pkgdatadir[@],$(pkgdatadir),g'
run_tests.sh: run_tests.sh.in Makefile
$(do_substitution) < $(srcdir)/run_tests.sh.in > run_tests.sh
chmod +x run_tests.sh
test_config.py: test_config.py.in Makefile
$(do_substitution) < $(srcdir)/test_config.py.in > test_config.py
check-local:
$(MKDIR_P) $(top_srcdir)/data/screenshots
./run_tests.sh
BUILT_SOURCES = test_config.py
CLEANFILES = run_tests.sh test_config.py
================================================
FILE: tests/iso_gen.py
================================================
#
# Project Kimchi
#
# Copyright IBM Corp, 2013-2016
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
import platform
import struct
from wok.plugins.kimchi.isoinfo import IsoImage
iso_des = [
('openbsd', lambda v: True, lambda v: 'OpenBSD/i386 %s Install CD' % v),
('centos', lambda v: True, lambda v: 'CentOS_%s_Final' % v),
('windows', '2000', 'W2AFPP'),
('windows', 'xp', 'WXPFPP'),
('windows', '2003', 'ARMECHK'),
('windows', '2003r2', 'CRMEFPP'),
('windows', '2008', 'KRTMSVOL'),
('windows', '2008r2', 'GRMSXVOL'),
('windows', 'vista', 'FB1EVOL'),
('windows', '7', 'GRMCULFRER'),
('windows', '8', 'HB1_CCPA_X86FRE'),
('sles', '10', 'SLES10'),
('sles', '11', 'SUSE_SLES-11-0-0'),
('opensuse', '11.1', 'SU1110.001'),
('opensuse', '11.3', 'openSUSE-DVD-x86_64.0702..001'),
('opensuse', '11.4', 'openSUSE-DVD-x86_640024'),
('opensuse', '12.1', 'openSUSE-DVD-x86_640039'),
('opensuse', '12.2', 'openSUSE-DVD-x86_640167'),
('opensuse', lambda v: True, lambda v: 'openSUSE-%s' % v),
('rhel', '4.8', 'RHEL/4-U8'),
('rhel', lambda v: v.startswith('6.'), lambda v: 'RHEL_%s' % v),
('debian', lambda v: True, lambda v: 'Debian %s' % v),
(
'ubuntu',
lambda v: v
in (
'7.10',
'8.04',
'8.10',
'9.04',
'9.10',
'10.04',
'10.10',
'11.04',
'11.10',
'12.04',
'12.10',
'13.04',
'13.10',
'14.04',
),
lambda v: 'Ubuntu %s' % v,
),
('fedora', lambda v: v in ('16', '17', '18', '19'), lambda v: 'Fedora %s' % v),
]
class FakeIsoImage(object):
def _build_iso(self, fd, iso_volid, bootable):
if platform.machine().startswith('ppc'):
self._build_powerpc_bootable_iso(fd, iso_volid)
return
self._build_intel_iso(fd, iso_volid, bootable)
def _build_powerpc_bootable_iso(self, fd, iso_volid):
self._build_prim_vol(fd, iso_volid)
self._build_bootable_ppc_path_table(fd)
def _build_intel_iso(self, fd, iso_volid, bootable):
# Do not change the order of the method calls
self._build_el_boot(fd, bootable)
self._build_prim_vol(fd, iso_volid)
self._build_el_torito(fd)
def _build_prim_vol(self, fd, iso_volid):
fd.seek(16 * IsoImage.SECTOR_SIZE)
fmt = IsoImage.VOL_DESC
vd_type = 1
vd_ident = b'CD001'
vd_ver = 1
pad0 = 1
sys_id = b'fake os'
vol_id = iso_volid.encode('utf-8')
data = (vd_type, vd_ident, vd_ver, pad0, sys_id, vol_id)
s = fmt.pack(*data)
fd.write(s)
self._add_sector_padding(fd, s)
def _add_sector_padding(self, fd, s):
padding_len = IsoImage.SECTOR_SIZE - len(s)
fmt = struct.Struct('=%ss' % padding_len)
s = fmt.pack(b'a' * padding_len)
fd.write(s)
def _build_el_torito(self, fd):
fmt = IsoImage.EL_TORITO_BOOT_RECORD
vd_type = 0
vd_ident = b'CD001'
vd_ver = 1
et_ident = b'EL TORITO SPECIFICATION:'
pad0 = b'a' * 32
boot_cat = 0
data = (vd_type, vd_ident, vd_ver, et_ident, pad0, boot_cat)
s = fmt.pack(*data)
fd.write(s)
self._add_sector_padding(fd, s)
def _build_el_boot(self, fd, bootable):
fmt = IsoImage.EL_TORITO_VALIDATION_ENTRY
hdr_id = 0
platform_id = 0
pad0 = 1
ident = b'c' * 24
csum = 1
key55 = 0x55
keyAA = 0xAA
data = (hdr_id, platform_id, pad0, ident, csum, key55, keyAA)
s = fmt.pack(*data)
fd.write(s)
fmt = IsoImage.EL_TORITO_BOOT_ENTRY
if bootable:
boot = 0x88
else:
boot = 0
media_type = 1
load_seg = 1
sys_type = 1
pad0 = 1
sectors = 1
load_rba = 1
data = (boot, media_type, load_seg, sys_type, pad0, sectors, load_rba)
s = fmt.pack(*data)
fd.write(s)
s = b'a' * IsoImage.SECTOR_SIZE
fd.write(s)
def _build_bootable_ppc_path_table(self, fd):
# write path table locator
PATH_TABLE_LOC_OFFSET = 16 * IsoImage.SECTOR_SIZE + 132
PATH_TABLE_SIZE_LOC = struct.Struct('&1)
RES=$?
if [ $RES -ne 0 ]; then
# unit test has failed, so keep the OUTPUT_FILE and print the results
STATS=$(echo "$OUTPUT" | grep "Ran")
echo -e "\t ${RED}FAILED${NC} - $STATS"
ERROR_LOG_BEGIN=$(echo "$OUTPUT" | grep -n "^\==*" | head -n1 | cut -d":" -f1)
ERROR_LOG_END=$(echo "$OUTPUT" | wc -l)
echo "$OUTPUT" | tail -n $((${ERROR_LOG_END}-${ERROR_LOG_BEGIN}+1))
FAILED_UT+=([$UT]=$(echo "$OUTPUT" | grep FAILED | cut -d" " -f2-4))
echo "$OUTPUT" >> $OUTPUT_FILE
else
# unit test has passed, so print the results and delete the OUTPUT_FILE
STATS=$(echo "$OUTPUT" | grep "Ran")
echo -e "\t ${GREEN}PASSED${NC} - $STATS"
fi
TES=$(echo $STATS | cut -d" " -f2)
NUM_TESTS=$(echo "$NUM_TESTS + $TES" | bc)
TES=$(echo $STATS | cut -d" " -f5)
TIME=$(echo "$TIME + ${TES:0:-1}" | bc)
done
# Print summary results
echo -e "======================================================================"
echo -e "===================== Kimchi Unit Tests Summary ======================"
echo -e "Ran $NUM_TESTS tests in $TIME seconds."
for i in "${!FAILED_UT[@]}"; do
echo -e "$i FAILED: ${FAILED_UT[$i]} - full log available at $OUTPUT_FILE"
done
================================================
FILE: tests/test_authorization.py
================================================
#
# Project Kimchi
#
# Copyright IBM Corp, 2014-2017
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
import json
import os
import unittest
from functools import partial
import cherrypy
import mock
from iso_gen import construct_fake_iso
from tests.utils import patch_auth
from tests.utils import request
from tests.utils import run_server
from tests.utils import wait_task
test_server = None
model = None
fake_iso = '/tmp/fake.iso'
def setUpModule():
global test_server, model
patch_auth()
test_server = run_server(test_mode=True)
model = cherrypy.tree.apps['/plugins/kimchi'].root.model
# Create fake ISO to do the tests
construct_fake_iso(fake_iso, True, '12.04', 'ubuntu')
def tearDownModule():
test_server.stop()
os.unlink(fake_iso)
class AuthorizationTests(unittest.TestCase):
def setUp(self):
self.request = partial(request, user='user')
model.reset()
@mock.patch('wok.plugins.kimchi.model.users.PAMUsersModel._validate')
def test_nonroot_access(self, validate_users):
validate_users.return_value = True
# Non-root users can not create or delete network (only get)
resp = self.request('/plugins/kimchi/networks', '{}', 'GET')
self.assertEqual(200, resp.status)
resp = self.request('/plugins/kimchi/networks', '{}', 'POST')
self.assertEqual(403, resp.status)
resp = self.request(
'/plugins/kimchi/networks/default/activate', '{}', 'POST')
self.assertEqual(403, resp.status)
resp = self.request('/plugins/kimchi/networks/default', '{}', 'DELETE')
self.assertEqual(403, resp.status)
# Non-root users can not create or delete storage pool (only get)
resp = self.request('/plugins/kimchi/storagepools', '{}', 'GET')
self.assertEqual(200, resp.status)
resp = self.request('/plugins/kimchi/storagepools', '{}', 'POST')
self.assertEqual(403, resp.status)
resp = self.request(
'/plugins/kimchi/storagepools/default/activate', '{}', 'POST'
)
self.assertEqual(403, resp.status)
resp = self.request(
'/plugins/kimchi/storagepools/default', '{}', 'DELETE')
self.assertEqual(403, resp.status)
# Non-root users can not update or delete a template
# but he can get and create a new one
resp = self.request('/plugins/kimchi/templates', '{}', 'GET')
self.assertEqual(403, resp.status)
req = json.dumps({'name': 'test', 'source_media': fake_iso})
resp = self.request('/plugins/kimchi/templates', req, 'POST')
self.assertEqual(403, resp.status)
resp = self.request('/plugins/kimchi/templates/test', '{}', 'PUT')
self.assertEqual(403, resp.status)
resp = self.request('/plugins/kimchi/templates/test', '{}', 'DELETE')
self.assertEqual(403, resp.status)
# Non-root users can only get vms authorized to them
model.templates_create(
{'name': u'test', 'source_media': {'type': 'disk', 'path': fake_iso}}
)
task_info = model.vms_create(
{'name': u'test-me', 'template': '/plugins/kimchi/templates/test'}
)
wait_task(model.task_lookup, task_info['id'])
model.vm_update(u'test-me', {'users': ['user'], 'groups': []})
task_info = model.vms_create(
{'name': u'test-usera', 'template': '/plugins/kimchi/templates/test'}
)
wait_task(model.task_lookup, task_info['id'])
non_root = list(set(model.users_get_list()) - set(['admin']))[0]
model.vm_update(u'test-usera', {'users': [non_root], 'groups': []})
task_info = model.vms_create(
{'name': u'test-groupa', 'template': '/plugins/kimchi/templates/test'}
)
wait_task(model.task_lookup, task_info['id'])
a_group = model.groups_get_list()[0]
model.vm_update(u'test-groupa', {'groups': [a_group]})
resp = self.request('/plugins/kimchi/vms', '{}', 'GET')
self.assertEqual(200, resp.status)
vms_data = json.loads(resp.read())
self.assertEqual(
[u'test-groupa', u'test-me'], sorted([v['name'] for v in vms_data])
)
resp = self.request('/plugins/kimchi/vms', req, 'POST')
self.assertEqual(403, resp.status)
# Create a vm using mockmodel directly to test Resource access
task_info = model.vms_create(
{'name': 'kimchi-test', 'template': '/plugins/kimchi/templates/test'}
)
wait_task(model.task_lookup, task_info['id'])
resp = self.request('/plugins/kimchi/vms/kimchi-test', '{}', 'PUT')
self.assertEqual(403, resp.status)
resp = self.request('/plugins/kimchi/vms/kimchi-test', '{}', 'DELETE')
self.assertEqual(403, resp.status)
# Non-root users can only update VMs authorized by them
resp = self.request('/plugins/kimchi/vms/test-me/start', '{}', 'POST')
self.assertEqual(200, resp.status)
resp = self.request(
'/plugins/kimchi/vms/test-usera/start', '{}', 'POST')
self.assertEqual(403, resp.status)
model.template_delete('test')
model.vm_delete('test-me')
================================================
FILE: tests/test_config.py.in
================================================
#
# Project Kimchi
#
# Copyright IBM Corp, 2014-2017
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
import unittest
from cherrypy.lib.reprconf import Parser
from wok.config import CACHEEXPIRES
from wok.config import Paths, PluginPaths
from wok.plugins.kimchi.config import get_screenshot_path
from wok.plugins.kimchi.config import get_virtviewerfiles_path
from wok.plugins.kimchi.config import KimchiConfig, KimchiPaths
get_prefix = None
def setUpModule():
global get_prefix
get_prefix = Paths.get_prefix
def tearDownModule():
Paths.get_prefix = KimchiPaths.get_prefix = get_prefix
class ConfigTests(unittest.TestCase):
def assertInstalledPath(self, actual, expected):
if '@pkgdatadir@' != '/usr/share/kimchi':
usr_local = '/usr/local'
if not expected.startswith('/usr'):
expected = usr_local + expected
self.assertEqual(actual, expected)
def test_installed_plugin_paths(self):
KimchiPaths.get_prefix = lambda self: '@datadir@/wok'
paths = KimchiPaths()
self.assertInstalledPath(paths.conf_dir, '/etc/wok/plugins.d')
self.assertInstalledPath(paths.conf_file,
'/etc/wok/plugins.d/kimchi.conf')
self.assertInstalledPath(paths.src_dir, '@wokdir@/plugins/kimchi')
self.assertInstalledPath(paths.ui_dir,
'@datadir@/wok/plugins/kimchi/ui')
self.assertInstalledPath(paths.mo_dir, '@prefix@/share/locale')
def test_uninstalled_plugin_paths(self):
paths = KimchiPaths()
prefix = paths.prefix
self.assertEqual(paths.conf_dir, '%s/src/wok/plugins/kimchi' % prefix)
self.assertEqual(paths.conf_file,
'%s/src/wok/plugins/kimchi/kimchi.conf' % prefix)
self.assertEqual(paths.src_dir, '%s/src/wok/plugins/kimchi' % prefix)
self.assertEqual(paths.ui_dir,
'%s/src/wok/plugins/kimchi/ui' % prefix)
self.assertEqual(paths.mo_dir,
'%s/src/wok/plugins/kimchi/mo' % prefix)
def test_kimchi_config(self):
KimchiPaths.get_prefix = PluginPaths.get_prefix = get_prefix
paths = KimchiPaths()
pluginPrefix = paths.add_prefix(paths.plugin_dir)
configObj = {
'wok': {
'enable': True
},
'kimchi': {
'create_iso_pool': True,
'take_screenshot': True
},
'/': {
'tools.trailing_slash.on': False,
'request.methods_with_bodies': ('POST', 'PUT'),
'tools.nocache.on': True,
'tools.proxy.on': True,
'tools.sessions.on': True,
'tools.sessions.name': 'wok',
'tools.sessions.secure': True,
'tools.sessions.httponly': True,
'tools.sessions.locking': 'explicit',
'tools.sessions.storage_type': 'ram'
},
'/novnc': {
'tools.wokauth.on': True,
'tools.nocache.on': True,
'tools.staticdir.dir': paths.novnc_dir,
'tools.staticdir.on': True
},
'/spice-html5': {
'tools.wokauth.on': True,
'tools.nocache.on': True,
'tools.staticdir.dir': paths.spice_dir,
'tools.staticdir.on': True
},
'/spice-web-client': {
'tools.wokauth.on': True,
'tools.nocache.on': True,
'tools.staticdir.dir': paths.spice_dir,
'tools.staticdir.on': True
},
'/spice_auto.html': {
'tools.wokauth.on': True,
'tools.nocache.on': True,
'tools.staticfile.on': True,
'tools.staticfile.filename': paths.spice_file,
},
'/spice-html5/spice.css': {
'tools.wokauth.on': True,
'tools.nocache.on': True,
'tools.staticfile.on': True,
'tools.staticfile.filename': paths.spice_css_file,
},
'/help': {
'tools.nocache.on': True,
'tools.staticdir.dir': '%s/ui/pages/help' % pluginPrefix,
'tools.staticdir.on': True
},
'/js': {
'tools.wokauth.on': False,
'tools.nocache.on': False,
'tools.staticdir.dir': '%s/ui/js' % pluginPrefix,
'tools.expires.on': True,
'tools.expires.secs': CACHEEXPIRES,
'tools.staticdir.on': True
},
'/css': {
'tools.wokauth.on': False,
'tools.nocache.on': False,
'tools.staticdir.dir': '%s/ui/css' % pluginPrefix,
'tools.expires.on': True,
'tools.expires.secs': CACHEEXPIRES,
'tools.staticdir.on': True
},
'/images': {
'tools.wokauth.on': False,
'tools.nocache.on': False,
'tools.staticdir.dir': '%s/ui/images' % pluginPrefix,
'tools.staticdir.content_types': {'svg': 'image/svg+xml'},
'tools.staticdir.on': True
},
'/data/screenshots': {
'tools.nocache.on': False,
'tools.staticdir.dir': get_screenshot_path(),
'tools.staticdir.on': True
},
'/data/virtviewerfiles': {
'tools.nocache.on': False,
'tools.staticdir.dir': get_virtviewerfiles_path(),
'tools.staticdir.on': True
},
'/ui/config/tab-ext.xml': {
'tools.nocache.on': True,
'tools.staticfile.on': True,
'tools.staticfile.filename': '%s/ui/config/tab-ext.xml' %
pluginPrefix,
},
'/serial': {
'tools.nocache.on': True,
'tools.wokauth.on': True,
'tools.staticdir.dir': paths.serial_dir,
'tools.staticdir.on': True
},
}
kimchi_config = Parser().dict_from_file(KimchiPaths().conf_file)
kimchi_config.update(KimchiConfig())
self.assertEqual(kimchi_config, configObj)
================================================
FILE: tests/test_disks.py
================================================
#
# Project Kimchi
#
# Copyright IBM Corp, 2017
#
# Code derived from Ginger Base
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
import unittest
import mock
from wok.exception import NotFoundError
from wok.exception import OperationFailed
from wok.plugins.kimchi.disks import _get_lsblk_devs
class DiskTests(unittest.TestCase):
@mock.patch('wok.plugins.kimchi.disks.run_command')
def test_lsblk_returns_404_when_device_not_found(self, mock_run_command):
mock_run_command.return_value = ['', 'not a block device', 32]
fake_dev = '/not/a/true/block/dev'
keys = ['MOUNTPOINT']
with self.assertRaises(NotFoundError):
_get_lsblk_devs(keys, [fake_dev])
cmd = ['lsblk', '-Pbo', 'MOUNTPOINT', fake_dev]
mock_run_command.assert_called_once_with(cmd)
@mock.patch('wok.plugins.kimchi.disks.run_command')
def test_lsblk_returns_500_when_unknown_error_occurs(
self, mock_run_command):
mock_run_command.return_value = ['', '', 1]
valid_dev = '/valid/block/dev'
keys = ['MOUNTPOINT']
with self.assertRaises(OperationFailed):
_get_lsblk_devs(keys, [valid_dev])
cmd = ['lsblk', '-Pbo', 'MOUNTPOINT', valid_dev]
mock_run_command.assert_called_once_with(cmd)
================================================
FILE: tests/test_host.py
================================================
# -*- coding: utf-8 -*-
#
# Project Kimchi
#
# Copyright IBM Corp, 2015-2017
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
import json
import unittest
from functools import partial
from tests.utils import patch_auth
from tests.utils import request
from tests.utils import run_server
test_server = None
def setUpModule():
global test_server
patch_auth()
test_server = run_server(test_mode=True)
def tearDownModule():
test_server.stop()
class HostTests(unittest.TestCase):
def setUp(self):
self.request = partial(request)
def test_host_devices(self):
def asset_devices_type(devices, dev_type):
for dev in devices:
self.assertEqual(dev['device_type'], dev_type)
resp = self.request('/plugins/kimchi/host/devices?_cap=scsi_host')
nodedevs = json.loads(resp.read())
# Mockmodel brings 3 preconfigured scsi fc_host
self.assertEqual(3, len(nodedevs))
nodedev = json.loads(
self.request('/plugins/kimchi/host/devices/scsi_host2').read()
)
# Mockmodel generates random wwpn and wwnn
self.assertEqual('scsi_host2', nodedev['name'])
self.assertEqual('fc_host', nodedev['adapter']['type'])
self.assertEqual(16, len(nodedev['adapter']['wwpn']))
self.assertEqual(16, len(nodedev['adapter']['wwnn']))
devs = json.loads(self.request('/plugins/kimchi/host/devices').read())
dev_names = [dev['name'] for dev in devs]
for dev_type in ('pci', 'usb_device', 'scsi'):
resp = self.request(
'/plugins/kimchi/host/devices?_cap=%s' % dev_type)
devsByType = json.loads(resp.read())
names = [dev['name'] for dev in devsByType]
self.assertTrue(set(names) <= set(dev_names))
asset_devices_type(devsByType, dev_type)
resp = self.request('/plugins/kimchi/host/devices?_passthrough=true')
passthru_devs = [dev['name'] for dev in json.loads(resp.read())]
self.assertTrue(set(passthru_devs) <= set(dev_names))
for dev_type in ('pci', 'usb_device', 'scsi'):
resp = self.request(
'/plugins/kimchi/host/devices?_cap=%s&_passthrough=true' % dev_type
)
filteredDevs = json.loads(resp.read())
filteredNames = [dev['name'] for dev in filteredDevs]
self.assertTrue(set(filteredNames) <= set(dev_names))
asset_devices_type(filteredDevs, dev_type)
for dev in passthru_devs:
resp = self.request(
'/plugins/kimchi/host/devices?_passthrough_affected_by=%s' % dev
)
affected_devs = [dev['name'] for dev in json.loads(resp.read())]
self.assertTrue(set(affected_devs) <= set(dev_names))
def test_get_available_passthrough_devices(self):
resp = self.request('/plugins/kimchi/host/devices?_passthrough=true')
all_devs = [dev['name'] for dev in json.loads(resp.read())]
resp = self.request(
'/plugins/kimchi/host/devices?' '_passthrough=true&_available_only=true'
)
available_devs = [dev['name'] for dev in json.loads(resp.read())]
self.assertLessEqual(len(available_devs), len(all_devs))
def test_host_partitions(self):
resp = self.request('/plugins/kimchi/host/partitions')
self.assertEqual(200, resp.status)
partitions = json.loads(resp.read())
keys = ['name', 'path', 'type', 'fstype',
'size', 'mountpoint', 'available']
for item in partitions:
resp = self.request(
'/plugins/kimchi/host/partitions/%s' % item['name'])
info = json.loads(resp.read())
self.assertEqual(sorted(info.keys()), sorted(keys))
================================================
FILE: tests/test_livemigration.py
================================================
#
# Project Kimchi
#
# Copyright IBM Corp, 2015-2017
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
import json
import os
import socket
import unittest
from functools import partial
import iso_gen
import libvirt
import mock
from wok.basemodel import Singleton
from wok.exception import OperationFailed
from wok.plugins.kimchi.model import model
from wok.plugins.kimchi.model.libvirtconnection import LibvirtConnection
from wok.plugins.kimchi.model.vms import VMModel
from wok.rollbackcontext import RollbackContext
from wok.utils import run_command
from tests.utils import patch_auth
from tests.utils import request
from tests.utils import rollback_wrapper
from tests.utils import run_server
from tests.utils import running_as_root
from tests.utils import wait_task
ISO_DIR = '/var/lib/libvirt/images/'
UBUNTU_ISO = ISO_DIR + 'ubuntu_kimchi_migration_test_14.04.iso'
KIMCHI_LIVE_MIGRATION_TEST = None
def setUpModule():
if not os.path.exists(ISO_DIR):
os.makedirs(ISO_DIR)
iso_gen.construct_fake_iso(UBUNTU_ISO, True, '14.04', 'ubuntu')
# Some FeatureTests functions depend on server to validate their result.
# As CapabilitiesModel is a Singleton class it will get the first result
# from FeatureTests which may be wrong when using the Model instance
# directly - the case of this test_model.py
# So clean Singleton instances to make sure to get the right result when
# running the following tests.
Singleton._instances = {}
def tearDownModule():
os.remove(UBUNTU_ISO)
def remoteserver_environment_defined():
global KIMCHI_LIVE_MIGRATION_TEST
KIMCHI_LIVE_MIGRATION_TEST = os.environ.get('KIMCHI_LIVE_MIGRATION_TEST')
return KIMCHI_LIVE_MIGRATION_TEST is not None
def running_root_and_remoteserver_defined():
return running_as_root() and remoteserver_environment_defined()
def check_if_vm_migration_test_possible():
inst = model.Model(objstore_loc='/tmp/kimchi-store-test')
try:
inst.vm_migration_pre_check(KIMCHI_LIVE_MIGRATION_TEST, 'root', None)
except Exception:
return False
return True
@unittest.skipUnless(
running_root_and_remoteserver_defined(),
'Must be run as root and with a remote server '
'defined in the KIMCHI_LIVE_MIGRATION_TEST variable',
)
class LiveMigrationTests(unittest.TestCase):
def setUp(self):
self.tmp_store = '/tmp/kimchi-store-test'
self.inst = model.Model('qemu:///system', objstore_loc=self.tmp_store)
params = {
'name': 'template_test_vm_migrate',
'disks': [],
'source_media': UBUNTU_ISO,
'memory': {'current': 2048, 'max_memory': 4096 << 10},
}
self.inst.templates_create(params)
params = {
'name': 'template_test_vm_migrate_nonshared',
'disks': [{'name': 'test_vm_migrate.img', 'size': 1}],
'source_media': UBUNTU_ISO,
'memory': {'current': 2048, 'maxmemory': 4096 * 1024},
}
self.inst.templates_create(params)
def tearDown(self):
self.inst.template_delete('template_test_vm_migrate')
self.inst.template_delete('template_test_vm_migrate_nonshared')
os.unlink(self.tmp_store)
def create_vm_test(self, non_shared_storage=False):
params = {
'name': 'test_vm_migrate',
'template': '/plugins/kimchi/templates/template_test_vm_migrate',
}
if non_shared_storage:
params = {
'name': 'test_vm_migrate',
'template': '/plugins/kimchi/templates/'
'template_test_vm_migrate_nonshared',
}
task = self.inst.vms_create(params)
self.inst.task_wait(task['id'])
def test_vm_migrate_fails_if_remote_is_localhost(self):
with RollbackContext() as rollback:
self.create_vm_test()
rollback.prependDefer(
rollback_wrapper, self.inst.vm_delete, 'test_vm_migrate'
)
self.assertRaises(
OperationFailed, self.inst.vm_migrate, 'test_vm_migrate', '127.0.0.1'
)
self.assertRaises(
OperationFailed, self.inst.vm_migrate, 'test_vm_migrate', 'localhost'
)
hostname = socket.gethostname()
self.assertRaises(
OperationFailed, self.inst.vm_migrate, 'test_vm_migrate', hostname
)
def test_vm_migrate_fails_if_remotehost_unreachable(self):
with RollbackContext() as rollback:
self.create_vm_test()
rollback.prependDefer(
rollback_wrapper, self.inst.vm_delete, 'test_vm_migrate'
)
self.assertRaises(
OperationFailed,
self.inst.vm_migrate,
'test_vm_migrate',
'test.vm.migrate.host.unreachable',
)
def test_vm_migrate_fails_if_not_passwordless_login(self):
with RollbackContext() as rollback:
self.create_vm_test()
rollback.prependDefer(
rollback_wrapper, self.inst.vm_delete, 'test_vm_migrate'
)
self.assertRaises(
OperationFailed,
self.inst.vm_migrate,
'test_vm_migrate',
'this_is_a_fake_remote_host',
)
@mock.patch('wok.plugins.kimchi.model.vms.VMModel.' '_get_remote_libvirt_conn')
def test_vm_migrate_fails_different_remote_hypervisor(self, mock_get_remote_conn):
class MockRemoteConnObj(object):
def getType(self):
return 'another_hypervisor'
def close(self):
pass
mock_get_remote_conn.return_value = MockRemoteConnObj()
with RollbackContext() as rollback:
self.create_vm_test()
rollback.prependDefer(
rollback_wrapper, self.inst.vm_delete, 'test_vm_migrate'
)
self.assertRaises(
OperationFailed,
self.inst.vm_migrate,
'test_vm_migrate',
KIMCHI_LIVE_MIGRATION_TEST,
)
@mock.patch('wok.plugins.kimchi.model.vms.VMModel.' '_get_remote_libvirt_conn')
def test_vm_migrate_fails_different_remote_arch(self, mock_get_remote_conn):
class MockRemoteConnObj(object):
def getType(self):
return 'QEMU'
def getInfo(self):
return ['another_arch', 'QEMU']
def close(self):
pass
mock_get_remote_conn.return_value = MockRemoteConnObj()
with RollbackContext() as rollback:
self.create_vm_test()
rollback.prependDefer(
rollback_wrapper, self.inst.vm_delete, 'test_vm_migrate'
)
self.assertRaises(
OperationFailed,
self.inst.vm_migrate,
'test_vm_migrate',
KIMCHI_LIVE_MIGRATION_TEST,
)
def get_remote_conn(self):
remote_uri = 'qemu+ssh://%s@%s/system' % (
'root', KIMCHI_LIVE_MIGRATION_TEST)
remote_conn = libvirt.open(remote_uri)
return remote_conn
def get_remote_vm_list(self):
remote_uri = 'qemu+ssh://%s@%s/system' % (
'root', KIMCHI_LIVE_MIGRATION_TEST)
remote_conn = libvirt.open(remote_uri)
return [vm.name() for vm in remote_conn.listAllDomains()]
@unittest.skipUnless(
check_if_vm_migration_test_possible(), 'not possible to test a live migration'
)
def test_vm_livemigrate_persistent(self):
with RollbackContext() as rollback:
self.create_vm_test()
rollback.prependDefer(
rollback_wrapper, self.inst.vm_delete, 'test_vm_migrate'
)
# removing cdrom because it is not shared storage and will make
# the migration fail
dev_list = self.inst.vmstorages_get_list('test_vm_migrate')
self.inst.vmstorage_delete('test_vm_migrate', dev_list[0])
try:
self.inst.vm_start('test_vm_migrate')
except Exception as e:
self.fail('Failed to start the vm, reason: %s' % e.message)
try:
task = self.inst.vm_migrate(
'test_vm_migrate', KIMCHI_LIVE_MIGRATION_TEST
)
self.inst.task_wait(task['id'])
self.assertIn('test_vm_migrate', self.get_remote_vm_list())
remote_conn = self.get_remote_conn()
rollback.prependDefer(remote_conn.close)
remote_vm = remote_conn.lookupByName('test_vm_migrate')
self.assertTrue(remote_vm.isPersistent())
remote_vm.destroy()
remote_vm.undefine()
except Exception as e:
self.fail(f'Migration test failed: {e}')
@unittest.skipUnless(
check_if_vm_migration_test_possible(), 'not possible to test a live migration'
)
def test_vm_livemigrate_transient(self):
self.create_vm_test()
with RollbackContext() as rollback:
try:
# removing cdrom because it is not shared storage and will make
# the migration fail
dev_list = self.inst.vmstorages_get_list('test_vm_migrate')
self.inst.vmstorage_delete('test_vm_migrate', dev_list[0])
self.inst.vm_start('test_vm_migrate')
# to make the VM transient, undefine it while it's running
vm = VMModel.get_vm(
'test_vm_migrate', LibvirtConnection('qemu:///system')
)
vm.undefine()
task = self.inst.vm_migrate(
'test_vm_migrate', KIMCHI_LIVE_MIGRATION_TEST
)
self.inst.task_wait(task['id'])
self.assertIn('test_vm_migrate', self.get_remote_vm_list())
remote_conn = self.get_remote_conn()
rollback.prependDefer(remote_conn.close)
remote_vm = remote_conn.lookupByName('test_vm_migrate')
self.assertFalse(remote_vm.isPersistent())
remote_vm.destroy()
except Exception as e:
# Clean up here instead of rollback because if the
# VM was turned transient and shut down it might
# not exist already - rollback in this case will cause
# a QEMU error
vm = VMModel.get_vm(
'test_vm_migrate', LibvirtConnection('qemu:///system')
)
if vm.isPersistent():
vm.undefine()
vm.shutdown()
self.fail('Migration test failed: %s' % e.message)
@unittest.skipUnless(
check_if_vm_migration_test_possible(), 'not possible to test shutdown migration'
)
def test_vm_coldmigrate(self):
with RollbackContext() as rollback:
self.create_vm_test()
rollback.prependDefer(
rollback_wrapper, self.inst.vm_delete, 'test_vm_migrate'
)
# removing cdrom because it is not shared storage and will make
# the migration fail
dev_list = self.inst.vmstorages_get_list('test_vm_migrate')
self.inst.vmstorage_delete('test_vm_migrate', dev_list[0])
try:
task = self.inst.vm_migrate(
'test_vm_migrate', KIMCHI_LIVE_MIGRATION_TEST
)
self.inst.task_wait(task['id'])
self.assertIn('test_vm_migrate', self.get_remote_vm_list())
remote_conn = self.get_remote_conn()
rollback.prependDefer(remote_conn.close)
remote_vm = remote_conn.lookupByName('test_vm_migrate')
self.assertTrue(remote_vm.isPersistent())
state = remote_vm.info()[0]
self.assertEqual(state, libvirt.VIR_DOMAIN_SHUTOFF)
remote_vm.undefine()
except Exception as e:
self.fail('Migration test failed: %s' % e.message)
def _erase_remote_file(self, path):
username_host = 'root@%s' % KIMCHI_LIVE_MIGRATION_TEST
cmd = ['ssh', '-oStrictHostKeyChecking=no',
username_host, 'rm', '-f', path]
_, _, returncode = run_command(cmd, silent=True)
if returncode != 0:
print(f'cannot erase remote file {path}')
@unittest.skipUnless(
check_if_vm_migration_test_possible(), 'not possible to test a live migration'
)
def test_vm_livemigrate_persistent_nonshared(self):
with RollbackContext() as rollback:
self.create_vm_test(non_shared_storage=True)
rollback.prependDefer(
rollback_wrapper, self.inst.vm_delete, 'test_vm_migrate'
)
# getting disk path info to clean it up later
storage_list = self.inst.vmstorages_get_list('test_vm_migrate')
disk_info = self.inst.vmstorage_lookup(
'test_vm_migrate', storage_list[0])
disk_path = disk_info.get('path')
try:
self.inst.vm_start('test_vm_migrate')
except Exception as e:
self.fail('Failed to start the vm, reason: %s' % e.message)
try:
task = self.inst.vm_migrate(
'test_vm_migrate', KIMCHI_LIVE_MIGRATION_TEST
)
self.inst.task_wait(task['id'], 3600)
self.assertIn('test_vm_migrate', self.get_remote_vm_list())
remote_conn = self.get_remote_conn()
rollback.prependDefer(remote_conn.close)
remote_vm = remote_conn.lookupByName('test_vm_migrate')
self.assertTrue(remote_vm.isPersistent())
remote_vm.destroy()
remote_vm.undefine()
self._erase_remote_file(disk_path)
self._erase_remote_file(UBUNTU_ISO)
except Exception as e:
self.fail('Migration test failed: %s' % e.message)
def _task_lookup(self, taskid):
return json.loads(self.request('/plugins/kimchi/tasks/%s' % taskid).read())
@unittest.skipUnless(
check_if_vm_migration_test_possible(), 'not possible to test a live migration'
)
def test_vm_livemigrate_persistent_API(self):
patch_auth()
with RollbackContext() as rollback:
test_server = run_server()
rollback.prependDefer(test_server.stop)
self.request = partial(request)
self.create_vm_test()
rollback.prependDefer(
rollback_wrapper, self.inst.vm_delete, 'test_vm_migrate'
)
# removing cdrom because it is not shared storage and will make
# the migration fail
dev_list = self.inst.vmstorages_get_list('test_vm_migrate')
self.inst.vmstorage_delete('test_vm_migrate', dev_list[0])
try:
self.inst.vm_start('test_vm_migrate')
except Exception as e:
self.fail('Failed to start the vm, reason: %s' % e.message)
migrate_url = '/plugins/kimchi/vms/%s/migrate' % 'test_vm_migrate'
req = json.dumps(
{'remote_host': KIMCHI_LIVE_MIGRATION_TEST, 'user': 'root'}
)
resp = self.request(migrate_url, req, 'POST')
self.assertEqual(202, resp.status)
task = json.loads(resp.read())
wait_task(self._task_lookup, task['id'])
task = json.loads(
self.request('/plugins/kimchi/tasks/%s' %
task['id'], '{}').read()
)
self.assertEqual('finished', task['status'])
try:
remote_conn = self.get_remote_conn()
rollback.prependDefer(remote_conn.close)
remote_vm = remote_conn.lookupByName('test_vm_migrate')
self.assertTrue(remote_vm.isPersistent())
remote_vm.destroy()
remote_vm.undefine()
except Exception as e:
self.fail('Migration test failed: %s' % e.message)
@mock.patch('wok.plugins.kimchi.model.vms.VMModel.' '_set_password_less_login')
@mock.patch(
'wok.plugins.kimchi.model.vms.VMModel.'
'_check_if_migrating_same_arch_hypervisor'
)
@mock.patch(
'wok.plugins.kimchi.model.vms.VMModel.' '_check_ppc64_subcores_per_core'
)
def test_set_passwordless_login(
self, mock_ppc64_subpercore, mock_same_arch, mock_password_less_login
):
self.inst.vm_migration_pre_check(
'this_is_a_fake_remote_host', 'test_vm_migrate_fake_user', 'fake_password'
)
mock_password_less_login.assert_called_once_with(
'this_is_a_fake_remote_host', 'test_vm_migrate_fake_user', 'fake_password'
)
@mock.patch('wok.plugins.kimchi.model.vms.VMModel.' 'migration_pre_check')
@mock.patch('wok.plugins.kimchi.model.vms.VMModel.' '_get_remote_libvirt_conn')
@mock.patch('libvirt.virDomain.migrate')
def test_vm_livemigrate_RDMA(self, mock_migrate, mock_remote_conn, mock_precheck):
mock_remote_conn.return_value = 'remote_conn'
self.create_vm_test()
try:
# removing cdrom because it is not shared storage and will make
# the migration fail
dev_list = self.inst.vmstorages_get_list('test_vm_migrate')
self.inst.vmstorage_delete('test_vm_migrate', dev_list[0])
self.inst.vm_start('test_vm_migrate')
# to make the VM transient, undefine it while it's running
vm = VMModel.get_vm('test_vm_migrate',
LibvirtConnection('qemu:///system'))
vm.undefine()
self.inst.vm_migrate(
'test_vm_migrate', KIMCHI_LIVE_MIGRATION_TEST, enable_rdma=True
)
flags = (
libvirt.VIR_MIGRATE_PEER2PEER
| libvirt.VIR_MIGRATE_LIVE
| libvirt.VIR_MIGRATE_TUNNELLED
)
param_uri = 'rdma://' + KIMCHI_LIVE_MIGRATION_TEST
mock_migrate.assert_called_once_with(vm, flags, param_uri)
except Exception as e:
# Clean up here instead of rollback because if the
# VM was turned transient and shut down it might
# not exist already - rollback in this case will cause
# a QEMU error
vm = VMModel.get_vm('test_vm_migrate',
LibvirtConnection('qemu:///system'))
if vm.isPersistent():
vm.undefine()
vm.shutdown()
self.fail('Migration test failed: %s' % e.message)
================================================
FILE: tests/test_mock_network.py
================================================
# -*- coding: utf-8 -*-
#
# Project Kimchi
#
# Copyright IBM Corp, 2015-2017
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
import json
import unittest
from functools import partial
import cherrypy
from test_model_network import _do_network_test
from wok.plugins.kimchi.model.featuretests import FeatureTests
from tests.utils import patch_auth
from tests.utils import request
from tests.utils import run_server
model = None
test_server = None
def setUpModule():
global test_server, model
patch_auth()
test_server = run_server(test_mode=True)
model = cherrypy.tree.apps['/plugins/kimchi'].root.model
def tearDownModule():
test_server.stop()
class MockNetworkTests(unittest.TestCase):
def setUp(self):
self.request = partial(request)
model.reset()
@unittest.skipIf(
FeatureTests.is_nm_running(),
'test_vlan_tag_bridge skipped because Network ' 'Manager is running.',
)
def test_vlan_tag_bridge(self):
# Verify the current system has at least one interface to create a
# bridged network
interfaces = json.loads(
self.request('/plugins/kimchi/interfaces?_inuse=false&type=nic')
.read()
.decode('utf-8')
)
if len(interfaces) > 0:
iface = interfaces[0]['name']
_do_network_test(
self,
model,
{
'name': u'vlan-tagged-bridge',
'connection': 'bridge',
'interface': iface,
'vlan_id': 987,
},
)
================================================
FILE: tests/test_mock_storagepool.py
================================================
# -*- coding: utf-8 -*-
#
# Project Kimchi
#
# Copyright IBM Corp, 2015-2017
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
import json
import unittest
import urllib
from functools import partial
import cherrypy
from tests.utils import patch_auth
from tests.utils import request
from tests.utils import run_server
model = None
test_server = None
def setUpModule():
global test_server, model
patch_auth()
test_server = run_server(test_mode=True)
model = cherrypy.tree.apps['/plugins/kimchi'].root.model
def tearDownModule():
test_server.stop()
class MockStoragepoolTests(unittest.TestCase):
def setUp(self):
self.request = partial(request)
model.reset()
def _task_lookup(self, taskid):
return json.loads(self.request('/plugins/kimchi/tasks/%s' % taskid).read())
def test_storagepool(self):
# MockModel always returns 2 VGs (hostVG, kimchiVG)
vgs = json.loads(self.request('/plugins/kimchi/host/vgs').read())
vg_names = [vg['name'] for vg in vgs]
# MockModel always returns 2 partitions (vdx, vdz)
partitions = json.loads(self.request(
'/plugins/kimchi/host/partitions').read())
devs = [dev['path'] for dev in partitions]
# MockModel always returns 3 FC devices
fc_devs = json.loads(
self.request('/plugins/kimchi/host/devices?_cap=fc_host').read()
)
fc_devs = [dev['name'] for dev in fc_devs]
poolDefs = [
{
'type': 'dir',
'name': 'kīмсhīUnitTestDirPool',
'path': '/tmp/kimchi-images',
},
{
'type': 'netfs',
'name': 'kīмсhīUnitTestNSFPool',
'source': {'host': 'localhost', 'path': '/var/lib/kimchi/nfs-pool'},
},
{
'type': 'scsi',
'name': 'kīмсhīUnitTestSCSIFCPool',
'source': {'adapter_name': fc_devs[0]},
},
{
'type': 'iscsi',
'name': 'kīмсhīUnitTestISCSIPool',
'source': {
'host': '127.0.0.1',
'target': 'iqn.2015-01.localhost.kimchiUnitTest',
},
},
{
'type': 'logical',
'name': 'kīмсhīUnitTestLogicalPool',
'source': {'devices': [devs[0]]},
},
{'type': 'logical', 'name': vg_names[0], 'source': {
'from_vg': True}},
]
def _do_test(params):
name = params['name']
uri = urllib.parse.quote(f'/plugins/kimchi/storagepools/{name}')
req = json.dumps(params)
resp = self.request('/plugins/kimchi/storagepools', req, 'POST')
self.assertEqual(201, resp.status)
# activate the storage pool
resp = self.request(uri + '/activate', '{}', 'POST')
storagepool = json.loads(self.request(uri).read().decode('utf-8'))
self.assertEqual('active', storagepool['state'])
# Set autostart flag of an active storage pool
for autostart in [True, False]:
t = {'autostart': autostart}
req = json.dumps(t)
resp = self.request(uri, req, 'PUT')
storagepool = json.loads(
self.request(uri).read().decode('utf-8'))
self.assertEqual(autostart, storagepool['autostart'])
# Extend an active logical pool
if params['type'] == 'logical':
t = {'disks': [devs[1]]}
req = json.dumps(t)
resp = self.request(uri, req, 'PUT')
self.assertEqual(200, resp.status)
# Deactivate the storage pool
resp = self.request(uri + '/deactivate', '{}', 'POST')
storagepool = json.loads(self.request(uri).read().decode('utf-8'))
self.assertEqual('inactive', storagepool['state'])
# Set autostart flag of an inactive storage pool
for autostart in [True, False]:
t = {'autostart': autostart}
req = json.dumps(t)
resp = self.request(uri, req, 'PUT')
storagepool = json.loads(
self.request(uri).read().decode('utf-8'))
self.assertEqual(autostart, storagepool['autostart'])
# Extend an inactive logical pool
if params['type'] == 'logical':
t = {'disks': [devs[1]]}
req = json.dumps(t)
resp = self.request(uri, req, 'PUT')
self.assertEqual(200, resp.status)
# Delete the storage pool
resp = self.request(uri, '{}', 'DELETE')
self.assertEqual(204, resp.status)
for pool in poolDefs:
_do_test(pool)
================================================
FILE: tests/test_mock_storagevolume.py
================================================
# -*- coding: utf-8 -*-
#
# Project Kimchi
#
# Copyright IBM Corp, 2015-2017
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
import json
import unittest
import urllib
from functools import partial
import cherrypy
from test_model_storagevolume import _do_volume_test
from tests.utils import patch_auth
from tests.utils import request
from tests.utils import run_server
model = None
test_server = None
def setUpModule():
global test_server, model
patch_auth()
test_server = run_server(test_mode=True)
model = cherrypy.tree.apps['/plugins/kimchi'].root.model
def tearDownModule():
test_server.stop()
class MockStorageVolumeTests(unittest.TestCase):
def setUp(self):
self.request = partial(request)
def test_storagevolume(self):
# MockModel always returns 2 partitions (vdx, vdz)
partitions = json.loads(
self.request(
'/plugins/kimchi/host/partitions').read().decode('utf-8')
)
devs = [dev['path'] for dev in partitions]
# MockModel always returns 3 FC devices
fc_devs = json.loads(
self.request('/plugins/kimchi/host/devices?_cap=fc_host')
.read()
.decode('utf-8')
)
fc_devs = [dev['name'] for dev in fc_devs]
poolDefs = [
{
'type': 'dir',
'name': 'kīмсhīUnitTestDirPool',
'path': '/tmp/kimchi-images',
},
{
'type': 'netfs',
'name': 'kīмсhīUnitTestNSFPool',
'source': {'host': 'localhost', 'path': '/var/lib/kimchi/nfs-pool'},
},
{
'type': 'scsi',
'name': 'kīмсhīUnitTestSCSIFCPool',
'source': {'adapter_name': fc_devs[0]},
},
{
'type': 'iscsi',
'name': 'kīмсhīUnitTestISCSIPool',
'source': {
'host': '127.0.0.1',
'target': 'iqn.2015-01.localhost.kimchiUnitTest',
},
},
{
'type': 'logical',
'name': 'kīмсhīUnitTestLogicalPool',
'source': {'devices': [devs[0]]},
},
]
for pool in poolDefs:
pool_name = pool['name']
uri = urllib.parse.quote(
f'/plugins/kimchi/storagepools/{pool_name}')
req = json.dumps(pool)
resp = self.request('/plugins/kimchi/storagepools', req, 'POST')
self.assertEqual(201, resp.status)
# activate the storage pool
resp = self.request(uri + '/activate', '{}', 'POST')
self.assertEqual(200, resp.status)
_do_volume_test(self, model, pool_name)
================================================
FILE: tests/test_mockmodel.py
================================================
#
# Project Kimchi
#
# Copyright IBM Corp, 2013-2017
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
import json
import os
import time
import unittest
import cherrypy
import iso_gen
from wok.exception import InvalidOperation
from wok.plugins.kimchi.osinfo import get_template_default
from tests.utils import patch_auth
from tests.utils import request
from tests.utils import run_server
from tests.utils import wait_task
test_server = None
model = None
fake_iso = None
def setUpModule():
global model, test_server, fake_iso
cherrypy.request.headers = {'Accept': 'application/json'}
patch_auth()
test_server = run_server(test_mode=True)
model = cherrypy.tree.apps['/plugins/kimchi'].root.model
fake_iso = '/tmp/fake.iso'
iso_gen.construct_fake_iso(fake_iso, True, '12.04', 'ubuntu')
def tearDownModule():
test_server.stop()
os.unlink(fake_iso)
class MockModelTests(unittest.TestCase):
def setUp(self):
model.reset()
def test_screenshot_refresh(self):
# Create a VM
req = json.dumps(
{'name': 'test', 'source_media': {'type': 'disk', 'path': fake_iso}}
)
request('/plugins/kimchi/templates', req, 'POST')
req = json.dumps(
{'name': 'test-vm', 'template': '/plugins/kimchi/templates/test'}
)
resp = request('/plugins/kimchi/vms', req, 'POST')
task = json.loads(resp.read().decode('utf-8'))
wait_task(model.task_lookup, task['id'])
# Test screenshot refresh for running vm
request('/plugins/kimchi/vms/test-vm/start', '{}', 'POST')
resp = request('/plugins/kimchi/vms/test-vm/screenshot')
self.assertEqual(200, resp.status)
self.assertEqual('image/png', resp.getheader('content-type'))
resp1 = request('/plugins/kimchi/vms/test-vm')
rspBody = resp1.read().decode('utf-8')
testvm_Data = json.loads(rspBody)
screenshotURL = '/' + testvm_Data['screenshot']
time.sleep(5)
resp2 = request(screenshotURL)
self.assertEqual(200, resp2.status)
self.assertEqual(
resp2.getheader('content-type'), resp.getheader('content-type')
)
self.assertEqual(
resp2.getheader('content-length'), resp.getheader('content-length')
)
self.assertEqual(
resp2.getheader('last-modified'), resp.getheader('last-modified')
)
def test_vm_list_sorted(self):
req = json.dumps(
{'name': 'test', 'source_media': {'type': 'disk', 'path': fake_iso}}
)
request('/plugins/kimchi/templates', req, 'POST')
def add_vm(name):
# Create a VM
req = json.dumps(
{'name': name, 'template': '/plugins/kimchi/templates/test'}
)
task = json.loads(
request('/plugins/kimchi/vms', req,
'POST').read().decode('utf-8')
)
wait_task(model.task_lookup, task['id'])
vms = [u'abc', u'bca', u'cab', u'xba']
for vm in vms:
add_vm(vm)
vms.append(u'test')
self.assertEqual(model.vms_get_list(), sorted(vms))
def test_memory_window_changes(self):
model.templates_create(
{'name': u'test', 'source_media': {'type': 'disk', 'path': fake_iso}}
)
task = model.vms_create(
{'name': u'test-vm', 'template': '/plugins/kimchi/templates/test'}
)
wait_task(model.task_lookup, task['id'])
info = model.device_lookup('pci_0000_1a_00_0')
model.vmhostdevs_update_mmio_guest(u'test-vm', True)
model._attach_device(
u'test-vm', model._get_pci_device_xml(info, 0, False))
def test_hotplug_3D_card(self):
model.templates_create(
{'name': u'test', 'source_media': {'type': 'disk', 'path': fake_iso}}
)
task = model.vms_create(
{'name': u'test-vm', 'template': '/plugins/kimchi/templates/test'}
)
wait_task(model.task_lookup, task['id'])
model.vm_start(u'test-vm')
# attach the 3D cards found to a running guest
all_devices = model.devices_get_list()
for device in all_devices:
device_info = model.device_lookup(device)
if model.device_is_device_3D_controller(device_info):
try:
model.vmhostdevs_create(u'test-vm', {'name': device})
# expect the error: KCHVMHDEV0006E
except InvalidOperation as e:
self.assertEqual(e.message[:14], u'KCHVMHDEV0006E')
def test_vm_info(self):
model.templates_create(
{'name': u'test', 'source_media': {'type': 'disk', 'path': fake_iso}}
)
task = model.vms_create(
{'name': u'test-vm', 'template': '/plugins/kimchi/templates/test'}
)
wait_task(model.task_lookup, task['id'])
vms = model.vms_get_list()
self.assertEqual(2, len(vms))
self.assertIn(u'test-vm', vms)
keys = set(
(
'name',
'state',
'stats',
'uuid',
'memory',
'cpu_info',
'screenshot',
'icon',
'graphics',
'users',
'groups',
'access',
'persistent',
'bootorder',
'bootmenu',
'title',
'description',
'autostart',
)
)
stats_keys = set(
(
'cpu_utilization',
'mem_utilization',
'net_throughput',
'net_throughput_peak',
'io_throughput',
'io_throughput_peak',
)
)
info = model.vm_lookup(u'test-vm')
self.assertEqual(keys, set(info.keys()))
self.assertEqual('shutoff', info['state'])
self.assertEqual('test-vm', info['name'])
self.assertEqual(get_template_default('old', 'memory'), info['memory'])
self.assertEqual(1, info['cpu_info']['vcpus'])
self.assertEqual(1, info['cpu_info']['maxvcpus'])
self.assertEqual('plugins/kimchi/images/icon-vm.png', info['icon'])
self.assertEqual(stats_keys, set(info['stats'].keys()))
self.assertEqual('vnc', info['graphics']['type'])
self.assertEqual('127.0.0.1', info['graphics']['listen'])
================================================
FILE: tests/test_model.py
================================================
# -*- coding: utf-8 -*-
#
# Project Kimchi
#
# Copyright IBM Corp, 2013-2017
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
import base64
import builtins
import grp
import json
import os
import platform
import pwd
import re
import shutil
import time
import unittest
import libvirt
import lxml.etree as ET
import mock
import wok.objectstore
from iso_gen import construct_fake_iso
from lxml import objectify
from wok.asynctask import AsyncTask
from wok.basemodel import Singleton
from wok.config import config
from wok.config import PluginPaths
from wok.exception import InvalidOperation
from wok.exception import InvalidParameter
from wok.exception import NotFoundError
from wok.exception import OperationFailed
from wok.plugins.kimchi import network as netinfo
from wok.plugins.kimchi import osinfo
from wok.plugins.kimchi.config import kimchiPaths as paths
from wok.plugins.kimchi.model import model
from wok.plugins.kimchi.model.libvirtconnection import LibvirtConnection
from wok.plugins.kimchi.model.virtviewerfile import FirewallManager
from wok.plugins.kimchi.model.virtviewerfile import VMVirtViewerFileModel
from wok.plugins.kimchi.model.vms import VMModel
from wok.rollbackcontext import RollbackContext
from wok.utils import convert_data_size
from wok.xmlutils.utils import xpath_get_text
import tests.utils as utils
invalid_repository_urls = [
'www.fedora.org', # missing protocol
'://www.fedora.org', # missing protocol
'http://www.fedora', # invalid domain name
'file:///home/foobar',
] # invalid path
TMP_DIR = '/var/lib/kimchi/tests/'
UBUNTU_ISO = TMP_DIR + 'ubuntu14.04.iso'
NON_NUMA_XML = """
non-numa-kimchi-test41hvm"""
def setUpModule():
if not os.path.exists(TMP_DIR):
os.makedirs(TMP_DIR)
construct_fake_iso(UBUNTU_ISO, True, '14.04', 'ubuntu')
# Some FeatureTests functions depend on server to validate their result.
# As CapabilitiesModel is a Singleton class it will get the first result
# from FeatureTests which may be wrong when using the Model instance
# directly - the case of this test_model.py
# So clean Singleton instances to make sure to get the right result when
# running the following tests.
Singleton._instances = {}
def tearDownModule():
shutil.rmtree(TMP_DIR)
def get_remote_iso_path():
"""
Get a remote iso with the right arch from the distro files shipped
with kimchi.
"""
host_arch = os.uname()[4]
remote_path = ''
with open(
os.path.join(PluginPaths('kimchi').conf_dir,
'distros.d', 'fedora.json')
) as fedora_isos:
# Get a list of dicts
json_isos_list = json.load(fedora_isos)
for iso in json_isos_list:
if (iso.get('os_arch')) == host_arch:
remote_path = iso.get('path')
break
return remote_path
def _setDiskPoolDefault():
osinfo.defaults['disks'][0]['pool'] = {
'name': '/plugins/kimchi/storagepools/default'
}
def _setDiskPoolDefaultTest():
osinfo.defaults['disks'][0]['pool'] = {
'name': '/plugins/kimchi/storagepools/default-pool'
}
class ModelTests(unittest.TestCase):
def setUp(self):
self.tmp_store = '/tmp/kimchi-store-test'
def tearDown(self):
# FIXME: Tests using 'test:///default' URI should be moved to
# test_rest or test_mockmodel to avoid overriding problems
LibvirtConnection._connections['test:///default'] = {}
if os.path.isfile(self.tmp_store):
os.unlink(self.tmp_store)
def test_vm_info(self):
inst = model.Model('test:///default', self.tmp_store)
vms = inst.vms_get_list()
self.assertEqual(1, len(vms))
self.assertEqual('test', vms[0])
keys = set(
(
'name',
'state',
'stats',
'uuid',
'memory',
'cpu_info',
'screenshot',
'icon',
'graphics',
'users',
'groups',
'access',
'persistent',
'bootorder',
'bootmenu',
'title',
'description',
'autostart',
)
)
stats_keys = set(
(
'cpu_utilization',
'mem_utilization',
'net_throughput',
'net_throughput_peak',
'io_throughput',
'io_throughput_peak',
)
)
info = inst.vm_lookup('test')
self.assertEqual(keys, set(info.keys()))
self.assertEqual('running', info['state'])
self.assertEqual('test', info['name'])
self.assertEqual(2048, info['memory']['current'])
self.assertEqual(2, info['cpu_info']['vcpus'])
self.assertEqual(2, info['cpu_info']['maxvcpus'])
self.assertEqual(None, info['icon'])
self.assertEqual(stats_keys, set(info['stats'].keys()))
self.assertRaises(NotFoundError, inst.vm_lookup, 'nosuchvm')
self.assertEqual([], info['users'])
self.assertEqual([], info['groups'])
self.assertTrue(info['persistent'])
@unittest.skipUnless(
utils.running_as_root() and os.uname()[
4] != 's390x', 'Must be run as root'
)
def test_vm_lifecycle(self):
inst = model.Model(objstore_loc=self.tmp_store)
with RollbackContext() as rollback:
vol_params = {'name': u'test-vol', 'capacity': 1024}
task = inst.storagevolumes_create(u'default', vol_params)
rollback.prependDefer(
inst.storagevolume_delete, u'default', vol_params['name']
)
inst.task_wait(task['id'])
task = inst.task_lookup(task['id'])
self.assertEqual('finished', task['status'])
params = {
'name': 'test',
'source_media': {'type': 'disk', 'path': UBUNTU_ISO},
}
inst.templates_create(params)
rollback.prependDefer(inst.template_delete, 'test')
params = {'name': 'kimchi-vm',
'template': '/plugins/kimchi/templates/test'}
task = inst.vms_create(params)
rollback.prependDefer(inst.vm_delete, 'kimchi-vm-new')
inst.task_wait(task['id'], 10)
task = inst.task_lookup(task['id'])
self.assertEqual('finished', task['status'])
vms = inst.vms_get_list()
self.assertTrue('kimchi-vm' in vms)
inst.vm_start('kimchi-vm')
info = inst.vm_lookup('kimchi-vm')
self.assertEqual('running', info['state'])
task = inst.vmsnapshots_create(u'kimchi-vm')
inst.task_wait(task['id'])
task = inst.task_lookup(task['id'])
self.assertEqual('finished', task['status'])
snap_name = task['target_uri'].split('/')[-1]
created_snaps = [snap_name]
inst.vm_poweroff(u'kimchi-vm')
vm = inst.vm_lookup(u'kimchi-vm')
current_snap = inst.currentvmsnapshot_lookup(u'kimchi-vm')
self.assertEqual(created_snaps[0], current_snap['name'])
# this snapshot should be deleted when its VM is deleted
params = {'name': u'mysnap'}
task = inst.vmsnapshots_create(u'kimchi-vm', params)
inst.task_wait(task['id'])
task = inst.task_lookup(task['id'])
self.assertEqual('finished', task['status'])
created_snaps.append(params['name'])
self.assertRaises(
NotFoundError, inst.vmsnapshot_lookup, u'kimchi-vm', u'foobar'
)
snap = inst.vmsnapshot_lookup(u'kimchi-vm', params['name'])
self.assertTrue(int(time.time()) >= int(snap['created']))
self.assertEqual(vm['state'], snap['state'])
self.assertEqual(params['name'], snap['name'])
self.assertEqual(created_snaps[0], snap['parent'])
snaps = inst.vmsnapshots_get_list(u'kimchi-vm')
self.assertEqual(created_snaps, snaps)
current_snap = inst.currentvmsnapshot_lookup(u'kimchi-vm')
self.assertEqual(snap, current_snap)
task = inst.vmsnapshots_create(u'kimchi-vm')
snap_name = task['target_uri'].split('/')[-1]
rollback.prependDefer(inst.vmsnapshot_delete,
u'kimchi-vm-new', snap_name)
inst.task_wait(task['id'])
task = inst.task_lookup(task['id'])
self.assertEqual('finished', task['status'])
created_snaps.append(snap_name)
snaps = inst.vmsnapshots_get_list(u'kimchi-vm')
self.assertEqual(sorted(created_snaps, key=str.lower), snaps)
snap = inst.vmsnapshot_lookup(u'kimchi-vm', snap_name)
current_snap = inst.currentvmsnapshot_lookup(u'kimchi-vm')
self.assertEqual(snap, current_snap)
# update vm name
inst.vm_update('kimchi-vm', {'name': u'kimchi-vm-new'})
# Look up the first created snapshot from the renamed vm
snap = inst.vmsnapshot_lookup(u'kimchi-vm-new', params['name'])
# snapshot revert to the first created vm
result = inst.vmsnapshot_revert(u'kimchi-vm-new', params['name'])
self.assertEqual(result, ['kimchi-vm-new', snap['name']])
vm = inst.vm_lookup(u'kimchi-vm-new')
self.assertEqual(vm['state'], snap['state'])
current_snap = inst.currentvmsnapshot_lookup(u'kimchi-vm-new')
self.assertEqual(params['name'], current_snap['name'])
# suspend and resume the VM
info = inst.vm_lookup(u'kimchi-vm-new')
self.assertEqual(info['state'], 'shutoff')
self.assertRaises(InvalidOperation,
inst.vm_suspend, u'kimchi-vm-new')
inst.vm_start(u'kimchi-vm-new')
info = inst.vm_lookup(u'kimchi-vm-new')
self.assertEqual(info['state'], 'running')
inst.vm_suspend(u'kimchi-vm-new')
info = inst.vm_lookup(u'kimchi-vm-new')
self.assertEqual(info['state'], 'paused')
self.assertRaises(
InvalidParameter, inst.vm_update, u'kimchi-vm-new', {
'name': 'foo'}
)
inst.vm_resume(u'kimchi-vm-new')
info = inst.vm_lookup(u'kimchi-vm-new')
self.assertEqual(info['state'], 'running')
self.assertRaises(InvalidOperation,
inst.vm_resume, u'kimchi-vm-new')
# leave the VM suspended to make sure a paused VM can be
# deleted correctly
inst.vm_suspend('kimchi-vm-new')
vms = inst.vms_get_list()
self.assertFalse('kimchi-vm-new' in vms)
@unittest.skipUnless(
utils.running_as_root() and os.uname()[
4] != 's390x', 'Must be run as root'
)
def test_image_based_template(self):
inst = model.Model(objstore_loc=self.tmp_store)
with RollbackContext() as rollback:
vol = 'base-vol.img'
params = {
'name': vol,
'capacity': 1073741824, # 1 GiB
'allocation': 1048576, # 1 MiB
'format': 'qcow2',
}
task_id = inst.storagevolumes_create('default', params)['id']
rollback.prependDefer(inst.storagevolume_delete, 'default', vol)
inst.task_wait(task_id)
self.assertEqual('finished', inst.task_lookup(task_id)['status'])
vol_path = inst.storagevolume_lookup('default', vol)['path']
# Create template based on IMG file
tmpl_name = 'img-tmpl'
tmpl_info = {
'cpu_info': {'vcpus': 1},
'name': tmpl_name,
'graphics': {'type': 'vnc', 'listen': '127.0.0.1'},
'networks': ['default'],
'memory': {'current': 1024},
'folder': [],
'icon': 'images/icon-vm.png',
'os_distro': 'unknown',
'os_version': 'unknown',
'source_media': {'type': 'disk', 'path': vol_path},
}
inst.templates_create(tmpl_info)
rollback.prependDefer(inst.template_delete, tmpl_name)
# verify disk
tmpl = inst.template_lookup(tmpl_name)
self.assertEqual(vol_path, tmpl['disks'][0]['base'])
params = {
'name': 'kimchi-vm',
'template': '/plugins/kimchi/templates/img-tmpl',
}
task = inst.vms_create(params)
inst.task_wait(task['id'])
rollback.prependDefer(inst.vm_delete, 'kimchi-vm')
vms = inst.vms_get_list()
self.assertTrue('kimchi-vm' in vms)
inst.vm_start('kimchi-vm')
rollback.prependDefer(inst.vm_poweroff, 'kimchi-vm')
info = inst.vm_lookup('kimchi-vm')
self.assertEqual('running', info['state'])
@unittest.skipUnless(
utils.running_as_root() and os.uname()[
4] != 's390x', 'Must be run as root'
)
def test_vm_graphics(self):
inst = model.Model(objstore_loc=self.tmp_store)
params = {'name': 'test', 'source_media': {
'type': 'disk', 'path': UBUNTU_ISO}}
inst.templates_create(params)
with RollbackContext() as rollback:
params = {
'name': 'kimchi-graphics',
'template': '/plugins/kimchi/templates/test',
}
task1 = inst.vms_create(params)
inst.task_wait(task1['id'])
rollback.prependDefer(inst.vm_delete, 'kimchi-graphics')
info = inst.vm_lookup('kimchi-graphics')
self.assertEqual('vnc', info['graphics']['type'])
self.assertEqual('127.0.0.1', info['graphics']['listen'])
graphics = {'type': 'spice'}
params = {'graphics': graphics}
inst.vm_update('kimchi-graphics', params)
info = inst.vm_lookup('kimchi-graphics')
self.assertEqual('spice', info['graphics']['type'])
self.assertEqual('127.0.0.1', info['graphics']['listen'])
inst.template_delete('test')
@unittest.skipUnless(utils.running_as_root(), 'Must be run as root')
def test_vm_virtviewerfile_vmnotrunning(self):
inst = model.Model(objstore_loc=self.tmp_store)
params = {'name': 'test', 'source_media': {
'type': 'disk', 'path': UBUNTU_ISO}}
inst.templates_create(params)
vm_name = 'kìmchí-vñç'
with RollbackContext() as rollback:
params = {'name': vm_name,
'template': '/plugins/kimchi/templates/test'}
task1 = inst.vms_create(params)
inst.task_wait(task1['id'])
rollback.prependDefer(inst.vm_delete, vm_name)
error_msg = 'KCHVM0083E'
with self.assertRaisesRegexp(InvalidOperation, error_msg):
vvmodel = VMVirtViewerFileModel(conn=inst.conn)
vvmodel.lookup(vm_name)
inst.template_delete('test')
@mock.patch('wok.plugins.kimchi.model.virtviewerfile._get_request_host')
@mock.patch('wok.plugins.kimchi.model.virtviewerfile.' 'VMModel.get_graphics')
@mock.patch(
'wok.plugins.kimchi.model.virtviewerfile.'
'FirewallManager.add_vm_graphics_port'
)
@mock.patch(
'wok.plugins.kimchi.model.virtviewerfile.'
'VMVirtViewerFileModel.handleVMShutdownPowerOff'
)
@mock.patch(
'wok.plugins.kimchi.model.virtviewerfile.'
'VMVirtViewerFileModel._check_if_vm_running'
)
def test_vm_virtviewerfile_vnc(
self,
mock_vm_running,
mock_handleVMOff,
mock_add_port,
mock_get_graphics,
mock_get_host,
):
mock_get_host.return_value = 'kimchi-test-host'
mock_get_graphics.return_value = ['vnc', 'listen', '5999', None]
mock_vm_running.return_value = True
vvmodel = VMVirtViewerFileModel(conn=None)
open_ = mock.mock_open(read_data='')
with mock.patch.object(builtins, 'open', open_):
vvfilepath = vvmodel.lookup('kimchi-vm')
self.assertEqual(
vvfilepath, 'plugins/kimchi/data/virtviewerfiles/kimchi-vm-access.vv'
)
expected_write_content = (
'[virt-viewer]\ntype=vnc\n' 'host=kimchi-test-host\nport=5999\n'
)
self.assertEqual(open_().write.mock_calls, [
mock.call(expected_write_content)])
mock_get_graphics.assert_called_once_with('kimchi-vm', None)
mock_vm_running.assert_called_once_with('kimchi-vm')
mock_handleVMOff.assert_called_once_with('kimchi-vm')
mock_add_port.assert_called_once_with('kimchi-vm', '5999')
@mock.patch('wok.plugins.kimchi.model.virtviewerfile._get_request_host')
@mock.patch('wok.plugins.kimchi.model.virtviewerfile.' 'VMModel.get_graphics')
@mock.patch(
'wok.plugins.kimchi.model.virtviewerfile.'
'FirewallManager.add_vm_graphics_port'
)
@mock.patch(
'wok.plugins.kimchi.model.virtviewerfile.'
'VMVirtViewerFileModel.handleVMShutdownPowerOff'
)
@mock.patch(
'wok.plugins.kimchi.model.virtviewerfile.'
'VMVirtViewerFileModel._check_if_vm_running'
)
def test_vm_virtviewerfile_spice_passwd(
self,
mock_vm_running,
mock_handleVMOff,
mock_add_port,
mock_get_graphics,
mock_get_host,
):
mock_get_host.return_value = 'kimchi-test-host'
mock_get_graphics.return_value = [
'spice', 'listen', '6660', 'spicepasswd']
mock_vm_running.return_value = True
vvmodel = VMVirtViewerFileModel(conn=None)
open_ = mock.mock_open(read_data='')
with mock.patch.object(builtins, 'open', open_):
vvfilepath = vvmodel.lookup('kimchi-vm')
self.assertEqual(
vvfilepath, 'plugins/kimchi/data/virtviewerfiles/kimchi-vm-access.vv'
)
expected_write_content = (
'[virt-viewer]\ntype=spice\n'
'host=kimchi-test-host\nport=6660\npassword=spicepasswd\n'
)
self.assertEqual(open_().write.mock_calls, [
mock.call(expected_write_content)])
mock_get_graphics.assert_called_once_with('kimchi-vm', None)
mock_vm_running.assert_called_once_with('kimchi-vm')
mock_handleVMOff.assert_called_once_with('kimchi-vm')
mock_add_port.assert_called_once_with('kimchi-vm', '6660')
@mock.patch('wok.plugins.kimchi.model.virtviewerfile.run_command')
def test_firewall_provider_firewallcmd(self, mock_run_cmd):
mock_run_cmd.side_effect = [['', '', 0], ['', '', 0], ['', '', 0]]
fw_manager = FirewallManager()
fw_manager.add_vm_graphics_port('vm-name', 5905)
self.assertEqual(fw_manager.opened_ports, {'vm-name': 5905})
fw_manager.remove_vm_graphics_port('vm-name')
self.assertEqual(fw_manager.opened_ports, {})
mock_run_cmd.assert_has_calls(
[
mock.call(['firewall-cmd', '--state', '-q']),
mock.call(['firewall-cmd', '--add-port=5905/tcp']),
mock.call(['firewall-cmd', '--remove-port=5905/tcp']),
]
)
@mock.patch('wok.plugins.kimchi.model.virtviewerfile.run_command')
def test_firewall_provider_ufw(self, mock_run_cmd):
mock_run_cmd.side_effect = [['', '', 1], [
'', '', 0], ['', '', 0], ['', '', 0]]
fw_manager = FirewallManager()
fw_manager.add_vm_graphics_port('vm-name', 5905)
self.assertEqual(fw_manager.opened_ports, {'vm-name': 5905})
fw_manager.remove_vm_graphics_port('vm-name')
self.assertEqual(fw_manager.opened_ports, {})
mock_run_cmd.assert_has_calls(
[
mock.call(['firewall-cmd', '--state', '-q']),
mock.call(['ufw', 'status']),
mock.call(['ufw', 'allow', '5905/tcp']),
mock.call(['ufw', 'deny', '5905/tcp']),
]
)
@mock.patch('wok.plugins.kimchi.model.virtviewerfile.run_command')
def test_firewall_provider_iptables(self, mock_run_cmd):
mock_run_cmd.side_effect = [['', '', 1], [
'', '', 1], ['', '', 0], ['', '', 0]]
fw_manager = FirewallManager()
fw_manager.add_vm_graphics_port('vm-name', 5905)
self.assertEqual(fw_manager.opened_ports, {'vm-name': 5905})
fw_manager.remove_vm_graphics_port('vm-name')
self.assertEqual(fw_manager.opened_ports, {})
iptables_add = [
'iptables',
'-I',
'INPUT',
'-p',
'tcp',
'--dport',
5905,
'-j',
'ACCEPT',
]
iptables_del = [
'iptables',
'-D',
'INPUT',
'-p',
'tcp',
'--dport',
5905,
'-j',
'ACCEPT',
]
mock_run_cmd.assert_has_calls(
[
mock.call(['firewall-cmd', '--state', '-q']),
mock.call(['ufw', 'status']),
mock.call(iptables_add),
mock.call(iptables_del),
]
)
@unittest.skipUnless(
utils.running_as_root() and os.uname()[
4] != 's390x', 'Must be run as root'
)
@mock.patch(
'wok.plugins.kimchi.model.virtviewerfile.'
'FirewallManager.remove_vm_graphics_port'
)
@mock.patch(
'wok.plugins.kimchi.model.virtviewerfile.'
'FirewallManager.add_vm_graphics_port'
)
def test_vm_virtviewerfile_vmlifecycle(self, mock_add_port, mock_remove_port):
inst = model.Model(objstore_loc=self.tmp_store)
params = {'name': 'test', 'source_media': {
'type': 'disk', 'path': UBUNTU_ISO}}
inst.templates_create(params)
vm_name = 'kìmçhí-vñç'
with RollbackContext() as rollback:
params = {'name': vm_name,
'template': '/plugins/kimchi/templates/test'}
task1 = inst.vms_create(params)
inst.task_wait(task1['id'])
rollback.prependDefer(inst.vm_delete, vm_name)
inst.vm_start(vm_name)
graphics_info = VMModel.get_graphics(vm_name, inst.conn)
graphics_port = graphics_info[2]
vvmodel = VMVirtViewerFileModel(conn=inst.conn)
vvmodel.lookup(vm_name)
inst.vm_poweroff(vm_name)
time.sleep(5)
mock_add_port.assert_called_once_with(vm_name, graphics_port)
mock_remove_port.assert_called_once_with(
base64.b64encode(vm_name.encode('utf-8')).decode('utf-8')
)
inst.template_delete('test')
@unittest.skipUnless(
utils.running_as_root() and os.uname()[
4] != 's390x', 'Must be run as root'
)
def test_vm_serial(self):
inst = model.Model(objstore_loc=self.tmp_store)
params = {'name': 'test', 'source_media': {
'type': 'disk', 'path': UBUNTU_ISO}}
inst.templates_create(params)
with RollbackContext() as rollback:
params = {
'name': 'kimchi-serial',
'template': '/plugins/kimchi/templates/test',
}
task1 = inst.vms_create(params)
inst.task_wait(task1['id'])
rollback.prependDefer(inst.vm_delete, 'kimchi-serial')
inst.vm_start('kimchi-serial')
rollback.prependDefer(inst.vm_poweroff, 'kimchi-serial')
with self.assertRaises(OperationFailed):
inst.vm_serial('kimchi-serial')
inst.template_delete('test')
@unittest.skipUnless(utils.running_as_root(), 'Must be run as root')
def test_vm_ifaces(self):
inst = model.Model(objstore_loc=self.tmp_store)
with RollbackContext() as rollback:
params = {
'name': 'test',
'source_media': {'type': 'disk', 'path': UBUNTU_ISO},
}
inst.templates_create(params)
rollback.prependDefer(inst.template_delete, 'test')
# Create a network
net_name = 'test-network'
net_args = {
'name': net_name,
'connection': 'nat',
'subnet': '127.0.100.0/24',
}
inst.networks_create(net_args)
rollback.prependDefer(inst.network_delete, net_name)
inst.network_activate(net_name)
rollback.prependDefer(inst.network_deactivate, net_name)
for vm_name in ['kimchi-ifaces', 'kimchi-ifaces-running']:
params = {'name': vm_name,
'template': '/plugins/kimchi/templates/test'}
task = inst.vms_create(params)
inst.task_wait(task['id'])
rollback.prependDefer(inst.vm_delete, vm_name)
ifaces = inst.vmifaces_get_list(vm_name)
if not os.uname()[4] == 's390x':
self.assertEqual(1, len(ifaces))
iface = inst.vmiface_lookup(vm_name, ifaces[0])
self.assertEqual(17, len(iface['mac']))
self.assertEqual('default', iface['network'])
self.assertIn('model', iface)
# attach network interface to vm
iface_args = {
'type': 'network',
'network': 'test-network',
'model': 'virtio',
}
mac = inst.vmifaces_create(vm_name, iface_args)
# detach network interface from vm
rollback.prependDefer(inst.vmiface_delete, vm_name, mac)
self.assertEqual(17, len(mac))
iface = inst.vmiface_lookup(vm_name, mac)
self.assertEqual('network', iface['type'])
self.assertEqual('test-network', iface['network'])
self.assertEqual('virtio', iface['model'])
# attach network interface to vm without providing model
iface_args = {'type': 'network', 'network': 'test-network'}
mac = inst.vmifaces_create(vm_name, iface_args)
rollback.prependDefer(inst.vmiface_delete, vm_name, mac)
iface = inst.vmiface_lookup(vm_name, mac)
self.assertEqual('network', iface['type'])
self.assertEqual('test-network', iface['network'])
# update vm interface
newMacAddr = '54:50:e3:44:8a:af'
iface_args = {'mac': newMacAddr}
inst.vmiface_update(vm_name, mac, iface_args)
iface = inst.vmiface_lookup(vm_name, newMacAddr)
self.assertEqual(newMacAddr, iface['mac'])
# undo mac address change
iface_args = {'mac': mac}
inst.vmiface_update(vm_name, newMacAddr, iface_args)
iface = inst.vmiface_lookup(vm_name, mac)
self.assertEqual(mac, iface['mac'])
if os.uname()[4] == 's390x':
# attach macvtap interface to vm
iface_args = {
'type': 'macvtap',
'source': 'test-network',
'mode': 'vepa',
}
mac = inst.vmifaces_create(vm_name, iface_args)
rollback.prependDefer(inst.vmiface_delete, vm_name, mac)
iface = inst.vmiface_lookup(vm_name, mac)
self.assertEqual('macvtap', iface['type'])
self.assertEqual('test-network', iface['source'])
self.assertEqual('vepa', iface['mode'])
# attach ovs interface to vm
iface_args = {'type': 'ovs', 'source': 'test-network'}
mac = inst.vmifaces_create(vm_name, iface_args)
rollback.prependDefer(inst.vmiface_delete, vm_name, mac)
iface = inst.vmiface_lookup(vm_name, mac)
self.assertEqual('ovs', iface['type'])
self.assertEqual('test-network', iface['source'])
@unittest.skipUnless(utils.running_as_root(), 'Must be run as root')
def test_vm_netboot(self):
inst = model.Model(objstore_loc=self.tmp_store)
with RollbackContext() as rollback:
params = {'name': 'test-netboot',
'source_media': {'type': 'netboot'}}
inst.templates_create(params)
rollback.prependDefer(inst.template_delete, 'test-netboot')
params = {
'name': 'kimchi-netboot-vm',
'template': '/plugins/kimchi/templates/test-netboot',
}
task = inst.vms_create(params)
rollback.prependDefer(inst.vm_delete, 'kimchi-netboot-vm')
inst.task_wait(task['id'], 10)
task = inst.task_lookup(task['id'])
self.assertEqual('finished', task['status'])
vms = inst.vms_get_list()
self.assertTrue('kimchi-netboot-vm' in vms)
inst.vm_start('kimchi-netboot-vm')
info = inst.vm_lookup('kimchi-netboot-vm')
self.assertEqual('running', info['state'])
inst.vm_poweroff(u'kimchi-netboot-vm')
vms = inst.vms_get_list()
self.assertFalse('kimchi-netboot-vm' in vms)
@unittest.skipUnless(
utils.running_as_root() and os.uname()[
4] != 's390x', 'Must be run as root'
)
def test_vm_disk(self):
disk_path = os.path.join(TMP_DIR, 'existent2.iso')
open(disk_path, 'w').close()
modern_disk_bus = osinfo.get_template_default('modern', 'disk_bus')
def _attach_disk(expect_bus=modern_disk_bus):
disk_args = {'type': 'disk', 'pool': pool, 'vol': vol}
disk = inst.vmstorages_create(vm_name, disk_args)
storage_list = inst.vmstorages_get_list(vm_name)
self.assertEqual(prev_count + 1, len(storage_list))
# Check the bus type to be 'virtio'
disk_info = inst.vmstorage_lookup(vm_name, disk)
self.assertEqual(u'disk', disk_info['type'])
self.assertEqual(vol_path, disk_info['path'])
self.assertEqual(expect_bus, disk_info['bus'])
return disk
inst = model.Model(objstore_loc=self.tmp_store)
with RollbackContext() as rollback:
path = os.path.join(TMP_DIR, 'kimchi-images')
pool = 'test-pool'
vol = 'test-volume.img'
vol_path = '%s/%s' % (path, vol)
if not os.path.exists(path):
os.mkdir(path)
rollback.prependDefer(shutil.rmtree, path)
args = {'name': pool, 'path': path, 'type': 'dir'}
inst.storagepools_create(args)
rollback.prependDefer(inst.storagepool_delete, pool)
# Activate the pool before adding any volume
inst.storagepool_activate(pool)
rollback.prependDefer(inst.storagepool_deactivate, pool)
params = {
'name': vol,
'capacity': 1073741824, # 1 GiB
'allocation': 536870912, # 512 MiB
'format': 'qcow2',
}
task_id = inst.storagevolumes_create(pool, params)['id']
rollback.prependDefer(inst.storagevolume_delete, pool, vol)
inst.task_wait(task_id)
vm_name = 'kimchi-cdrom'
params = {
'name': 'test',
'disks': [],
'source_media': {'type': 'disk', 'path': UBUNTU_ISO},
}
inst.templates_create(params)
rollback.prependDefer(inst.template_delete, 'test')
params = {'name': vm_name,
'template': '/plugins/kimchi/templates/test'}
task1 = inst.vms_create(params)
inst.task_wait(task1['id'])
rollback.prependDefer(inst.vm_delete, vm_name)
prev_count = len(inst.vmstorages_get_list(vm_name))
self.assertEqual(1, prev_count)
# Volume format with mismatched type raise error
cdrom_args = {'type': 'cdrom', 'pool': pool, 'vol': vol}
self.assertRaises(
InvalidParameter, inst.vmstorages_create, vm_name, cdrom_args
)
# Cold plug and unplug a disk
disk = _attach_disk()
inst.vmstorage_delete(vm_name, disk)
# Hot plug a disk
inst.vm_start(vm_name)
disk = _attach_disk()
# VM disk still there after powered off
inst.vm_poweroff(vm_name)
disk_info = inst.vmstorage_lookup(vm_name, disk)
self.assertEqual(u'disk', disk_info['type'])
inst.vmstorage_delete(vm_name, disk)
# Specifying pool and path at same time will fail
disk_args = {'type': 'disk', 'pool': pool,
'vol': vol, 'path': disk_path}
self.assertRaises(
InvalidParameter, inst.vmstorages_create, vm_name, disk_args
)
old_distro_iso = TMP_DIR + 'rhel4_8.iso'
construct_fake_iso(old_distro_iso, True, '4.8', 'rhel')
vm_name = 'kimchi-ide-bus-vm'
params = {
'name': 'old_distro_template',
'disks': [],
'source_media': {'type': 'disk', 'path': old_distro_iso},
}
inst.templates_create(params)
rollback.prependDefer(inst.template_delete, 'old_distro_template')
params = {
'name': vm_name,
'template': '/plugins/kimchi/templates/old_distro_template',
}
task2 = inst.vms_create(params)
inst.task_wait(task2['id'])
rollback.prependDefer(inst.vm_delete, vm_name)
# Need to check the right disk_bus for old distro
disk = _attach_disk(osinfo.get_template_default('old', 'disk_bus'))
inst.vmstorage_delete('kimchi-ide-bus-vm', disk)
# Hot plug IDE bus disk does not work
inst.vm_start(vm_name)
self.assertRaises(InvalidOperation, _attach_disk)
inst.vm_poweroff(vm_name)
@unittest.skipUnless(utils.running_as_root(), 'Must be run as root')
def test_vm_cdrom(self):
inst = model.Model(objstore_loc=self.tmp_store)
with RollbackContext() as rollback:
vm_name = 'kimchi-cdrom'
params = {
'name': 'test',
'disks': [],
'source_media': {'type': 'disk', 'path': UBUNTU_ISO},
}
inst.templates_create(params)
rollback.prependDefer(inst.template_delete, 'test')
params = {'name': vm_name,
'template': '/plugins/kimchi/templates/test'}
task = inst.vms_create(params)
inst.task_wait(task['id'])
rollback.prependDefer(inst.vm_delete, vm_name)
prev_count = len(inst.vmstorages_get_list(vm_name))
self.assertEqual(1, prev_count)
# dummy .iso files
iso_path = os.path.join(TMP_DIR, 'existent.iso')
iso_path2 = os.path.join(TMP_DIR, 'existent2.iso')
open(iso_path, 'w').close()
rollback.prependDefer(os.remove, iso_path)
open(iso_path2, 'w').close()
rollback.prependDefer(os.remove, iso_path2)
wrong_iso_path = '/nonexistent.iso'
# Create a cdrom
cdrom_args = {'type': 'cdrom', 'path': iso_path}
cdrom_dev = inst.vmstorages_create(vm_name, cdrom_args)
storage_list = inst.vmstorages_get_list(vm_name)
self.assertEqual(prev_count + 1, len(storage_list))
# Get cdrom info
cd_info = inst.vmstorage_lookup(vm_name, cdrom_dev)
self.assertEqual(u'cdrom', cd_info['type'])
self.assertEqual(iso_path, cd_info['path'])
# update path of existing cd with
# non existent iso
self.assertRaises(
InvalidParameter,
inst.vmstorage_update,
vm_name,
cdrom_dev,
{'path': wrong_iso_path},
)
# Make sure CD ROM still exists after failure
cd_info = inst.vmstorage_lookup(vm_name, cdrom_dev)
self.assertEqual(u'cdrom', cd_info['type'])
self.assertEqual(iso_path, cd_info['path'])
# update path of existing cd with existent iso of shutoff vm
inst.vmstorage_update(vm_name, cdrom_dev, {'path': iso_path2})
cdrom_info = inst.vmstorage_lookup(vm_name, cdrom_dev)
self.assertEqual(iso_path2, cdrom_info['path'])
# update path of existing cd with existent iso of running vm
inst.vm_start(vm_name)
inst.vmstorage_update(vm_name, cdrom_dev, {'path': iso_path})
cdrom_info = inst.vmstorage_lookup(vm_name, cdrom_dev)
self.assertEqual(iso_path, cdrom_info['path'])
# eject cdrom
cdrom_dev = inst.vmstorage_update(vm_name, cdrom_dev, {'path': ''})
cdrom_info = inst.vmstorage_lookup(vm_name, cdrom_dev)
self.assertEqual('', cdrom_info['path'])
inst.vm_poweroff(vm_name)
# removing non existent cdrom
self.assertRaises(
NotFoundError, inst.vmstorage_delete, vm_name, 'fakedev')
# removing valid cdrom
inst.vmstorage_delete(vm_name, cdrom_dev)
storage_list = inst.vmstorages_get_list(vm_name)
self.assertEqual(prev_count, len(storage_list))
# Create a new cdrom using a remote iso
valid_remote_iso_path = get_remote_iso_path()
cdrom_args = {'type': 'cdrom', 'path': valid_remote_iso_path}
cdrom_dev = inst.vmstorages_create(vm_name, cdrom_args)
storage_list = inst.vmstorages_get_list(vm_name)
self.assertEqual(prev_count + 1, len(storage_list))
# Update remote-backed cdrom with the same ISO
inst.vmstorage_update(vm_name, cdrom_dev, {
'path': valid_remote_iso_path})
cdrom_info = inst.vmstorage_lookup(vm_name, cdrom_dev)
cur_cdrom_path = re.sub(':80/', '/', cdrom_info['path'])
self.assertEqual(valid_remote_iso_path, cur_cdrom_path)
@unittest.skipUnless(utils.running_as_root(), 'Must be run as root')
def test_vm_storage_provisioning(self):
inst = model.Model(objstore_loc=self.tmp_store)
with RollbackContext() as rollback:
params = {
'name': 'test',
'disks': [
{
'size': 1,
'pool': {'name': '/plugins/kimchi/storagepools/default'},
}
],
'source_media': {'type': 'disk', 'path': UBUNTU_ISO},
}
inst.templates_create(params)
rollback.prependDefer(inst.template_delete, 'test')
params = {'name': 'test-vm-1',
'template': '/plugins/kimchi/templates/test'}
task = inst.vms_create(params)
inst.task_wait(task['id'])
rollback.prependDefer(inst.vm_delete, 'test-vm-1')
vm_info = inst.vm_lookup(params['name'])
disk_path = '%s/%s-0.img' % (
inst.storagepool_lookup('default')['path'],
vm_info['uuid'],
)
self.assertTrue(os.access(disk_path, os.F_OK))
self.assertFalse(os.access(disk_path, os.F_OK))
def _create_template_conf_with_disk_format(self, vol_format):
if vol_format is None:
conf_file_data = (
'[main]\n\n[storage]\n\n[[disk.0]]\n'
'#format = \n\n[graphics]\n\n[processor]\n'
)
else:
conf_file_data = (
'[main]\n\n[storage]\n\n[[disk.0]]\n'
'format = %s\n\n[graphics]\n\n[processor]\n' % vol_format
)
config_file = os.path.join(paths.sysconf_dir, 'template.conf')
config_bkp_file = os.path.join(
paths.sysconf_dir, 'template.conf-unit_test_bkp')
os.rename(config_file, config_bkp_file)
with open(config_file, 'w') as f:
f.write(conf_file_data)
osinfo.defaults = osinfo._get_tmpl_defaults()
def _restore_template_conf_file(self):
config_file = os.path.join(paths.sysconf_dir, 'template.conf')
config_bkp_file = os.path.join(
paths.sysconf_dir, 'template.conf-unit_test_bkp')
os.rename(config_bkp_file, config_file)
osinfo.defaults = osinfo._get_tmpl_defaults()
def _get_disk_format_from_vm(self, vm, conn):
dom = VMModel.get_vm(vm, conn)
xml = dom.XMLDesc(0)
xpath = "/domain/devices/disk[@device='disk']/driver/@type"
return xpath_get_text(xml, xpath)[0]
@unittest.skipUnless(utils.running_as_root(), 'Must be run as root')
def test_template_get_default_vol_format_from_conf(self):
inst = model.Model(objstore_loc=self.tmp_store)
with RollbackContext() as rollback:
self._create_template_conf_with_disk_format('vmdk')
rollback.prependDefer(self._restore_template_conf_file)
params = {
'name': 'test',
'disks': [
{
'size': 1,
'pool': {'name': '/plugins/kimchi/storagepools/default'},
}
],
'source_media': {'type': 'disk', 'path': UBUNTU_ISO},
}
inst.templates_create(params)
rollback.prependDefer(inst.template_delete, 'test')
params = {'name': 'test-vm-1',
'template': '/plugins/kimchi/templates/test'}
task = inst.vms_create(params)
inst.task_wait(task['id'])
rollback.prependDefer(inst.vm_delete, 'test-vm-1')
created_disk_format = self._get_disk_format_from_vm(
'test-vm-1', inst.conn)
self.assertEqual(created_disk_format, 'vmdk')
@unittest.skipUnless(utils.running_as_root(), 'Must be run as root')
def test_template_creates_user_defined_vol_format_instead_default(self):
inst = model.Model(objstore_loc=self.tmp_store)
default_vol = 'vmdk'
user_vol = 'raw'
with RollbackContext() as rollback:
self._create_template_conf_with_disk_format(default_vol)
rollback.prependDefer(self._restore_template_conf_file)
params = {
'name': 'test',
'disks': [
{
'size': 1,
'format': user_vol,
'pool': {'name': '/plugins/kimchi/storagepools/default'},
}
],
'source_media': {'type': 'disk', 'path': UBUNTU_ISO},
}
inst.templates_create(params)
rollback.prependDefer(inst.template_delete, 'test')
params = {'name': 'test-vm-1',
'template': '/plugins/kimchi/templates/test'}
task = inst.vms_create(params)
inst.task_wait(task['id'])
rollback.prependDefer(inst.vm_delete, 'test-vm-1')
created_disk_format = self._get_disk_format_from_vm(
'test-vm-1', inst.conn)
self.assertEqual(created_disk_format, user_vol)
@unittest.skipUnless(utils.running_as_root(), 'Must be run as root')
def test_template_uses_qcow2_format_if_no_user_or_default_defined(self):
inst = model.Model(objstore_loc=self.tmp_store)
with RollbackContext() as rollback:
self._create_template_conf_with_disk_format(None)
rollback.prependDefer(self._restore_template_conf_file)
params = {
'name': 'test',
'disks': [
{
'size': 1,
'pool': {'name': '/plugins/kimchi/storagepools/default'},
}
],
'source_media': {'type': 'disk', 'path': UBUNTU_ISO},
}
inst.templates_create(params)
rollback.prependDefer(inst.template_delete, 'test')
params = {'name': 'test-vm-1',
'template': '/plugins/kimchi/templates/test'}
task = inst.vms_create(params)
inst.task_wait(task['id'])
rollback.prependDefer(inst.vm_delete, 'test-vm-1')
created_disk_format = self._get_disk_format_from_vm(
'test-vm-1', inst.conn)
self.assertEqual(created_disk_format, 'qcow2')
def test_vm_memory_hotplug(self):
config.set('authentication', 'method', 'pam')
inst = model.Model(None, objstore_loc=self.tmp_store)
orig_params = {
'name': 'test',
'memory': {
'current': 1024,
'maxmemory': 4096 if os.uname()[4] != 's390x' else 2048,
},
'source_media': {'type': 'disk', 'path': UBUNTU_ISO},
}
inst.templates_create(orig_params)
with RollbackContext() as rollback:
params = {
'name': 'kimchi-vm1',
'template': '/plugins/kimchi/templates/test',
}
task1 = inst.vms_create(params)
inst.task_wait(task1['id'])
rollback.prependDefer(utils.rollback_wrapper,
inst.vm_delete, 'kimchi-vm1')
# Start vm
inst.vm_start('kimchi-vm1')
rollback.prependDefer(
utils.rollback_wrapper, inst.vm_poweroff, 'kimchi-vm1'
)
# Hotplug memory, only available in Libvirt >= 1.2.14
params = {'memory': {'current': 2048}}
if inst.capabilities_lookup()['mem_hotplug_support']:
inst.vm_update('kimchi-vm1', params)
rollback.prependDefer(
utils.rollback_wrapper, inst.vm_delete, 'kimchi-vm1'
)
params['memory']['maxmemory'] = 4096
self.assertEqual(
params['memory'], inst.vm_lookup('kimchi-vm1')['memory']
)
params['memory']['current'] = 4096
del params['memory']['maxmemory']
inst.vm_update('kimchi-vm1', params)
vm = inst.vm_lookup('kimchi-vm1')
self.assertEqual(4096, vm['memory']['current'])
# Test memory devices
conn = inst.conn.get()
xml = conn.lookupByName('kimchi-vm1').XMLDesc()
root = ET.fromstring(xml)
devs = root.findall('./devices/memory/target/size')
self.assertEqual(2, len(devs))
totMemDevs = 0
for size in devs:
totMemDevs += convert_data_size(size.text,
size.get('unit'), 'MiB')
self.assertEqual(3072, totMemDevs)
inst.vm_poweroff('kimchi-vm1')
# Remove all devs:
params = {'memory': {'current': 1024}}
inst.vm_update('kimchi-vm1', params)
xml = conn.lookupByName('kimchi-vm1').XMLDesc()
root = ET.fromstring(xml)
devs = root.findall('./devices/memory')
self.assertEqual(0, len(devs))
# Hotplug 1G DIMM , 512M , 256M and 256M
inst.vm_start('kimchi-vm1')
params = {'memory': {'current': 2048}}
inst.vm_update('kimchi-vm1', params)
params = {'memory': {'current': 2560}}
inst.vm_update('kimchi-vm1', params)
params = {'memory': {'current': 2816}}
inst.vm_update('kimchi-vm1', params)
params = {'memory': {'current': 3072}}
inst.vm_update('kimchi-vm1', params)
vm = inst.vm_lookup('kimchi-vm1')
self.assertEqual(3072, vm['memory']['current'])
xml = conn.lookupByName('kimchi-vm1').XMLDesc()
root = ET.fromstring(xml)
devs = root.findall('./devices/memory/target/size')
self.assertEqual(4, len(devs))
totMemDevs = 0
for size in devs:
totMemDevs += convert_data_size(size.text,
size.get('unit'), 'MiB')
self.assertEqual(2048, totMemDevs)
inst.vm_poweroff('kimchi-vm1')
# Remove 2x256M + 1x512M ... then sum 256M to virtual memory
params = {'memory': {'current': 2304}}
inst.vm_update('kimchi-vm1', params)
xml = conn.lookupByName('kimchi-vm1').XMLDesc()
root = ET.fromstring(xml)
devs = root.findall('./devices/memory/target/size')
self.assertEqual(1, len(devs))
totMemDevs = 0
for size in devs:
totMemDevs += convert_data_size(size.text,
size.get('unit'), 'MiB')
self.assertEqual(1024, totMemDevs)
else:
self.assertRaises(
InvalidOperation, inst.vm_update, 'kimchi-vm1', params
)
msg = 'Memory hotplug in non-numa guests only for PowerPC arch.'
@unittest.skipUnless(('ppc64' in os.uname()[4]), msg)
def test_non_numa_vm_memory_hotplug(self):
config.set('authentication', 'method', 'pam')
inst = model.Model(None, objstore_loc=self.tmp_store)
conn = inst.conn.get()
vm = 'non-numa-kimchi-test'
with RollbackContext() as rollback:
conn.defineXML(NON_NUMA_XML)
rollback.prependDefer(conn.lookupByName(vm).undefine)
# Start vm
inst.vm_start(vm)
# Hotplug memory
params = {'memory': {'current': 3072}}
inst.vm_update(vm, params)
self.assertEqual(
params['memory']['current'], inst.vm_lookup(
vm)['memory']['current']
)
# Test number and size of memory device added
root = ET.fromstring(conn.lookupByName(vm).XMLDesc())
devs = root.findall('./devices/memory/target/size')
self.assertEqual(1, len(devs))
self.assertEqual(2048 << 10, int(devs[0].text))
params = {'memory': {'current': 4096}}
inst.vm_update(vm, params)
self.assertEqual(
params['memory']['current'], inst.vm_lookup(
vm)['memory']['current']
)
# Test number and size of memory device added
root = ET.fromstring(conn.lookupByName(vm).XMLDesc())
devs = root.findall('./devices/memory/target/size')
self.assertEqual(2, len(devs))
self.assertEqual(1024 << 10, int(devs[1].text))
self.assertEqual(3072 << 10, int(devs[0].text) + int(devs[1].text))
# Stop vm and test persistence
inst.vm_poweroff(vm)
self.assertEqual(
params['memory']['current'], inst.vm_lookup(
vm)['memory']['current']
)
def test_vm_edit(self):
config.set('authentication', 'method', 'pam')
inst = model.Model(None, objstore_loc=self.tmp_store)
# template disk format must be qcow2 because vmsnapshot
# only supports this format
orig_params = {
'name': 'test',
'memory': {'current': 1024, 'maxmemory': 2048},
'cpu_info': {'vcpus': 1},
'source_media': {'type': 'disk', 'path': UBUNTU_ISO},
'disks': [
{
'size': 1,
'format': 'qcow2',
'pool': {'name': '/plugins/kimchi/storagepools/default'},
}
],
}
inst.templates_create(orig_params)
with RollbackContext() as rollback:
params_1 = {
'name': 'kimchi-vm1',
'template': '/plugins/kimchi/templates/test',
}
params_2 = {
'name': 'kimchi-vm2',
'template': '/plugins/kimchi/templates/test',
}
task1 = inst.vms_create(params_1)
inst.task_wait(task1['id'])
rollback.prependDefer(utils.rollback_wrapper,
inst.vm_delete, 'kimchi-vm1')
task2 = inst.vms_create(params_2)
inst.task_wait(task2['id'])
rollback.prependDefer(utils.rollback_wrapper,
inst.vm_delete, 'kimchi-vm2')
vms = inst.vms_get_list()
self.assertTrue('kimchi-vm1' in vms)
# make sure "vm_update" works when the domain has a snapshot
inst.vmsnapshots_create(u'kimchi-vm1')
if os.uname()[4] != 's390x':
# update vm graphics when vm is not running
inst.vm_update(
u'kimchi-vm1', {'graphics': {'passwd': '123456'}})
inst.vm_start('kimchi-vm1')
rollback.prependDefer(
utils.rollback_wrapper, inst.vm_poweroff, 'kimchi-vm1'
)
vm_info = inst.vm_lookup('kimchi-vm1')
self.assertEqual('123456', vm_info['graphics']['passwd'])
self.assertEqual(None, vm_info['graphics']['passwdValidTo'])
# update vm graphics when vm is running
inst.vm_update(
'kimchi-vm1',
{'graphics': {'passwd': 'abcdef', 'passwdValidTo': 20}},
)
vm_info = inst.vm_lookup('kimchi-vm1')
self.assertEqual('abcdef', vm_info['graphics']['passwd'])
self.assertGreaterEqual(
20, vm_info['graphics']['passwdValidTo'])
info = inst.vm_lookup('kimchi-vm1')
self.assertEqual('running', info['state'])
params = {'name': 'new-vm'}
self.assertRaises(
InvalidParameter, inst.vm_update, 'kimchi-vm1', params
)
else:
inst.vm_start('kimchi-vm1')
# change VM users and groups, when wm is running.
inst.vm_update(
u'kimchi-vm1', {'users': ['root'], 'groups': ['root']})
vm_info = inst.vm_lookup(u'kimchi-vm1')
self.assertEqual(['root'], vm_info['users'])
self.assertEqual(['root'], vm_info['groups'])
# change VM users and groups by removing all elements,
# when vm is running.
inst.vm_update(u'kimchi-vm1', {'users': [], 'groups': []})
vm_info = inst.vm_lookup(u'kimchi-vm1')
self.assertEqual([], vm_info['users'])
self.assertEqual([], vm_info['groups'])
# power off vm
inst.vm_poweroff('kimchi-vm1')
self.assertRaises(
OperationFailed, inst.vm_update, 'kimchi-vm1', {
'name': 'kimchi-vm2'}
)
# update maxvcpus only
inst.vm_update(u'kimchi-vm1', {'cpu_info': {'maxvcpus': 8}})
vm_info = inst.vm_lookup(u'kimchi-vm1')
self.assertEqual(8, vm_info['cpu_info']['maxvcpus'])
# update vcpus only
inst.vm_update(u'kimchi-vm1', {'cpu_info': {'vcpus': 4}})
vm_info = inst.vm_lookup(u'kimchi-vm1')
self.assertEqual(4, vm_info['cpu_info']['vcpus'])
# vcpus > maxvcpus: failure
self.assertRaises(
InvalidParameter,
inst.vm_update,
u'kimchi-vm1',
{'cpu_info': {'vcpus': 10}},
)
# define CPU topology
inst.vm_update(
u'kimchi-vm1',
{'cpu_info': {'topology': {'sockets': 2, 'cores': 2, 'threads': 2}}},
)
vm_info = inst.vm_lookup(u'kimchi-vm1')
self.assertEqual(
{'sockets': 2, 'cores': 2, 'threads': 2},
vm_info['cpu_info']['topology'],
)
# vcpus not a multiple of threads
self.assertRaises(
InvalidParameter,
inst.vm_update,
u'kimchi-vm1',
{'cpu_info': {'vcpus': 5}},
)
# maxvcpus different of (sockets * cores * threads)
self.assertRaises(
InvalidParameter,
inst.vm_update,
u'kimchi-vm1',
{'cpu_info': {'maxvcpus': 4}},
)
# topology does not match maxvcpus (8 != 3 * 2 * 2)
self.assertRaises(
InvalidParameter,
inst.vm_update,
u'kimchi-vm1',
{'cpu_info': {'topology': {'sockets': 3, 'cores': 2, 'threads': 2}}},
)
# undefine CPU topology
inst.vm_update(u'kimchi-vm1', {'cpu_info': {'topology': {}}})
vm_info = inst.vm_lookup(u'kimchi-vm1')
self.assertEqual({}, vm_info['cpu_info']['topology'])
# reduce maxvcpus to same as vcpus
inst.vm_update(u'kimchi-vm1', {'cpu_info': {'maxvcpus': 4}})
vm_info = inst.vm_lookup(u'kimchi-vm1')
self.assertEqual(4, vm_info['cpu_info']['maxvcpus'])
# rename and increase memory when vm is not running
params = {'name': u'пeω-∨м', 'memory': {'current': 2048}}
inst.vm_update('kimchi-vm1', params)
rollback.prependDefer(utils.rollback_wrapper,
inst.vm_delete, u'пeω-∨м')
self.assertEqual(
vm_info['uuid'], inst.vm_lookup(u'пeω-∨м')['uuid'])
info = inst.vm_lookup(u'пeω-∨м')
# Max memory is returned, add to test
params['memory']['maxmemory'] = 2048
for key in params.keys():
self.assertEqual(params[key], info[key])
# change only VM users - groups are not changed (default is empty)
users = inst.users_get_list()[:3]
inst.vm_update(u'пeω-∨м', {'users': users})
self.assertEqual(users, inst.vm_lookup(u'пeω-∨м')['users'])
self.assertEqual([], inst.vm_lookup(u'пeω-∨м')['groups'])
# change only VM groups - users are not changed (default is empty)
groups = inst.groups_get_list()[:2]
inst.vm_update(u'пeω-∨м', {'groups': groups})
self.assertEqual(users, inst.vm_lookup(u'пeω-∨м')['users'])
self.assertEqual(groups, inst.vm_lookup(u'пeω-∨м')['groups'])
# change VM users and groups by adding a new element to each one
users.append(pwd.getpwuid(os.getuid()).pw_name)
groups.append(grp.getgrgid(os.getgid()).gr_name)
inst.vm_update(u'пeω-∨м', {'users': users, 'groups': groups})
self.assertEqual(users, inst.vm_lookup(u'пeω-∨м')['users'])
self.assertEqual(groups, inst.vm_lookup(u'пeω-∨м')['groups'])
# change VM users (wrong value) and groups
# when an error occurs, everything fails and nothing is changed
self.assertRaises(
InvalidParameter,
inst.vm_update,
u'пeω-∨м',
{'users': ['userdoesnotexist'], 'groups': []},
)
self.assertEqual(users, inst.vm_lookup(u'пeω-∨м')['users'])
self.assertEqual(groups, inst.vm_lookup(u'пeω-∨м')['groups'])
# change VM users and groups (wrong value)
# when an error occurs, everything fails and nothing is changed
self.assertRaises(
InvalidParameter,
inst.vm_update,
u'пeω-∨м',
{'users': [], 'groups': ['groupdoesnotexist']},
)
self.assertEqual(users, inst.vm_lookup(u'пeω-∨м')['users'])
self.assertEqual(groups, inst.vm_lookup(u'пeω-∨м')['groups'])
# change VM users and groups by removing all elements
inst.vm_update(u'пeω-∨м', {'users': [], 'groups': []})
self.assertEqual([], inst.vm_lookup(u'пeω-∨м')['users'])
self.assertEqual([], inst.vm_lookup(u'пeω-∨м')['groups'])
# change bootorder
b_order = ['hd', 'network', 'cdrom']
inst.vm_update(u'пeω-∨м', {'bootorder': b_order})
self.assertEqual(b_order, inst.vm_lookup(u'пeω-∨м')['bootorder'])
# try to add empty list
self.assertRaises(
OperationFailed, inst.vm_update, u'пeω-∨м', {'bootorder': ['']}
)
# try to pass invalid parameter
self.assertRaises(
OperationFailed, inst.vm_update, u'пeω-∨м', {
'bootorder': ['bla']}
)
# enable/disable bootmenu
inst.vm_update(u'пeω-∨м', {'bootmenu': True})
self.assertEqual('yes', inst.vm_lookup(u'пeω-∨м')['bootmenu'])
inst.vm_update(u'пeω-∨м', {'bootmenu': False})
self.assertEqual('no', inst.vm_lookup(u'пeω-∨м')['bootmenu'])
def test_get_vm_cpu_cores(self):
xml = """\
\
"""
inst = model.Model(None, objstore_loc=self.tmp_store)
self.assertEqual('2', inst.vm_get_vm_cpu_cores(xml))
def test_get_vm_cpu_sockets(self):
xml = """\
\
"""
inst = model.Model(None, objstore_loc=self.tmp_store)
self.assertEqual('3', inst.vm_get_vm_cpu_sockets(xml))
def test_get_vm_cpu_threads(self):
xml = """\
\
"""
inst = model.Model(None, objstore_loc=self.tmp_store)
self.assertEqual('8', inst.vm_get_vm_cpu_threads(xml))
@mock.patch('wok.plugins.kimchi.model.vms.VMModel.has_topology')
def test_get_vm_cpu_topology(self, mock_has_topology):
class FakeDom:
def XMLDesc(self, flag):
return """\
\
"""
def name(self):
return 'fakedom'
mock_has_topology.return_value = True
expected_topology = {'sockets': 3, 'cores': 2, 'threads': 8}
inst = model.Model(None, objstore_loc=self.tmp_store)
self.assertEqual(expected_topology,
inst.vm_get_vm_cpu_topology(FakeDom()))
@mock.patch('wok.plugins.kimchi.model.vms.VMModel.has_topology')
def test_get_vm_cpu_topology_blank(self, mock_has_topology):
class FakeDom:
def XMLDesc(self, flag):
return """"""
def name(self):
return 'fakedom'
mock_has_topology.return_value = False
expected_topology = {}
inst = model.Model(None, objstore_loc=self.tmp_store)
self.assertEqual(expected_topology,
inst.vm_get_vm_cpu_topology(FakeDom()))
def test_vm_cpu_hotplug_invalidparam_fail(self):
inst = model.Model(None, objstore_loc=self.tmp_store)
with self.assertRaisesRegexp(InvalidParameter, 'KCHCPUHOTP0001E'):
params = {'cpu_info': {'vcpus': 1, 'maxvcpus': 4}}
inst.vm_cpu_hotplug_precheck('', params)
@mock.patch('wok.plugins.kimchi.model.vms.VMModel.has_topology')
def test_vm_cpu_hotplug_abovemax_fail(self, mock_has_topology):
class FakeDom:
def XMLDesc(self, flag):
return """\
8<\
/domain>"""
def name(self):
return 'fakedom'
mock_has_topology.return_value = False
inst = model.Model(None, objstore_loc=self.tmp_store)
with self.assertRaisesRegexp(InvalidParameter, 'KCHCPUINF0001E'):
params = {'cpu_info': {'vcpus': 16}}
inst.vm_cpu_hotplug_precheck(FakeDom(), params)
@mock.patch('wok.plugins.kimchi.model.vms.VMModel.has_topology')
@mock.patch('wok.plugins.kimchi.model.vms.VMModel.get_vm_cpu_topology')
def test_vm_cpu_hotplug_topology_mismatch_fail(
self, mock_topology, mock_has_topology
):
class FakeDom:
def XMLDesc(self, flag):
return """\
48<\
/domain>"""
def name(self):
return 'fakedom'
mock_has_topology.return_value = True
mock_topology.return_value = {'sockets': 3, 'cores': 2, 'threads': 8}
inst = model.Model(None, objstore_loc=self.tmp_store)
with self.assertRaisesRegexp(InvalidParameter, 'KCHCPUINF0005E'):
params = {'cpu_info': {'vcpus': 10}}
inst.vm_cpu_hotplug_precheck(FakeDom(), params)
def test_vm_cpu_hotplug_error(self):
class FakeDom:
def setVcpusFlags(self, vcpu, flags):
raise libvirt.libvirtError('')
inst = model.Model(None, objstore_loc=self.tmp_store)
with self.assertRaisesRegexp(OperationFailed, 'KCHCPUHOTP0002E'):
inst.vm_update_cpu_live(FakeDom(), '')
# enable/disable autostart
inst.vm_update(u'пeω-∨м', {'autostart': True})
self.assertEqual(1, inst.vm_lookup(u'пeω-∨м')['autostart'])
inst.vm_update(u'пeω-∨м', {'autostart': False})
self.assertEqual(0, inst.vm_lookup(u'пeω-∨м')['autostart'])
def test_get_interfaces(self):
inst = model.Model('test:///default', objstore_loc=self.tmp_store)
expected_ifaces = netinfo.all_favored_interfaces()
ifaces = inst.interfaces_get_list()
self.assertEqual(len(expected_ifaces), len(ifaces))
for name in expected_ifaces:
iface = inst.interface_lookup(name)
self.assertEqual(iface['name'], name)
self.assertIn('type', iface)
self.assertIn('status', iface)
self.assertIn('ipaddr', iface)
self.assertIn('netmask', iface)
def test_async_tasks(self):
class task_except(Exception):
pass
def quick_op(cb, message):
cb(message, True)
def long_op(cb, params):
time.sleep(params.get('delay', 3))
cb(params.get('message', ''), params.get('result', False))
def abnormal_op(cb, params):
try:
raise task_except
except Exception:
cb('Exception raised', False)
def continuous_ops(cb, params):
cb('step 1 OK')
time.sleep(2)
cb('step 2 OK')
time.sleep(2)
cb('step 3 OK', params.get('result', True))
inst = model.Model('test:///default', objstore_loc=self.tmp_store)
taskid = AsyncTask('', quick_op, 'Hello').id
inst.task_wait(taskid)
self.assertEqual('finished', inst.task_lookup(taskid)['status'])
self.assertEqual('Hello', inst.task_lookup(taskid)['message'])
params = {'delay': 3, 'result': False,
'message': 'It was not meant to be'}
taskid = AsyncTask('', long_op, params).id
self.assertEqual('running', inst.task_lookup(taskid)['status'])
self.assertEqual(
'The request is being processing.', inst.task_lookup(taskid)[
'message']
)
inst.task_wait(taskid)
self.assertEqual('failed', inst.task_lookup(taskid)['status'])
self.assertEqual('It was not meant to be',
inst.task_lookup(taskid)['message'])
taskid = AsyncTask('', abnormal_op, {}).id
inst.task_wait(taskid)
self.assertEqual('Exception raised',
inst.task_lookup(taskid)['message'])
self.assertEqual('failed', inst.task_lookup(taskid)['status'])
taskid = AsyncTask('', continuous_ops, {'result': True}).id
self.assertEqual('running', inst.task_lookup(taskid)['status'])
inst.task_wait(taskid, timeout=10)
self.assertEqual('finished', inst.task_lookup(taskid)['status'])
@unittest.skipUnless(utils.running_as_root(), 'Must be run as root')
def test_delete_running_vm(self):
inst = model.Model(objstore_loc=self.tmp_store)
with RollbackContext() as rollback:
params = {
'name': u'test',
'disks': [],
'source_media': {'type': 'disk', 'path': UBUNTU_ISO},
}
inst.templates_create(params)
rollback.prependDefer(inst.template_delete, 'test')
params = {
'name': u'kīмсhī-∨м',
'template': u'/plugins/kimchi/templates/test',
}
task = inst.vms_create(params)
inst.task_wait(task['id'])
rollback.prependDefer(utils.rollback_wrapper,
inst.vm_delete, u'kīмсhī-∨м')
inst.vm_start(u'kīмсhī-∨м')
self.assertEqual(inst.vm_lookup(u'kīмсhī-∨м')['state'], 'running')
rollback.prependDefer(
utils.rollback_wrapper, inst.vm_poweroff, u'kīмсhī-∨м'
)
inst.vm_delete(u'kīмсhī-∨м')
vms = inst.vms_get_list()
self.assertFalse(u'kīмсhī-∨м' in vms)
@unittest.skipUnless(utils.running_as_root(), 'Must be run as root')
def test_vm_list_sorted(self):
inst = model.Model(objstore_loc=self.tmp_store)
with RollbackContext() as rollback:
params = {
'name': 'test',
'disks': [],
'source_media': {'type': 'disk', 'path': UBUNTU_ISO},
}
inst.templates_create(params)
rollback.prependDefer(inst.template_delete, 'test')
params = {'name': 'kimchi-vm',
'template': '/plugins/kimchi/templates/test'}
task = inst.vms_create(params)
inst.task_wait(task['id'])
rollback.prependDefer(inst.vm_delete, 'kimchi-vm')
vms = inst.vms_get_list()
self.assertEqual(vms, sorted(vms, key=str.lower))
def test_vm_clone(self):
inst = model.Model('test:///default', objstore_loc=self.tmp_store)
all_vm_names = inst.vms_get_list()
name = all_vm_names[0]
original_vm = inst.vm_lookup(name)
if original_vm['state'] == u'shutoff':
inst.vm_start(name)
# the VM 'test' should be running by now, so we can't clone it yet
self.assertRaises(InvalidParameter, inst.vm_clone, name)
with RollbackContext() as rollback:
inst.vm_poweroff(name)
rollback.prependDefer(inst.vm_start, name)
# create two simultaneous clones of the same VM
# and make sure both of them complete successfully
task1 = inst.vm_clone(name)
task2 = inst.vm_clone(name)
clone1_name = task1['target_uri'].split('/')[-2]
rollback.prependDefer(inst.vm_delete, clone1_name)
clone2_name = task2['target_uri'].split('/')[-2]
rollback.prependDefer(inst.vm_delete, clone2_name)
inst.task_wait(task1['id'])
task1 = inst.task_lookup(task1['id'])
self.assertEqual('finished', task1['status'])
inst.task_wait(task2['id'])
task2 = inst.task_lookup(task2['id'])
self.assertEqual('finished', task2['status'])
# update the original VM info because its state has changed
original_vm = inst.vm_lookup(name)
clone_vm = inst.vm_lookup(clone1_name)
self.assertNotEqual(original_vm['name'], clone_vm['name'])
self.assertTrue(
re.match(u'%s-clone-\\d+' %
original_vm['name'], clone_vm['name'])
)
del original_vm['name']
del clone_vm['name']
self.assertNotEqual(original_vm['uuid'], clone_vm['uuid'])
del original_vm['uuid']
del clone_vm['uuid']
# compare all VM settings except the ones already compared
# (and removed) above (i.e. 'name' and 'uuid')
self.assertEqual(original_vm, clone_vm)
def test_use_test_host(self):
inst = model.Model('test:///default', objstore_loc=self.tmp_store)
with RollbackContext() as rollback:
params = {
'name': 'test',
'source_media': {'type': 'disk', 'path': UBUNTU_ISO},
'domain': 'test',
'arch': 'i686',
'disks': [],
}
_setDiskPoolDefaultTest()
rollback.prependDefer(_setDiskPoolDefault)
inst.templates_create(params)
rollback.prependDefer(inst.template_delete, 'test')
params = {'name': 'kimchi-vm',
'template': '/plugins/kimchi/templates/test'}
task = inst.vms_create(params)
inst.task_wait(task['id'])
rollback.prependDefer(inst.vm_delete, 'kimchi-vm')
vms = inst.vms_get_list()
self.assertTrue('kimchi-vm' in vms)
def test_get_distros(self):
inst = model.Model('test:///default', objstore_loc=self.tmp_store)
distros = inst.distros_get_list()
for d in distros:
distro = inst.distro_lookup(d)
self.assertIn('name', distro)
self.assertIn('os_distro', distro)
self.assertIn('os_version', distro)
self.assertIn('os_arch', distro)
self.assertIn('path', distro)
@unittest.skipUnless(utils.running_as_root(), 'Must be run as root')
def test_deep_scan(self):
inst = model.Model(None, objstore_loc=self.tmp_store)
with RollbackContext() as rollback:
deep_path = os.path.join(TMP_DIR, 'deep-scan')
subdir_path = os.path.join(deep_path, 'isos')
if not os.path.exists(subdir_path):
os.makedirs(subdir_path)
ubuntu_iso = os.path.join(deep_path, 'ubuntu12.04.iso')
sles_iso = os.path.join(subdir_path, 'sles10.iso')
construct_fake_iso(ubuntu_iso, True, '12.04', 'ubuntu')
construct_fake_iso(sles_iso, True, '10', 'sles')
args = {
'name': 'kimchi-scanning-pool',
'path': deep_path,
'type': 'kimchi-iso',
}
inst.storagepools_create(args)
rollback.prependDefer(shutil.rmtree, deep_path)
rollback.prependDefer(shutil.rmtree, args['path'])
rollback.prependDefer(inst.storagepool_deactivate, args['name'])
time.sleep(1)
volumes = inst.storagevolumes_get_list(args['name'])
self.assertEqual(len(volumes), 2)
def _host_is_power():
return platform.machine().startswith('ppc')
@unittest.skipUnless(_host_is_power(), 'Only required for Power hosts')
def test_pci_hotplug_requires_usb_controller(self):
config.set('authentication', 'method', 'pam')
inst = model.Model(None, objstore_loc=self.tmp_store)
tpl_params = {'name': 'test', 'memory': 1024, 'cdrom': UBUNTU_ISO}
inst.templates_create(tpl_params)
with RollbackContext() as rollback:
vm_params = {'name': 'kimchi-vm1', 'template': '/templates/test'}
task1 = inst.vms_create(vm_params)
inst.task_wait(task1['id'])
rollback.prependDefer(utils.rollback_wrapper,
inst.vm_delete, 'kimchi-vm1')
# Start vm
inst.vm_start('kimchi-vm1')
rollback.prependDefer(
utils.rollback_wrapper, inst.vm_poweroff, 'kimchi-vm1'
)
# check if create VM has USB controller
self.assertTrue(inst.vmhostdevs_have_usb_controller('kimchi-vm1'))
def get_hostdevs_xml(self):
return """\
vm_name/usr/bin/qemu-kvm
"""
def get_hostdev_multifunction_xml(self):
return """\
"""
def get_hostdev_nomultifunction_xml(self):
return """\
"""
def test_vmhostdev_is_hostdev_multifunction(self):
inst = model.Model(None, objstore_loc=self.tmp_store)
hostdev_multi_elem = objectify.fromstring(
self.get_hostdev_multifunction_xml())
self.assertTrue(
inst.vmhostdev_is_hostdev_multifunction(hostdev_multi_elem))
hostdev_nomulti_elem = objectify.fromstring(
self.get_hostdev_nomultifunction_xml()
)
self.assertFalse(
inst.vmhostdev_is_hostdev_multifunction(hostdev_nomulti_elem))
def test_vmhostdev_get_devices_same_addr(self):
inst = model.Model(None, objstore_loc=self.tmp_store)
root = objectify.fromstring(self.get_hostdevs_xml())
hostdevs = root.devices.hostdev
hostdev_multi_elem = objectify.fromstring(
self.get_hostdev_multifunction_xml())
hostdev_same_addr_str = """\
\
\
\
\
"""
same_addr_devices = [
ET.tostring(hostdev_multi_elem, encoding='unicode'),
hostdev_same_addr_str,
]
self.assertEqual(
set(same_addr_devices)
- set(inst.vmhostdev_get_devices_same_addr(hostdevs, hostdev_multi_elem)),
set(),
)
nomatch_elem = objectify.fromstring(
self.get_hostdev_nomultifunction_xml())
self.assertEqual(
inst.vmhostdev_get_devices_same_addr(hostdevs, nomatch_elem),
[ET.tostring(nomatch_elem, encoding='unicode')],
)
@mock.patch('wok.plugins.kimchi.model.vmhostdevs.get_vm_config_flag')
def test_vmhostdev_unplug_multifunction_pci(self, mock_conf_flag):
class FakeDom:
def detachDeviceFlags(self, xml, config_flag):
pass
mock_conf_flag.return_value = ''
inst = model.Model(None, objstore_loc=self.tmp_store)
root = objectify.fromstring(self.get_hostdevs_xml())
hostdevs = root.devices.hostdev
hostdev_multi_elem = objectify.fromstring(
self.get_hostdev_multifunction_xml())
self.assertTrue(
inst.vmhostdev_unplug_multifunction_pci(
FakeDom(), hostdevs, hostdev_multi_elem
)
)
nomatch_elem = objectify.fromstring(
self.get_hostdev_nomultifunction_xml())
self.assertFalse(
inst.vmhostdev_unplug_multifunction_pci(
FakeDom(), hostdevs, nomatch_elem)
)
class BaseModelTests(unittest.TestCase):
class FoosModel(object):
def __init__(self):
self.data = {}
def create(self, params):
self.data.update(params)
def get_list(self):
return list(self.data)
class TestModel(wok.basemodel.BaseModel):
def __init__(self):
foo = BaseModelTests.FoosModel()
super(BaseModelTests.TestModel, self).__init__([foo])
def test_root_model(self):
t = BaseModelTests.TestModel()
t.foos_create({'item1': 10})
self.assertEqual(t.foos_get_list(), ['item1'])
================================================
FILE: tests/test_model_libvirtevents.py
================================================
# -*- coding: utf-8 -*-
#
# Project Kimchi
#
# Copyright IBM Corp, 2016
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
import json
import os
import shutil
import tempfile
import time
import unittest
import iso_gen
import libvirt
from wok.plugins.kimchi.model import model
from wok.rollbackcontext import RollbackContext
import tests.utils as utils
TMP_DIR = '/var/lib/kimchi/tests/'
UBUNTU_ISO = TMP_DIR + 'ubuntu14.04.iso'
TMP_EVENT = None
EVENT_ID = 0
def setUpModule():
global TMP_DIR, TMP_EVENT
if not os.path.exists(TMP_DIR):
os.makedirs(TMP_DIR)
TMP_EVENT = tempfile.mktemp()
iso_gen.construct_fake_iso(UBUNTU_ISO, True, '14.04', 'ubuntu')
def tearDownModule():
global TMP_DIR, TMP_EVENT
if os.path.exists(TMP_EVENT):
os.unlink(TMP_EVENT)
shutil.rmtree(TMP_DIR)
def _get_next_event_id():
global EVENT_ID
EVENT_ID += 1
return EVENT_ID
def _get_event_id():
global EVENT_ID
return EVENT_ID
def _store_event(data):
global TMP_EVENT
with open(TMP_EVENT, 'a') as file:
file.write('%s\n' % data)
def _get_event(id):
global TMP_EVENT
with open(TMP_EVENT, 'r') as file:
for event in [line.rstrip('\n') for line in file.readlines()]:
fields = event.split('|')
if fields[0] == str(id):
return fields[1]
class LibvirtEventsTests(unittest.TestCase):
def setUp(self):
self.tmp_store = tempfile.mktemp()
def tearDown(self):
os.unlink(self.tmp_store)
def domain_event_lifecycle_cb(self, conn, dom, event, detail, *args):
"""
Callback to handle Domain (VMs) events - VM Livecycle.
"""
evStrings = (
'Defined',
'Undefined',
'Started',
'Suspended',
'Resumed',
'Stopped',
'Shutdown',
'PMSuspended',
'Crashed',
)
evDetails = (
('Added', 'Updated'),
('Removed',),
('Booted', 'Migrated', 'Restored', 'Snapshot', 'Wakeup'),
(
'Paused',
'Migrated',
'IOError',
'Watchdog',
'Restored',
'Snapshot',
'API error',
),
('Unpaused', 'Migrated', 'Snapshot'),
(
'Shutdown',
'Destroyed',
'Crashed',
'Migrated',
'Saved',
'Failed',
'Snapshot',
),
('Finished',),
('Memory', 'Disk'),
('Panicked'),
)
data = {
'domain': dom.name(),
'event': evStrings[event],
'event_detail': evDetails[event][detail],
}
_store_event('%s|%s' % (_get_next_event_id(), json.dumps(data)))
@unittest.skipUnless(
utils.running_as_root() and os.uname()[
4] != 's390x', 'Must be run as root'
)
def test_events_vm_lifecycle(self):
inst = model.Model(objstore_loc=self.tmp_store)
self.objstore = inst.objstore
conn = inst.conn.get()
# Create a template and VM to test, and start lifecycle tests
with RollbackContext() as rollback:
# Register the most common Libvirt domain events to be handled.
event_map = [
(libvirt.VIR_DOMAIN_EVENT_ID_LIFECYCLE, self.domain_event_lifecycle_cb)
]
for event, event_cb in event_map:
conn.domainEventRegister(event_cb, None)
rollback.prependDefer(conn.domainEventDeregister, event_cb)
# Create a template
template_params = {
'name': 'ttest',
'source_media': {'type': 'disk', 'path': UBUNTU_ISO},
}
inst.templates_create(template_params)
rollback.prependDefer(inst.template_delete, 'ttest')
# Create a VM (guest)
vm_params = {
'name': 'kimchi-vm1',
'template': '/plugins/kimchi/templates/ttest',
}
task = inst.vms_create(vm_params)
inst.task_wait(task['id'], 10)
task = inst.task_lookup(task['id'])
self.assertEqual('finished', task['status'])
time.sleep(5)
# Check event of domain definition (addition)
res = json.loads(_get_event(str(_get_event_id())))
self.assertEqual('kimchi-vm1', res['domain'])
self.assertEqual('Defined', res['event'])
self.assertEqual('Added', res['event_detail'])
# Start the VM and check the event
inst.vm_start('kimchi-vm1')
time.sleep(5)
res = json.loads(_get_event(str(_get_event_id())))
self.assertEqual('kimchi-vm1', res['domain'])
self.assertEqual('Started', res['event'])
self.assertEqual('Booted', res['event_detail'])
# Suspend the VM and check the event
inst.vm_suspend('kimchi-vm1')
time.sleep(5)
res = json.loads(_get_event(str(_get_event_id())))
self.assertEqual('kimchi-vm1', res['domain'])
self.assertEqual('Suspended', res['event'])
self.assertEqual('Paused', res['event_detail'])
# Resume the VM and check the event
inst.vm_resume('kimchi-vm1')
time.sleep(5)
res = json.loads(_get_event(str(_get_event_id())))
self.assertEqual('kimchi-vm1', res['domain'])
self.assertEqual('Resumed', res['event'])
self.assertEqual('Unpaused', res['event_detail'])
# PowerOff (hard stop) the VM and check the event
inst.vm_poweroff('kimchi-vm1')
time.sleep(5)
res = json.loads(_get_event(str(_get_event_id())))
self.assertEqual('kimchi-vm1', res['domain'])
self.assertEqual('Stopped', res['event'])
self.assertEqual('Destroyed', res['event_detail'])
# Delete the VM and check the event
inst.vm_delete('kimchi-vm1')
time.sleep(5)
res = json.loads(_get_event(str(_get_event_id())))
self.assertEqual('kimchi-vm1', res['domain'])
self.assertEqual('Undefined', res['event'])
self.assertEqual('Removed', res['event_detail'])
================================================
FILE: tests/test_model_network.py
================================================
# -*- coding: utf-8 -*-
#
# Project Kimchi
#
# Copyright IBM Corp, 2015-2017
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
import json
import os
import tempfile
import unittest
import urllib
from functools import partial
import cherrypy
import mock
from wok.plugins.kimchi.model.featuretests import FeatureTests
from wok.rollbackcontext import RollbackContext
from tests.utils import patch_auth
from tests.utils import request
from tests.utils import rollback_wrapper
from tests.utils import run_server
model = None
objectstore_loc = tempfile.mktemp()
test_server = None
@mock.patch('wok.plugins.kimchi.config.get_object_store')
def setUpModule(func):
func.return_value = objectstore_loc
global test_server, model
patch_auth()
test_server = run_server(test_mode=False)
model = cherrypy.tree.apps['/plugins/kimchi'].root.model
def tearDownModule():
test_server.stop()
os.unlink(objectstore_loc)
def _do_network_test(self, model, params):
with RollbackContext() as rollback:
net_name = params['name']
uri = urllib.parse.quote(f'/plugins/kimchi/networks/{net_name}')
# Create a network
req = json.dumps(params)
resp = self.request('/plugins/kimchi/networks', req, 'POST')
rollback.prependDefer(rollback_wrapper, model.network_delete, net_name)
self.assertEqual(201, resp.status)
# Verify the network
resp = self.request(uri)
network = json.loads(resp.read().decode('utf-8'))
self.assertEqual('inactive', network['state'])
self.assertTrue(network['persistent'])
# activate the network
resp = self.request(uri + '/activate', '{}', 'POST')
rollback.prependDefer(
rollback_wrapper, model.network_deactivate, net_name)
self.assertEqual(200, resp.status)
resp = self.request(uri)
network = json.loads(resp.read().decode('utf-8'))
self.assertEqual('active', network['state'])
# Deactivate the network
resp = self.request(uri + '/deactivate', '{}', 'POST')
self.assertEqual(200, resp.status)
resp = self.request(uri)
network = json.loads(resp.read().decode('utf-8'))
self.assertEqual('inactive', network['state'])
# Define network update parameters
updateParams = {'name': net_name + 'renamed'}
connection = params.get('connection')
if connection in ['isolated', 'nat'] and 'subnet' in params:
updateParams['subnet'] = '127.0.200.0/24'
elif connection == 'bridge' and 'vlan_id' in params:
updateParams['vlan_id'] = 389
# Test network update
req = json.dumps(updateParams)
resp = self.request(uri, req, 'PUT')
self.assertEqual(303, resp.status)
# Assert old name does not exist anymore
resp = self.request(uri, '{}', 'GET')
self.assertEqual(404, resp.status)
# Delete the network
resp = self.request(uri + 'renamed', '{}', 'DELETE')
self.assertEqual(204, resp.status)
class NetworkTests(unittest.TestCase):
def setUp(self):
self.request = partial(request)
def test_get_networks(self):
networks = json.loads(
self.request('/plugins/kimchi/networks').read().decode('utf-8')
)
self.assertIn('default', [net['name'] for net in networks])
with RollbackContext() as rollback:
# Now add a couple of Networks to the mock model
for i in range(5):
name = 'network-%i' % i
req = json.dumps(
{'name': name, 'connection': 'nat',
'subnet': '127.0.10%i.0/24' % i}
)
resp = self.request('/plugins/kimchi/networks', req, 'POST')
rollback.prependDefer(model.network_delete, name)
self.assertEqual(201, resp.status)
network = json.loads(resp.read().decode('utf-8'))
self.assertEqual([], network['vms'])
nets = json.loads(
self.request('/plugins/kimchi/networks').read().decode('utf-8')
)
self.assertEqual(len(networks) + 5, len(nets))
network = json.loads(
self.request('/plugins/kimchi/networks/network-1')
.read()
.decode('utf-8')
)
keys = [
'name',
'connection',
'interfaces',
'subnet',
'dhcp',
'vms',
'in_use',
'autostart',
'state',
'persistent',
]
self.assertEqual(sorted(keys), sorted(network.keys()))
def test_network_lifecycle(self):
# Verify all the supported network type
networks = [
{'name': 'kīмсhī-пet', 'connection': 'isolated'},
{'name': '&', 'connection': 'nat'},
{'name': 'subnet-network', 'connection': 'nat',
'subnet': '127.0.100.0/24'},
]
# Verify the current system has at least one interface to create a
# bridged network
interfaces = json.loads(
self.request('/plugins/kimchi/interfaces?_inuse=false&type=nic')
.read()
.decode('utf-8')
)
if len(interfaces) > 0:
iface = interfaces[0]['name']
networks.append(
{
'name': 'macvtap-network',
'connection': 'macvtap',
'interfaces': [iface],
}
)
if not FeatureTests.is_nm_running():
networks.append(
{
'name': 'bridge-network',
'connection': 'bridge',
'interfaces': [iface],
}
)
for net in networks:
_do_network_test(self, model, net)
def test_macvtap_network_create_fails_more_than_one_interface(self):
network = {
'name': 'macvtap-network',
'connection': 'macvtap',
'interfaces': ['fake_iface1', 'fake_iface2', 'fake_iface3'],
}
expected_error_msg = 'KCHNET0030E'
req = json.dumps(network)
resp = self.request('/plugins/kimchi/networks', req, 'POST')
self.assertEqual(400, resp.status)
self.assertIn(expected_error_msg, resp.read().decode('utf-8'))
def test_bridge_network_create_fails_more_than_one_interface(self):
network = {
'name': 'bridge-network',
'connection': 'bridge',
'interfaces': ['fake_iface1', 'fake_iface2', 'fake_iface3'],
}
expected_error_msg = 'KCHNET0030E'
req = json.dumps(network)
resp = self.request('/plugins/kimchi/networks', req, 'POST')
self.assertEqual(400, resp.status)
self.assertIn(expected_error_msg, resp.read().decode('utf-8'))
================================================
FILE: tests/test_model_storagepool.py
================================================
# -*- coding: utf-8 -*-
#
# Project Kimchi
#
# Copyright IBM Corp, 2015-2017
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
import json
import os
import shutil
import tempfile
import unittest
import urllib
from functools import partial
import cherrypy
import mock
from wok.rollbackcontext import RollbackContext
from tests.utils import patch_auth
from tests.utils import request
from tests.utils import run_server
model = None
objectstore_loc = tempfile.mktemp()
test_server = None
@mock.patch('wok.plugins.kimchi.config.get_object_store')
def setUpModule(func):
func.return_value = objectstore_loc
global test_server, model
patch_auth()
test_server = run_server(test_mode=False)
model = cherrypy.tree.apps['/plugins/kimchi'].root.model
def tearDownModule():
test_server.stop()
os.unlink(objectstore_loc)
class StoragepoolTests(unittest.TestCase):
def setUp(self):
self.request = partial(request)
def test_get_storagepools(self):
storagepools = json.loads(self.request(
'/plugins/kimchi/storagepools').read())
self.assertIn('default', [pool['name'] for pool in storagepools])
with RollbackContext() as rollback:
# Now add a couple of storage pools
for i in range(3):
name = f'kīмсhī-storagepool-{i}'
path = f'/var/lib/libvirt/images/{i}'
req = json.dumps({'name': name, 'type': 'dir', 'path': path})
resp = self.request(
'/plugins/kimchi/storagepools', req, 'POST')
rollback.prependDefer(model.storagepool_delete, name)
rollback.prependDefer(shutil.rmtree, path)
self.assertEqual(201, resp.status)
# Pool name must be unique
req = json.dumps(
{
'name': name,
'type': 'dir',
'path': f'/var/lib/libvirt/images/{i}',
}
)
resp = self.request(
'/plugins/kimchi/storagepools', req, 'POST')
self.assertEqual(400, resp.status)
# Verify pool information
quote_uri = urllib.parse.quote(
f'/plugins/kimchi/storagepools/{name}')
resp = self.request(quote_uri)
p = json.loads(resp.read())
keys = [
'name',
'state',
'capacity',
'allocated',
'available',
'path',
'source',
'type',
'nr_volumes',
'autostart',
'persistent',
'in_use',
]
self.assertEqual(sorted(keys), sorted(p.keys()))
self.assertEqual(name, p['name'])
self.assertEqual('inactive', p['state'])
self.assertEqual(True, p['persistent'])
self.assertEqual(True, p['autostart'])
self.assertEqual(0, p['nr_volumes'])
pools = json.loads(self.request(
'/plugins/kimchi/storagepools').read())
self.assertEqual(len(storagepools) + 3, len(pools))
# Create a pool with an existing path
tmp_path = tempfile.mkdtemp(dir='/var/lib/kimchi')
rollback.prependDefer(os.rmdir, tmp_path)
req = json.dumps(
{'name': 'existing_path', 'type': 'dir', 'path': tmp_path})
resp = self.request('/plugins/kimchi/storagepools', req, 'POST')
rollback.prependDefer(model.storagepool_delete, 'existing_path')
self.assertEqual(201, resp.status)
# Reserved pool return 400
req = json.dumps(
{
'name': 'kimchi_isos',
'type': 'dir',
'path': '/var/lib/libvirt/images/%i' % i,
}
)
resp = request('/plugins/kimchi/storagepools', req, 'POST')
self.assertEqual(400, resp.status)
================================================
FILE: tests/test_model_storagevolume.py
================================================
# -*- coding: utf-8 -*-
#
# Project Kimchi
#
# Copyright IBM Corp, 2015-2017
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
import json
import os
import tempfile
import unittest
import urllib
from functools import partial
import cherrypy
import mock
import requests
from requests.exceptions import ConnectionError
from wok.config import paths
from wok.plugins.kimchi.config import READONLY_POOL_TYPE
from wok.rollbackcontext import RollbackContext
from tests.utils import fake_auth_header
from tests.utils import HOST
from tests.utils import patch_auth
from tests.utils import PORT
from tests.utils import request
from tests.utils import rollback_wrapper
from tests.utils import run_server
from tests.utils import wait_task
model = None
objectstore_loc = tempfile.mktemp()
test_server = None
@mock.patch('wok.plugins.kimchi.config.get_object_store')
def setUpModule(func):
func.return_value = objectstore_loc
global test_server, model
patch_auth()
test_server = run_server(test_mode=False)
model = cherrypy.tree.apps['/plugins/kimchi'].root.model
def tearDownModule():
test_server.stop()
os.unlink(objectstore_loc)
def _do_volume_test(self, model, pool_name):
def _task_lookup(taskid):
return json.loads(
self.request(
f'/plugins/kimchi/tasks/{taskid}').read().decode('utf-8')
)
uri = urllib.parse.quote(
f'/plugins/kimchi/storagepools/{pool_name}/storagevolumes')
resp = self.request(uri)
self.assertEqual(200, resp.status)
resp = self.request(urllib.parse.quote(
f'/plugins/kimchi/storagepools/{pool_name}'))
pool_info = json.loads(resp.read().decode('utf-8'))
with RollbackContext() as rollback:
# Create storage volume with 'capacity'
vol = 'test-volume'
vol_uri = uri + '/' + vol
req = json.dumps(
{'name': vol, 'format': 'raw', 'capacity': 1073741824}
) # 1 GiB
resp = self.request(uri, req, 'POST')
if pool_info['type'] in READONLY_POOL_TYPE:
self.assertEqual(400, resp.status)
else:
rollback.prependDefer(
rollback_wrapper, model.storagevolume_delete, pool_name, vol
)
self.assertEqual(202, resp.status)
task_id = json.loads(resp.read().decode('utf-8'))['id']
wait_task(_task_lookup, task_id)
status = json.loads(
self.request(
f'/plugins/kimchi/tasks/{task_id}').read().decode('utf-8')
)
self.assertEqual('finished', status['status'])
vol_info = json.loads(self.request(vol_uri).read().decode('utf-8'))
vol_info['name'] = vol
vol_info['format'] = 'raw'
vol_info['capacity'] = 1073741824
# Resize the storage volume: increase its capacity to 2 GiB
req = json.dumps({'size': 2147483648}) # 2 GiB
resp = self.request(vol_uri + '/resize', req, 'POST')
self.assertEqual(200, resp.status)
storagevolume = json.loads(
self.request(vol_uri).read().decode('utf-8'))
self.assertEqual(2147483648, storagevolume['capacity'])
# Resize the storage volume: decrease its capacity to 512 MiB
# This test case may fail if libvirt does not include the fix for
# https://bugzilla.redhat.com/show_bug.cgi?id=1021802
req = json.dumps({'size': 536870912}) # 512 MiB
resp = self.request(vol_uri + '/resize', req, 'POST')
self.assertEqual(200, resp.status)
storagevolume = json.loads(
self.request(vol_uri).read().decode('utf-8'))
self.assertEqual(536870912, storagevolume['capacity'])
# Wipe the storage volume
resp = self.request(vol_uri + '/wipe', '{}', 'POST')
self.assertEqual(200, resp.status)
storagevolume = json.loads(
self.request(vol_uri).read().decode('utf-8'))
self.assertEqual(0, storagevolume['allocation'])
# Clone the storage volume
vol_info = json.loads(self.request(vol_uri).read().decode('utf-8'))
resp = self.request(vol_uri + '/clone', '{}', 'POST')
self.assertEqual(202, resp.status)
task = json.loads(resp.read())
cloned_vol_name = task['target_uri'].split('/')[-2]
rollback.prependDefer(
model.storagevolume_delete, pool_name, cloned_vol_name
)
wait_task(_task_lookup, task['id'])
task = json.loads(
self.request('/plugins/kimchi/tasks/%s' % task['id'])
.read()
.decode('utf-8')
)
self.assertEqual('finished', task['status'])
resp = self.request(uri + '/' + cloned_vol_name)
self.assertEqual(200, resp.status)
cloned_vol = json.loads(resp.read().decode('utf-8'))
self.assertNotEquals(vol_info['name'], cloned_vol['name'])
self.assertNotEquals(vol_info['path'], cloned_vol['path'])
for key in ['name', 'path', 'allocation']:
del vol_info[key]
del cloned_vol[key]
self.assertEqual(vol_info, cloned_vol)
# Delete the storage volume
resp = self.request(vol_uri, '{}', 'DELETE')
self.assertEqual(204, resp.status)
resp = self.request(vol_uri)
self.assertEqual(404, resp.status)
# Storage volume upload
# It is done through a sequence of POST and several PUT requests
filename = 'COPYING.LGPL'
filepath = os.path.join(paths.get_prefix(), filename)
filesize = os.stat(filepath).st_size
# Create storage volume for upload
req = json.dumps(
{'name': filename, 'format': 'raw',
'capacity': filesize, 'upload': True}
)
resp = self.request(uri, req, 'POST')
if pool_info['type'] in READONLY_POOL_TYPE:
self.assertEqual(400, resp.status)
else:
rollback.prependDefer(
rollback_wrapper, model.storagevolume_delete, pool_name, filename
)
self.assertEqual(202, resp.status)
task = json.loads(resp.read().decode('utf-8'))
task_id = task['id']
wait_task(_task_lookup, task_id)
status = json.loads(
self.request('/plugins/kimchi/tasks/%s' % task_id)
.read()
.decode('utf-8')
)
self.assertEqual('ready for upload', status['message'])
# Upload volume content
url = 'http://%s:%s' % (HOST, PORT) + uri + '/' + filename
# Create a file with 5M to upload
# Max body size is set to 4M so the upload should fail with 413.
# Since nginx is not being used for testing anymore, and cherrypy
# aborts connection instead of returning a 413 like nginx does,
# test case expects for exception raised by cherrypy.
newfile = '/tmp/5m-file'
with open(newfile, 'wb') as fd:
fd.seek(5 * 1024 * 1024 - 1)
fd.write(b'\0')
rollback.prependDefer(os.remove, newfile)
with open(newfile, 'rb') as fd:
with open(newfile + '.tmp', 'wb') as tmp_fd:
data = fd.read()
tmp_fd.write(data)
with open(newfile + '.tmp', 'rb') as tmp_fd:
error_msg = 'Connection aborted'
with self.assertRaisesRegexp(ConnectionError, error_msg):
requests.put(
url,
data={'chunk_size': len(data)},
files={'chunk': tmp_fd},
verify=False,
headers=fake_auth_header(),
)
# Do upload
index = 0
chunk_size = 2 * 1024
content = ''
with open(filepath, 'rb') as fd:
while True:
with open(filepath + '.tmp', 'wb') as tmp_fd:
fd.seek(index * chunk_size)
data = fd.read(chunk_size)
tmp_fd.write(data)
with open(filepath + '.tmp', 'rb') as tmp_fd:
r = requests.put(
url,
data={'chunk_size': len(data)},
files={'chunk': tmp_fd},
verify=False,
headers=fake_auth_header(),
)
self.assertEqual(r.status_code, 200)
content += data.decode('utf-8')
index = index + 1
if len(data) < chunk_size:
break
rollback.prependDefer(os.remove, filepath + '.tmp')
resp = self.request(uri + '/' + filename)
self.assertEqual(200, resp.status)
uploaded_path = json.loads(resp.read().decode('utf-8'))['path']
with open(uploaded_path) as fd:
uploaded_content = fd.read()
self.assertEqual(content, uploaded_content)
# Create storage volume with 'url'
url = 'https://github.com/kimchi-project/kimchi/raw/master/COPYING'
req = json.dumps({'url': url})
resp = self.request(uri, req, 'POST')
if pool_info['type'] in READONLY_POOL_TYPE:
self.assertEqual(400, resp.status)
else:
rollback.prependDefer(
model.storagevolume_delete, pool_name, 'COPYING')
self.assertEqual(202, resp.status)
task = json.loads(resp.read().decode('utf-8'))
wait_task(_task_lookup, task['id'])
resp = self.request(uri + '/COPYING')
self.assertEqual(200, resp.status)
class StorageVolumeTests(unittest.TestCase):
def setUp(self):
self.request = partial(request)
def test_get_storagevolume(self):
uri = '/plugins/kimchi/storagepools/default/storagevolumes'
resp = self.request(uri)
self.assertEqual(200, resp.status)
keys = [
'name',
'type',
'capacity',
'allocation',
'path',
'used_by',
'format',
'isvalid',
'has_permission',
]
for vol in json.loads(resp.read().decode('utf-8')):
resp = self.request(uri + '/' + vol['name'])
self.assertEqual(200, resp.status)
all_keys = keys[:]
vol_info = json.loads(resp.read().decode('utf-8'))
if vol_info['format'] == 'iso':
all_keys.extend(['os_distro', 'os_version', 'bootable'])
self.assertEqual(sorted(all_keys), sorted(vol_info.keys()))
def test_storagevolume_action(self):
_do_volume_test(self, model, 'default')
================================================
FILE: tests/test_networkxml.py
================================================
#
# Kimchi
#
# Copyright IBM Corp, 2013-2016
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
import ipaddress
import unittest
import lxml.etree as ET
from wok.plugins.kimchi.xmlutils import network as nxml
from wok.xmlutils.utils import xpath_get_text
def normalize_xml(xml_str):
node = ET.fromstring(xml_str, ET.XMLParser(remove_blank_text=True))
return ET.tostring(node, encoding='unicode')
class NetworkXmlTests(unittest.TestCase):
def test_dhcp_xml(self):
"""
Test network dhcp xml
"""
dhcp_range = {'start': '192.168.122.100', 'end': '192.168.122.254'}
host1 = {
'mac': '00:16:3e:77:e2:ed',
'name': 'foo.example.com',
'ip': '192.168.122.10',
}
host2 = {
'mac': '00:16:3e:3e:a9:1a',
'name': 'bar.example.com',
'ip': '192.168.122.11',
}
params = {}
dhcp = nxml._get_dhcp_elem(**params)
self.assertEqual(None, dhcp)
params['range'] = dhcp_range
xml = ET.tostring(nxml._get_dhcp_elem(**params), encoding='unicode')
start = xpath_get_text(xml, '/dhcp/range/@start')
end = xpath_get_text(xml, '/dhcp/range/@end')
self.assertEqual(dhcp_range['start'], start[0])
self.assertEqual(dhcp_range['end'], end[0])
params['hosts'] = [host1, host2]
xml = ET.tostring(nxml._get_dhcp_elem(**params), encoding='unicode')
ip = xpath_get_text(xml, '/dhcp/host/@ip')
self.assertEqual(ip, [host1['ip'], host2['ip']])
def test_ip_xml(self):
"""
Test network ip xml
"""
dhcp_range = {'start': '192.168.122.100', 'end': '192.168.122.254'}
params = {}
dhcp = nxml._get_dhcp_elem(**params)
self.assertEqual(None, dhcp)
params['net'] = '192.168.122.0/255.255.255.0'
params['dhcp'] = {'range': dhcp_range}
xml = ET.tostring(nxml._get_ip_elem(**params), encoding='unicode')
start = xpath_get_text(xml, '/ip/dhcp/range/@start')[0]
end = xpath_get_text(xml, '/ip/dhcp/range/@end')[0]
self.assertEqual(dhcp_range['start'], start)
self.assertEqual(dhcp_range['end'], end)
address = xpath_get_text(xml, '/ip/@address')[0]
netmask = xpath_get_text(xml, '/ip/@netmask')[0]
self.assertEqual(address, params['net'].split('/')[0])
self.assertEqual(netmask, params['net'].split('/')[1])
# test _get_ip_xml can accepts strings: '192.168.122.0/24',
# which is same as "192.168.122.0/255.255.255.0"
params['net'] = '192.168.122.0/24'
xml = ET.tostring(nxml._get_ip_elem(**params), encoding='unicode')
netmask = xpath_get_text(xml, '/ip/@netmask')[0]
self.assertEqual(netmask, str(
ipaddress.IPv4Network(params['net'], False).netmask))
def test_forward_xml(self):
"""
Test network forward xml
"""
params = {'mode': None}
forward = nxml._get_forward_elem(**params)
self.assertEqual(None, forward)
params['mode'] = 'nat'
params['dev'] = 'eth0'
xml = ET.tostring(nxml._get_forward_elem(**params), encoding='unicode')
mode = xpath_get_text(xml, '/forward/@mode')[0]
dev = xpath_get_text(xml, '/forward/@dev')[0]
self.assertEqual(params['mode'], mode)
self.assertEqual(params['dev'], dev)
def test_network_xml(self):
"""
Test network xml
"""
params = {
'name': 'test',
'forward': {'mode': 'nat', 'dev': ''},
'net': '192.168.0.0/255.255.255.0',
}
xml = nxml.to_network_xml(**params)
name = xpath_get_text(xml, '/network/name')[0]
self.assertEqual(name, params['name'])
forward_mode = xpath_get_text(xml, '/network/forward/@mode')[0]
self.assertEqual(forward_mode, params['forward']['mode'])
forward_dev = xpath_get_text(xml, '/network/forward/@dev')[0]
self.assertEqual(forward_dev, '')
address = xpath_get_text(xml, '/network/ip/@address')[0]
self.assertEqual(address, params['net'].split('/')[0])
netmask = xpath_get_text(xml, '/network/ip/@netmask')[0]
self.assertEqual(netmask, params['net'].split('/')[1])
dhcp_start = xpath_get_text(xml, '/network/ip/dhcp/range/@start')
self.assertEqual(dhcp_start, [])
dhcp_end = xpath_get_text(xml, '/network/ip/dhcp/range/@end')
self.assertEqual(dhcp_end, [])
# test optional params
params['forward']['dev'] = 'eth0'
params['dhcp'] = {
'range': {'start': '192.168.0.1', 'end': '192.168.0.254'}}
xml = nxml.to_network_xml(**params)
forward_dev = xpath_get_text(xml, '/network/forward/@dev')[0]
self.assertEqual(forward_dev, params['forward']['dev'])
dhcp_start = xpath_get_text(xml, '/network/ip/dhcp/range/@start')[0]
self.assertEqual(dhcp_start, params['dhcp']['range']['start'])
dhcp_end = xpath_get_text(xml, '/network/ip/dhcp/range/@end')[0]
self.assertEqual(dhcp_end, params['dhcp']['range']['end'])
# test _get_ip_xml can accepts strings: '192.168.122.0/24',
# which is same as "192.168.122.0/255.255.255.0"
params['net'] = '192.168.0.0/24'
xml = nxml.to_network_xml(**params)
netmask = xpath_get_text(xml, '/network/ip/@netmask')[0]
self.assertEqual(netmask, str(
ipaddress.IPv4Network(params['net'], False).netmask))
def test_vepa_network_singledev_xml(self):
expected_xml = """\
test_vepa\
\
\
\
"""
params = {
'name': 'test_vepa',
'forward': {'mode': 'vepa', 'devs': ['vepa_switch_interface']},
}
xml_str = nxml.to_network_xml(**params)
self.assertEqual(xml_str, expected_xml)
def test_vepa_network_multipledevs_xml(self):
expected_xml = """\
test_vepa\
\
\
\
\
\
"""
params = {
'name': 'test_vepa',
'forward': {
'mode': 'vepa',
'devs': [
'vepa_switch_interface1',
'vepa_switch_interface2',
'vepa_switch_interface3',
],
},
}
xml_str = nxml.to_network_xml(**params)
self.assertEqual(xml_str, expected_xml)
def test_passthrough_network_singledev_xml(self):
expected_xml = """\
test_passthrough\
\
\
\
"""
params = {
'name': 'test_passthrough',
'forward': {'mode': 'passthrough', 'devs': ['passthrough_interface']},
}
xml_str = nxml.to_network_xml(**params)
self.assertEqual(xml_str, expected_xml)
def test_passthrough_network_multipledevs_xml(self):
expected_xml = """\
test_passthrough\
\
\
\
\
\
"""
params = {
'name': 'test_passthrough',
'forward': {
'mode': 'passthrough',
'devs': [
'passthrough_interface1',
'passthrough_interface2',
'passthrough_interface3',
],
},
}
xml_str = nxml.to_network_xml(**params)
self.assertEqual(xml_str, expected_xml)
class InterfaceXmlTests(unittest.TestCase):
def test_vlan_tagged_bridge_no_ip(self):
expected_xml = """
"""
actual_xml = nxml.create_vlan_tagged_bridge_xml('br10', 'em1', '10')
self.assertEqual(actual_xml, normalize_xml(expected_xml))
def test_linux_bridge_no_ip(self):
em1_xml = """
"""
expected_xml = """
"""
actual_xml = nxml.create_linux_bridge_xml(
'br10', 'em1', normalize_xml(em1_xml))
self.assertEqual(actual_xml, normalize_xml(expected_xml))
================================================
FILE: tests/test_osinfo.py
================================================
#
# Project Kimchi
#
# Copyright IBM Corp, 2013-2016
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
import os
import unittest
from wok.plugins.kimchi.osinfo import _get_arch
from wok.plugins.kimchi.osinfo import get_template_default
from wok.plugins.kimchi.osinfo import lookup
from wok.plugins.kimchi.osinfo import modern_version_bases
class OSInfoTests(unittest.TestCase):
def test_default_lookup(self):
entry = lookup(None, None)
self.assertEqual('unknown', entry['os_distro'])
self.assertEqual('unknown', entry['os_version'])
if not os.uname()[4] == 's390x':
self.assertEqual(['default'], entry['networks'])
def test_old_distros(self):
old_versions = {
'debian': '5.0',
'ubuntu': '7.04',
'opensuse': '10.1',
'centos': '5.1',
'rhel': '5.1',
'fedora': '15',
}
for distro, version in old_versions.items():
entry = lookup(distro, version)
self.assertEqual(entry['disk_bus'],
get_template_default('old', 'disk_bus'))
self.assertEqual(
entry['nic_model'], get_template_default('old', 'nic_model')
)
def test_modern_bases(self):
if not os.uname()[4] == 's390x':
for distro, version in modern_version_bases[_get_arch()].items():
entry = lookup(distro, version)
self.assertEqual(
entry['disk_bus'], get_template_default(
'modern', 'disk_bus')
)
self.assertEqual(
entry['nic_model'], get_template_default(
'modern', 'nic_model')
)
def test_modern_distros(self):
# versions based on ppc64 modern distros
modern_versions = {
'ubuntu': '14.04',
'opensuse': '13.1',
'rhel': '6.5',
'fedora': '19',
'sles': '11sp3',
}
for distro, version in modern_versions.items():
entry = lookup(distro, version)
self.assertEqual(
entry['disk_bus'], get_template_default('modern', 'disk_bus')
)
self.assertEqual(
entry['nic_model'], get_template_default('modern', 'nic_model')
)
def test_lookup_unknown_distro_version_returns_old_distro(self):
distro = 'unknown_distro'
version = 'unknown_version'
entry = lookup(distro, version)
self.assertEqual(entry['disk_bus'],
get_template_default('old', 'disk_bus'))
self.assertEqual(entry['nic_model'],
get_template_default('old', 'nic_model'))
================================================
FILE: tests/test_rest.py
================================================
# -*- coding: utf-8 -*-
#
# Project Kimchi
#
# Copyright IBM Corp, 2013-2017
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
import json
import os
import re
import time
import unittest
import urllib
from functools import partial
import cherrypy
import iso_gen
from wok.asynctask import AsyncTask
from wok.plugins.kimchi.osinfo import get_template_default
from wok.rollbackcontext import RollbackContext
from tests.utils import patch_auth
from tests.utils import request
from tests.utils import run_server
from tests.utils import wait_task
test_server = None
model = None
fake_iso = '/tmp/fake.iso'
DISKS = [
{
'size': 10,
'format': 'qcow2',
'index': 0,
'pool': {'name': '/plugins/kimchi/storagepools/default-pool'},
}
]
def setUpModule():
global test_server, model
patch_auth()
test_server = run_server(test_mode=True)
model = cherrypy.tree.apps['/plugins/kimchi'].root.model
# Create fake ISO to do the tests
iso_gen.construct_fake_iso(fake_iso, True, '12.04', 'ubuntu')
iso_gen.construct_fake_iso(
'/var/lib/libvirt/images/fedora.iso', True, '17', 'fedora'
)
def tearDownModule():
test_server.stop()
os.unlink(fake_iso)
os.unlink('/var/lib/libvirt/images/fedora.iso')
class RestTests(unittest.TestCase):
def _async_op(self, cb, opaque):
time.sleep(1)
cb('success', True)
def _except_op(self, cb, opaque):
time.sleep(1)
raise Exception(
'Oops, this is an exception handle test.' ' You can ignore it safely'
)
cb('success', True)
def _intermid_op(self, cb, opaque):
time.sleep(1)
cb('in progress')
def setUp(self):
self.request = partial(request)
model.reset()
def assertHTTPStatus(self, code, *args):
resp = self.request(*args)
self.assertEqual(code, resp.status)
def test_get_vms(self):
vms = json.loads(self.request('/plugins/kimchi/vms').read())
# test_rest.py uses MockModel() which connects to libvirt URI
# test:///default. By default this driver already has one VM created
self.assertEqual(1, len(vms))
# Create a template as a base for our VMs
req = json.dumps(
{'name': 'test', 'source_media': {'type': 'disk', 'path': fake_iso}}
)
resp = self.request('/plugins/kimchi/templates', req, 'POST')
self.assertEqual(201, resp.status)
test_users = ['root']
test_groups = ['wheel']
# Now add a couple of VMs to the mock model
for i in range(10):
name = 'vm-%i' % i
req = json.dumps(
{
'name': name,
'template': '/plugins/kimchi/templates/test',
'users': test_users,
'groups': test_groups,
}
)
resp = self.request('/plugins/kimchi/vms', req, 'POST')
self.assertEqual(202, resp.status)
task = json.loads(resp.read())
wait_task(self._task_lookup, task['id'])
vms = json.loads(self.request('/plugins/kimchi/vms').read())
self.assertEqual(11, len(vms))
vm = json.loads(self.request('/plugins/kimchi/vms/vm-1').read())
self.assertEqual('vm-1', vm['name'])
self.assertEqual('shutoff', vm['state'])
self.assertEqual([], vm['users'])
self.assertEqual([], vm['groups'])
def test_edit_vm_cpuhotplug(self):
req = json.dumps(
{
'name': 'template_cpuhotplug',
'source_media': {'type': 'disk', 'path': fake_iso},
}
)
resp = self.request('/plugins/kimchi/templates', req, 'POST')
self.assertEqual(201, resp.status)
req = json.dumps(
{
'name': 'vm-cpuhotplug',
'template': '/plugins/kimchi/templates/template_cpuhotplug',
}
)
resp = self.request('/plugins/kimchi/vms', req, 'POST')
self.assertEqual(202, resp.status)
task = json.loads(resp.read())
wait_task(self._task_lookup, task['id'])
req = json.dumps({'cpu_info': {'maxvcpus': 5, 'vcpus': 1}})
resp = self.request('/plugins/kimchi/vms/vm-cpuhotplug', req, 'PUT')
self.assertEqual(200, resp.status)
resp = self.request(
'/plugins/kimchi/vms/vm-cpuhotplug/start', '{}', 'POST')
self.assertEqual(200, resp.status)
req = json.dumps({'cpu_info': {'vcpus': 5}})
resp = self.request('/plugins/kimchi/vms/vm-cpuhotplug', req, 'PUT')
self.assertEqual(200, resp.status)
def test_edit_vm(self):
req = json.dumps(
{'name': 'test', 'source_media': {'type': 'disk', 'path': fake_iso}}
)
resp = self.request('/plugins/kimchi/templates', req, 'POST')
self.assertEqual(201, resp.status)
req = json.dumps(
{'name': 'vm-1', 'template': '/plugins/kimchi/templates/test'})
resp = self.request('/plugins/kimchi/vms', req, 'POST')
self.assertEqual(202, resp.status)
task = json.loads(resp.read())
wait_task(self._task_lookup, task['id'])
vm = json.loads(self.request('/plugins/kimchi/vms/vm-1').read())
self.assertEqual('vm-1', vm['name'])
req = json.dumps({'cpu_info': {'maxvcpus': 5, 'vcpus': 3}})
resp = self.request('/plugins/kimchi/vms/vm-1', req, 'PUT')
self.assertEqual(200, resp.status)
# Test max memory
req = json.dumps({'memory': {'maxmemory': 23}})
resp = self.request('/plugins/kimchi/vms/vm-1', req, 'PUT')
self.assertEqual(400, resp.status)
req = json.dumps({'memory': {'maxmemory': 'maxmem 80'}})
resp = self.request('/plugins/kimchi/vms/vm-1', req, 'PUT')
self.assertEqual(400, resp.status)
# Check if there is support to memory hotplug
resp = self.request('/plugins/kimchi/config/capabilities').read()
conf = json.loads(resp)
if os.uname()[4] != 's390x' and conf['mem_hotplug_support']:
req = json.dumps({'memory': {'maxmemory': 3072}})
resp = self.request('/plugins/kimchi/vms/vm-1', req, 'PUT')
self.assertEqual(200, resp.status)
resp = self.request('/plugins/kimchi/vms/vm-1/start', '{}', 'POST')
self.assertEqual(200, resp.status)
req = json.dumps({'unsupported-attr': 'attr'})
resp = self.request('/plugins/kimchi/vms/vm-1', req, 'PUT')
self.assertEqual(400, resp.status)
req = json.dumps({'name': 'new-vm'})
resp = self.request('/plugins/kimchi/vms/vm-1', req, 'PUT')
self.assertEqual(400, resp.status)
# Test memory hotplug
req = json.dumps({'memory': {'current': 2048}})
resp = self.request('/plugins/kimchi/vms/vm-1', req, 'PUT')
if conf['mem_hotplug_support']:
self.assertEqual(200, resp.status)
else:
self.assertEqual(400, resp.status)
req = json.dumps({'graphics': {'passwd': 'abcdef'}})
resp = self.request('/plugins/kimchi/vms/vm-1', req, 'PUT')
self.assertEqual(200, resp.status)
info = json.loads(resp.read())
self.assertEqual('abcdef', info['graphics']['passwd'])
self.assertEqual(None, info['graphics']['passwdValidTo'])
resp = self.request('/plugins/kimchi/vms/vm-1/poweroff', '{}', 'POST')
self.assertEqual(200, resp.status)
req = json.dumps(
{'graphics': {'passwd': '123456', 'passwdValidTo': 20}})
resp = self.request('/plugins/kimchi/vms/vm-1', req, 'PUT')
info = json.loads(resp.read())
self.assertEqual('123456', info['graphics']['passwd'])
self.assertGreaterEqual(20, info['graphics']['passwdValidTo'])
req = json.dumps({'name': 12})
resp = self.request('/plugins/kimchi/vms/vm-1', req, 'PUT')
self.assertEqual(400, resp.status)
req = json.dumps({'name': ''})
resp = self.request('/plugins/kimchi/vms/vm-1', req, 'PUT')
self.assertEqual(400, resp.status)
req = json.dumps({'cpu_info': {'vcpus': -2}})
resp = self.request('/plugins/kimchi/vms/vm-1', req, 'PUT')
self.assertEqual(400, resp.status)
req = json.dumps({'cpu_info': {'vcpus': 'four'}})
resp = self.request('/plugins/kimchi/vms/vm-1', req, 'PUT')
self.assertEqual(400, resp.status)
req = json.dumps({'memory': {'current': 100}})
resp = self.request('/plugins/kimchi/vms/vm-1', req, 'PUT')
self.assertEqual(400, resp.status)
req = json.dumps({'memory': {'current': 'ten gigas'}})
resp = self.request('/plugins/kimchi/vms/vm-1', req, 'PUT')
self.assertEqual(400, resp.status)
req = json.dumps(
{'name': 'new-name', 'cpu_info': {'vcpus': 5}, 'UUID': 'notallowed'}
)
resp = self.request('/plugins/kimchi/vms/vm-1', req, 'PUT')
self.assertEqual(400, resp.status)
vm = json.loads(self.request('/plugins/kimchi/vms/vm-1', req).read())
# The maxmemory will be automatically increased when the amount of
# memory value is greater than the current maxmemory value
params = {
'name': '∨м-црdαtеd',
'cpu_info': {'vcpus': 5},
'memory': {'current': 3072},
}
req = json.dumps(params)
resp = self.request('/plugins/kimchi/vms/vm-1', req, 'PUT')
self.assertEqual(303, resp.status)
quoted_uri = urllib.parse.quote('/plugins/kimchi/vms/∨м-црdαtеd')
vm_updated = json.loads(self.request(quoted_uri, req).read())
# Memory was hot plugged
vm['name'] = '∨м-црdαtеd'
vm['cpu_info'].update(params['cpu_info'])
vm['memory']['current'] = 3072
vm['memory']['maxmemory'] = 3072
for key in params.keys():
self.assertEqual(vm[key], vm_updated[key])
# change only VM users - groups are not changed (default is empty)
resp = self.request('/plugins/kimchi/users', '{}', 'GET')
users = json.loads(resp.read())
req = json.dumps({'users': users})
resp = self.request(quoted_uri, req, 'PUT')
self.assertEqual(200, resp.status)
info = json.loads(self.request(quoted_uri, '{}').read())
self.assertEqual(users, info['users'])
# change only VM groups - users are not changed (default is empty)
resp = self.request('/plugins/kimchi/groups', '{}', 'GET')
groups = json.loads(resp.read())
req = json.dumps({'groups': groups})
resp = self.request(quoted_uri, req, 'PUT')
self.assertEqual(200, resp.status)
info = json.loads(self.request(quoted_uri, '{}').read())
self.assertEqual(groups, info['groups'])
# change VM users (wrong value) and groups
# when an error occurs, everything fails and nothing is changed
req = json.dumps({'users': ['userdoesnotexist'], 'groups': []})
resp = self.request(quoted_uri, req, 'PUT')
self.assertEqual(400, resp.status)
# change VM users and groups (wrong value)
# when an error occurs, everything fails and nothing is changed
req = json.dumps({'users': [], 'groups': ['groupdoesnotexist']})
resp = self.request(quoted_uri, req, 'PUT')
self.assertEqual(400, resp.status)
# change bootorder
b_order = ['hd', 'network', 'cdrom']
req = json.dumps({'bootorder': b_order})
resp = self.request(quoted_uri, req, 'PUT')
self.assertEqual(200, resp.status)
self.assertEqual(json.loads(resp.read())['bootorder'], b_order)
req = json.dumps({'bootorder': ['bla']})
resp = self.request(quoted_uri, req, 'PUT')
self.assertEqual(400, resp.status)
# change vm graphics type
req = json.dumps({'graphics': {'type': 'spice'}})
resp = self.request(quoted_uri, req, 'PUT')
self.assertEqual(json.loads(resp.read())['graphics']['type'], 'spice')
# try to add a invalid type
req = json.dumps({'graphics': {'type': 'test'}})
resp = self.request(quoted_uri, req, 'PUT')
self.assertEqual(400, resp.status)
# set vm autostart tests (powered off)
resp = self.request(f'{quoted_uri}/start', '{}', 'POST')
self.assertEqual(200, resp.status)
req = json.dumps({'autostart': True})
resp = self.request(quoted_uri, req, 'PUT')
self.assertEqual(200, resp.status)
resp = self.request(quoted_uri, '{}', 'GET').read()
self.assertEqual(json.loads(resp)['autostart'], True)
# set vm autostart tests (running)
resp = self.request(f'{quoted_uri}/poweroff', '{}', 'POST')
self.assertEqual(200, resp.status)
req = json.dumps({'autostart': False})
resp = self.request(quoted_uri, req, 'PUT')
self.assertEqual(200, resp.status)
resp = self.request(quoted_uri, '{}', 'GET').read()
self.assertEqual(json.loads(resp)['autostart'], False)
def test_vm_lifecycle(self):
# Create a Template
req = json.dumps(
{
'name': 'test',
'source_media': {'type': 'disk', 'path': fake_iso},
'disks': DISKS,
'icon': 'plugins/kimchi/images/icon-debian.png',
}
)
resp = self.request('/plugins/kimchi/templates', req, 'POST')
self.assertEqual(201, resp.status)
# Create a VM
req = json.dumps(
{'name': 'test-vm', 'template': '/plugins/kimchi/templates/test'}
)
resp = self.request('/plugins/kimchi/vms', req, 'POST')
task = json.loads(resp.read())
wait_task(self._task_lookup, task['id'])
self.assertEqual(202, resp.status)
# Verify the VM
vm = json.loads(self.request('/plugins/kimchi/vms/test-vm').read())
self.assertEqual('shutoff', vm['state'])
self.assertEqual('plugins/kimchi/images/icon-debian.png', vm['icon'])
# Verify the volume was created
vol_uri = (
'/plugins/kimchi/storagepools/default-pool/storagevolumes/' + '%s-0.img'
)
resp = self.request(vol_uri % vm['uuid'])
vol = json.loads(resp.read())
self.assertEqual(10 << 30, vol['capacity'])
self.assertEqual(['test-vm'], vol['used_by'])
# verify if poweroff command returns correct status
resp = self.request(
'/plugins/kimchi/vms/test-vm/poweroff', '{}', 'POST')
self.assertEqual(400, resp.status)
# verify if shutdown command returns correct status
resp = self.request(
'/plugins/kimchi/vms/test-vm/shutdown', '{}', 'POST')
self.assertEqual(400, resp.status)
# verify if reset command returns correct status
resp = self.request('/plugins/kimchi/vms/test-vm/reset', '{}', 'POST')
self.assertEqual(400, resp.status)
# Start the VM
resp = self.request('/plugins/kimchi/vms/test-vm/start', '{}', 'POST')
vm = json.loads(self.request('/plugins/kimchi/vms/test-vm').read())
self.assertEqual('running', vm['state'])
# verify if start command returns correct status
resp = self.request('/plugins/kimchi/vms/test-vm/start', '{}', 'POST')
self.assertEqual(400, resp.status)
# Test screenshot
resp = self.request('/' + vm['screenshot'], method='HEAD')
self.assertEqual(200, resp.status)
self.assertTrue(resp.getheader('Content-type').startswith('image'))
# Test Virt Viewer file
resp = self.request(
'/plugins/kimchi/vms/test-vm/virtviewerfile', '{}', 'GET')
self.assertEqual(200, resp.status)
vvfilecontent = resp.read().decode('utf-8')
self.assertEqual(
vvfilecontent, '[virt-viewer]\ntype=vnc\nhost=127.0.0.1\nport=5999\n'
)
# Clone a running VM
resp = self.request('/plugins/kimchi/vms/test-vm/clone', '{}', 'POST')
self.assertEqual(400, resp.status)
# Create a snapshot on running vm VM
params = {'name': 'test-snap2'}
resp = self.request(
'/plugins/kimchi/vms/test-vm/snapshots', json.dumps(params), 'POST'
)
self.assertEqual(202, resp.status)
task = json.loads(resp.read())
wait_task(self._task_lookup, task['id'])
task = json.loads(self.request(
'/plugins/kimchi/tasks/%s' % task['id']).read())
self.assertEqual('finished', task['status'])
# Delete a snapshot
resp = self.request(
'/plugins/kimchi/vms/test-vm/snapshots/%s' % params['name'], '{}', 'DELETE'
)
self.assertEqual(204, resp.status)
# Force poweroff the VM
resp = self.request(
'/plugins/kimchi/vms/test-vm/poweroff', '{}', 'POST')
vm = json.loads(self.request('/plugins/kimchi/vms/test-vm').read())
self.assertEqual('shutoff', vm['state'])
# Test create VM with same name fails with 400
req = json.dumps(
{'name': 'test-vm', 'template': '/plugins/kimchi/templates/test'}
)
resp = self.request('/plugins/kimchi/vms', req, 'POST')
self.assertEqual(400, resp.status)
# Clone a VM
resp = self.request('/plugins/kimchi/vms/test-vm/clone', '{}', 'POST')
self.assertEqual(202, resp.status)
task = json.loads(resp.read())
wait_task(self._task_lookup, task['id'])
task = json.loads(
self.request('/plugins/kimchi/tasks/%s' % task['id'], '{}').read()
)
self.assertEqual('finished', task['status'])
clone_vm_name = task['target_uri'].split('/')[-2]
self.assertTrue(re.match('test-vm-clone-\\d+', clone_vm_name))
resp = self.request('/plugins/kimchi/vms/test-vm', '{}')
original_vm_info = json.loads(resp.read())
resp = self.request('/plugins/kimchi/vms/%s' % clone_vm_name, '{}')
self.assertEqual(200, resp.status)
clone_vm_info = json.loads(resp.read())
self.assertNotEqual(original_vm_info['name'], clone_vm_info['name'])
del original_vm_info['name']
del clone_vm_info['name']
self.assertNotEqual(original_vm_info['uuid'], clone_vm_info['uuid'])
del original_vm_info['uuid']
del clone_vm_info['uuid']
self.assertEqual(original_vm_info, clone_vm_info)
# Create a snapshot on a stopped VM
params = {'name': 'test-snap'}
resp = self.request(
'/plugins/kimchi/vms/test-vm/snapshots', json.dumps(params), 'POST'
)
self.assertEqual(202, resp.status)
task = json.loads(resp.read())
wait_task(self._task_lookup, task['id'])
task = json.loads(self.request(
'/plugins/kimchi/tasks/%s' % task['id']).read())
self.assertEqual('finished', task['status'])
# Look up a non-existing snapshot
resp = self.request(
'/plugins/kimchi/vms/test-vm/snapshots/snap404', '{}', 'GET'
)
self.assertEqual(404, resp.status)
# Look up a snapshot
resp = self.request(
'/plugins/kimchi/vms/test-vm/snapshots/%s' % params['name'], '{}', 'GET'
)
self.assertEqual(200, resp.status)
snap = json.loads(resp.read())
self.assertTrue(int(time.time()) >= int(snap['created']))
self.assertEqual(params['name'], snap['name'])
self.assertEqual('', snap['parent'])
self.assertEqual('shutoff', snap['state'])
resp = self.request(
'/plugins/kimchi/vms/test-vm/snapshots', '{}', 'GET')
self.assertEqual(200, resp.status)
snaps = json.loads(resp.read())
self.assertEqual(1, len(snaps))
# Look up current snapshot (the one created above)
resp = self.request(
'/plugins/kimchi/vms/test-vm/snapshots/current', '{}', 'GET'
)
self.assertEqual(200, resp.status)
snap = json.loads(resp.read())
self.assertEqual(params['name'], snap['name'])
resp = self.request(
'/plugins/kimchi/vms/test-vm/snapshots', '{}', 'POST')
self.assertEqual(202, resp.status)
task = json.loads(resp.read())
snap_name = task['target_uri'].split('/')[-1]
wait_task(self._task_lookup, task['id'])
resp = self.request('/plugins/kimchi/tasks/%s' %
task['id'], '{}', 'GET')
task = json.loads(resp.read())
self.assertEqual('finished', task['status'])
resp = self.request(
'/plugins/kimchi/vms/test-vm/snapshots', '{}', 'GET')
self.assertEqual(200, resp.status)
snaps = json.loads(resp.read())
self.assertEqual(2, len(snaps))
# Look up current snapshot (the one created above)
resp = self.request(
'/plugins/kimchi/vms/test-vm/snapshots/current', '{}', 'GET'
)
self.assertEqual(200, resp.status)
snap = json.loads(resp.read())
self.assertEqual(snap_name, snap['name'])
# Revert to snapshot
resp = self.request(
'/plugins/kimchi/vms/test-vm/snapshots/%s/revert' % params['name'],
'{}',
'POST',
)
self.assertEqual(200, resp.status)
snap = json.loads(resp.read())
resp = self.request('/plugins/kimchi/vms/test-vm', '{}', 'GET')
self.assertEqual(200, resp.status)
vm = json.loads(resp.read())
self.assertEqual(vm['state'], snap['state'])
resp = self.request(
'/plugins/kimchi/vms/test-vm/snapshots/current', '{}', 'GET'
)
self.assertEqual(200, resp.status)
current_snap = json.loads(resp.read())
self.assertEqual(snap, current_snap)
# Delete a snapshot
resp = self.request(
'/plugins/kimchi/vms/test-vm/snapshots/%s' % params['name'], '{}', 'DELETE'
)
self.assertEqual(204, resp.status)
# Suspend the VM
resp = self.request('/plugins/kimchi/vms/test-vm', '{}', 'GET')
self.assertEqual(200, resp.status)
vm = json.loads(resp.read())
self.assertEqual(vm['state'], 'shutoff')
resp = self.request(
'/plugins/kimchi/vms/test-vm/suspend', '{}', 'POST')
self.assertEqual(400, resp.status)
resp = self.request('/plugins/kimchi/vms/test-vm/start', '{}', 'POST')
self.assertEqual(200, resp.status)
resp = self.request('/plugins/kimchi/vms/test-vm', '{}', 'GET')
self.assertEqual(200, resp.status)
vm = json.loads(resp.read())
self.assertEqual(vm['state'], 'running')
resp = self.request(
'/plugins/kimchi/vms/test-vm/suspend', '{}', 'POST')
self.assertEqual(200, resp.status)
resp = self.request('/plugins/kimchi/vms/test-vm', '{}', 'GET')
self.assertEqual(200, resp.status)
vm = json.loads(resp.read())
self.assertEqual(vm['state'], 'paused')
# Resume the VM
resp = self.request('/plugins/kimchi/vms/test-vm/resume', '{}', 'POST')
self.assertEqual(200, resp.status)
resp = self.request('/plugins/kimchi/vms/test-vm', '{}', 'GET')
self.assertEqual(200, resp.status)
vm = json.loads(resp.read())
self.assertEqual(vm['state'], 'running')
# Delete the VM
resp = self.request('/plugins/kimchi/vms/test-vm', '{}', 'DELETE')
self.assertEqual(204, resp.status)
# Delete the Template
resp = self.request('/plugins/kimchi/templates/test', '{}', 'DELETE')
self.assertEqual(204, resp.status)
# Verify the volume was deleted
self.assertHTTPStatus(404, vol_uri % vm['uuid'])
def test_vm_netboot(self):
# Create a Template
req = json.dumps(
{'name': 'tnetboot', 'source_media': {'type': 'netboot'}})
resp = self.request('/plugins/kimchi/templates', req, 'POST')
self.assertEqual(201, resp.status)
# Create a VM
req = json.dumps(
{'name': 'test-vm', 'template': '/plugins/kimchi/templates/tnetboot'}
)
resp = self.request('/plugins/kimchi/vms', req, 'POST')
task = json.loads(resp.read())
wait_task(self._task_lookup, task['id'])
self.assertEqual(202, resp.status)
# Verify the VM
vm = json.loads(self.request('/plugins/kimchi/vms/test-vm').read())
self.assertEqual('shutoff', vm['state'])
self.assertEqual('plugins/kimchi/images/icon-vm.png', vm['icon'])
# verify if poweroff command returns correct status
resp = self.request(
'/plugins/kimchi/vms/test-vm/poweroff', '{}', 'POST')
self.assertEqual(400, resp.status)
# verify if shutdown command returns correct status
resp = self.request(
'/plugins/kimchi/vms/test-vm/shutdown', '{}', 'POST')
self.assertEqual(400, resp.status)
# verify if reset command returns correct status
resp = self.request('/plugins/kimchi/vms/test-vm/reset', '{}', 'POST')
self.assertEqual(400, resp.status)
# Start the VM
resp = self.request('/plugins/kimchi/vms/test-vm/start', '{}', 'POST')
vm = json.loads(self.request('/plugins/kimchi/vms/test-vm').read())
self.assertEqual('running', vm['state'])
# verify if start command returns correct status
resp = self.request('/plugins/kimchi/vms/test-vm/start', '{}', 'POST')
self.assertEqual(400, resp.status)
# Force poweroff the VM
resp = self.request(
'/plugins/kimchi/vms/test-vm/poweroff', '{}', 'POST')
vm = json.loads(self.request('/plugins/kimchi/vms/test-vm').read())
self.assertEqual('shutoff', vm['state'])
# Delete the VM
resp = self.request('/plugins/kimchi/vms/test-vm', '{}', 'DELETE')
self.assertEqual(204, resp.status)
# Delete the Template
resp = self.request(
'/plugins/kimchi/templates/tnetboot', '{}', 'DELETE')
self.assertEqual(204, resp.status)
def test_vm_graphics(self):
# Create a Template
req = json.dumps(
{'name': 'test', 'source_media': {'type': 'disk', 'path': fake_iso}}
)
resp = self.request('/plugins/kimchi/templates', req, 'POST')
self.assertEqual(201, resp.status)
# Create a VM with default args
req = json.dumps(
{'name': 'test-vm', 'template': '/plugins/kimchi/templates/test'}
)
resp = self.request('/plugins/kimchi/vms', req, 'POST')
self.assertEqual(202, resp.status)
task = json.loads(resp.read())
wait_task(self._task_lookup, task['id'])
# Verify the VM
vm = json.loads(self.request('/plugins/kimchi/vms/test-vm').read())
self.assertEqual('127.0.0.1', vm['graphics']['listen'])
self.assertEqual('vnc', vm['graphics']['type'])
# Delete the VM
resp = self.request('/plugins/kimchi/vms/test-vm', '{}', 'DELETE')
self.assertEqual(204, resp.status)
# Create a VM with specified graphics type and listen
graphics = {'type': 'vnc', 'listen': '127.0.0.1'}
req = json.dumps(
{
'name': 'test-vm',
'template': '/plugins/kimchi/templates/test',
'graphics': graphics,
}
)
resp = self.request('/plugins/kimchi/vms', req, 'POST')
self.assertEqual(202, resp.status)
task = json.loads(resp.read())
wait_task(self._task_lookup, task['id'])
# Verify the VM
vm = json.loads(self.request('/plugins/kimchi/vms/test-vm').read())
self.assertEqual('127.0.0.1', vm['graphics']['listen'])
self.assertEqual('vnc', vm['graphics']['type'])
# Delete the VM
resp = self.request('/plugins/kimchi/vms/test-vm', '{}', 'DELETE')
self.assertEqual(204, resp.status)
# Create a VM with listen as ipv6 address
graphics = {'type': 'spice', 'listen': 'fe00::0'}
req = json.dumps(
{
'name': 'test-vm',
'template': '/plugins/kimchi/templates/test',
'graphics': graphics,
}
)
resp = self.request('/plugins/kimchi/vms', req, 'POST')
self.assertEqual(202, resp.status)
task = json.loads(resp.read())
wait_task(self._task_lookup, task['id'])
# Verify the VM
vm = json.loads(self.request('/plugins/kimchi/vms/test-vm').read())
self.assertEqual('fe00::0', vm['graphics']['listen'])
self.assertEqual('spice', vm['graphics']['type'])
# Delete the VM
resp = self.request('/plugins/kimchi/vms/test-vm', '{}', 'DELETE')
self.assertEqual(204, resp.status)
# Create a VM with specified graphics type and default listen
graphics = {'type': 'spice'}
req = json.dumps(
{
'name': 'test-vm',
'template': '/plugins/kimchi/templates/test',
'graphics': graphics,
}
)
resp = self.request('/plugins/kimchi/vms', req, 'POST')
self.assertEqual(202, resp.status)
task = json.loads(resp.read())
wait_task(self._task_lookup, task['id'])
# Verify the VM
vm = json.loads(self.request('/plugins/kimchi/vms/test-vm').read())
self.assertEqual('127.0.0.1', vm['graphics']['listen'])
self.assertEqual('spice', vm['graphics']['type'])
# Delete the VM
resp = self.request('/plugins/kimchi/vms/test-vm', '{}', 'DELETE')
self.assertEqual(204, resp.status)
# Try to create a VM with invalid graphics type
graphics = {'type': 'invalid'}
req = json.dumps(
{
'name': 'test-vm',
'template': '/plugins/kimchi/templates/test',
'graphics': graphics,
}
)
resp = self.request('/plugins/kimchi/vms', req, 'POST')
self.assertEqual(400, resp.status)
# Try to create a VM with invalid graphics listen
graphics = {'type': 'spice', 'listen': 'invalid'}
req = json.dumps(
{
'name': 'test-vm',
'template': '/plugins/kimchi/templates/test',
'graphics': graphics,
}
)
resp = self.request('/plugins/kimchi/vms', req, 'POST')
self.assertEqual(400, resp.status)
# Delete the Template
resp = self.request('/plugins/kimchi/templates/test', '{}', 'DELETE')
self.assertEqual(204, resp.status)
def test_vm_storage_devices(self):
with RollbackContext() as rollback:
# Create a template as a base for our VMs
req = json.dumps(
{'name': 'test', 'source_media': {'type': 'disk', 'path': fake_iso}}
)
resp = self.request('/plugins/kimchi/templates', req, 'POST')
self.assertEqual(201, resp.status)
# Delete the template
rollback.prependDefer(
self.request, '/plugins/kimchi/templates/test', '{}', 'DELETE'
)
# Create a VM with default args
req = json.dumps(
{'name': 'test-vm', 'template': '/plugins/kimchi/templates/test'}
)
resp = self.request('/plugins/kimchi/vms', req, 'POST')
self.assertEqual(202, resp.status)
task = json.loads(resp.read())
wait_task(self._task_lookup, task['id'])
# Delete the VM
rollback.prependDefer(
self.request, '/plugins/kimchi/vms/test-vm', '{}', 'DELETE'
)
# Check storage devices
resp = self.request(
'/plugins/kimchi/vms/test-vm/storages', '{}', 'GET')
devices = json.loads(resp.read())
self.assertEqual(2, len(devices))
dev_types = []
for d in devices:
self.assertIn('type', d.keys())
self.assertIn('dev', d.keys())
self.assertIn('path', d.keys())
dev_types.append(d['type'])
self.assertEqual(['cdrom', 'disk'], sorted(dev_types))
# Attach cdrom with nonexistent iso
req = json.dumps(
{'dev': 'hdx', 'type': 'cdrom', 'path': '/tmp/nonexistent.iso'}
)
resp = self.request(
'/plugins/kimchi/vms/test-vm/storages', req, 'POST')
self.assertEqual(400, resp.status)
# Create temp storage pool
req = json.dumps(
{
'name': 'tmp',
'capacity': 1024,
'allocated': 512,
'path': '/tmp',
'type': 'dir',
}
)
resp = self.request('/plugins/kimchi/storagepools', req, 'POST')
self.assertEqual(201, resp.status)
resp = self.request(
'/plugins/kimchi/storagepools/tmp/activate', req, 'POST'
)
self.assertEqual(200, resp.status)
# 'name' is required for this type of volume
open('/tmp/attach-volume', 'w').close()
req = json.dumps(
{'capacity': 1024, 'allocation': 512,
'type': 'disk', 'format': 'raw'}
)
resp = self.request(
'/plugins/kimchi/storagepools/tmp/storagevolumes', req, 'POST'
)
self.assertEqual(400, resp.status)
req = json.dumps(
{
'name': 'attach-volume',
'capacity': 1024,
'allocation': 512,
'type': 'disk',
'format': 'raw',
}
)
resp = self.request(
'/plugins/kimchi/storagepools/tmp/storagevolumes', req, 'POST'
)
self.assertEqual(202, resp.status)
time.sleep(1)
# Attach cdrom with both path and volume specified
open('/tmp/existent.iso', 'w').close()
req = json.dumps(
{
'dev': 'hdx',
'type': 'cdrom',
'pool': 'tmp',
'vol': 'attach-volume',
'path': '/tmp/existent.iso',
}
)
resp = self.request(
'/plugins/kimchi/vms/test-vm/storages', req, 'POST')
self.assertEqual(400, resp.status)
# Attach disk with both path and volume specified
req = json.dumps(
{
'dev': 'hdx',
'type': 'disk',
'pool': 'tmp',
'vol': 'attach-volume',
'path': '/tmp/existent.iso',
}
)
resp = self.request(
'/plugins/kimchi/vms/test-vm/storages', req, 'POST')
self.assertEqual(400, resp.status)
# Attach disk with only pool specified
req = json.dumps({'dev': 'hdx', 'type': 'cdrom', 'pool': 'tmp'})
resp = self.request(
'/plugins/kimchi/vms/test-vm/storages', req, 'POST')
self.assertEqual(400, resp.status)
# Attach disk with pool and vol specified
req = json.dumps(
{'type': 'disk', 'pool': 'tmp', 'vol': 'attach-volume'})
resp = self.request(
'/plugins/kimchi/vms/test-vm/storages', req, 'POST')
self.assertEqual(201, resp.status)
cd_info = json.loads(resp.read())
self.assertEqual('disk', cd_info['type'])
# Attach a cdrom with existent dev name
req = json.dumps({'type': 'cdrom', 'path': '/tmp/existent.iso'})
resp = self.request(
'/plugins/kimchi/vms/test-vm/storages', req, 'POST')
self.assertEqual(201, resp.status)
cd_info = json.loads(resp.read())
cd_dev = cd_info['dev']
self.assertEqual('cdrom', cd_info['type'])
self.assertEqual('/tmp/existent.iso', cd_info['path'])
# Delete the file and cdrom
rollback.prependDefer(
self.request,
'/plugins/kimchi/vms/test-vm/storages/hdx',
'{}',
'DELETE'
)
os.remove('/tmp/existent.iso')
os.remove('/tmp/attach-volume')
# Change path of storage cdrom
cdrom = 'http://mirrors.kernel.org/fedora/releases/29/Everything' \
'/x86_64/iso/Fedora-Everything-netinst-x86_64-29-1.2.iso'
req = json.dumps({'path': cdrom})
resp = self.request(
'/plugins/kimchi/vms/test-vm/storages/' + cd_dev, req, 'PUT'
)
if not os.uname()[4] == 's390x':
self.assertEqual(200, resp.status)
cd_info = json.loads(resp.read())
self.assertEqual(
urllib.parse.urlparse(cdrom).path,
urllib.parse.urlparse(cd_info['path']).path,
)
# Test GET
devs = json.loads(
self.request('/plugins/kimchi/vms/test-vm/storages').read()
)
self.assertEqual(4, len(devs))
# Detach storage cdrom
resp = self.request(
'/plugins/kimchi/vms/test-vm/storages/' + cd_dev, '{}', 'DELETE'
)
self.assertEqual(204, resp.status)
# Test GET
devs = json.loads(
self.request('/plugins/kimchi/vms/test-vm/storages').read()
)
self.assertEqual(3, len(devs))
resp = self.request(
'/plugins/kimchi/storagepools/tmp/deactivate', '{}', 'POST'
)
self.assertEqual(200, resp.status)
# cannot delete storagepool with volumes associate to guests
resp = self.request(
'/plugins/kimchi/storagepools/tmp', '{}', 'DELETE')
self.assertEqual(400, resp.status)
# activate pool
resp = self.request(
'/plugins/kimchi/storagepools/tmp/activate', '{}', 'POST'
)
self.assertEqual(200, resp.status)
# delete volumes
if not os.uname()[4] == 's390x':
uri = '/plugins/kimchi/vms/test-vm/storages/hdd'
else:
uri = '/plugins/kimchi/vms/test-vm/storages/vdb'
resp = self.request(uri, '{}', 'DELETE')
self.assertEqual(204, resp.status)
# deactive and delete storage pool
resp = self.request(
'/plugins/kimchi/storagepools/tmp/deactivate', '{}', 'POST'
)
self.assertEqual(200, resp.status)
# Pool is associated with VM test (create above)
resp = self.request(
'/plugins/kimchi/storagepools/tmp', '{}', 'DELETE')
self.assertEqual(204, resp.status)
def test_vm_iface(self):
with RollbackContext() as rollback:
# Create a template as a base for our VMs
req = json.dumps(
{'name': 'test', 'source_media': {'type': 'disk', 'path': fake_iso}}
)
resp = self.request('/plugins/kimchi/templates', req, 'POST')
self.assertEqual(201, resp.status)
# Delete the template
rollback.prependDefer(
self.request, '/plugins/kimchi/templates/test', '{}', 'DELETE'
)
# Create a VM with default args
req = json.dumps(
{'name': 'test-vm', 'template': '/plugins/kimchi/templates/test'}
)
resp = self.request('/plugins/kimchi/vms', req, 'POST')
self.assertEqual(202, resp.status)
task = json.loads(resp.read())
wait_task(self._task_lookup, task['id'])
# Delete the VM
rollback.prependDefer(
self.request, '/plugins/kimchi/vms/test-vm', '{}', 'DELETE'
)
# Create a network
req = json.dumps(
{'name': 'test-network', 'connection': 'nat', 'net': '127.0.1.0/24'}
)
resp = self.request('/plugins/kimchi/networks', req, 'POST')
self.assertEqual(201, resp.status)
# Delete the network
rollback.prependDefer(
self.request, '/plugins/kimchi/networks/test-network', '{}', 'DELETE'
)
ifaces = json.loads(
self.request('/plugins/kimchi/vms/test-vm/ifaces').read()
)
if not os.uname()[4] == 's390x':
self.assertEqual(1, len(ifaces))
for iface in ifaces:
res = json.loads(
self.request(
'/plugins/kimchi/vms/test-vm/ifaces/%s' % iface['mac']
).read()
)
self.assertEqual('default', res['network'])
self.assertEqual(17, len(res['mac']))
self.assertEqual(get_template_default(
'old', 'nic_model'), res['model'])
self.assertTrue('ips' in res)
# try to attach an interface without specifying 'model'
req = json.dumps({'type': 'network'})
resp = self.request(
'/plugins/kimchi/vms/test-vm/ifaces', req, 'POST')
self.assertEqual(400, resp.status)
# try to attach an interface of type "macvtap" without source
if os.uname()[4] == 's390x':
req = json.dumps({'type': 'macvtap'})
resp = self.request(
'/plugins/kimchi/vms/test-vm/ifaces', req, 'POST')
self.assertEqual(400, resp.status)
# try to attach an interface of type "ovs" without source
req = json.dumps({'type': 'ovs'})
resp = self.request(
'/plugins/kimchi/vms/test-vm/ifaces', req, 'POST')
self.assertEqual(400, resp.status)
# attach network interface to vm
req = json.dumps(
{'type': 'network', 'network': 'test-network', 'model': 'virtio'}
)
resp = self.request(
'/plugins/kimchi/vms/test-vm/ifaces', req, 'POST')
self.assertEqual(201, resp.status)
iface = json.loads(resp.read())
self.assertEqual('test-network', iface['network'])
self.assertEqual(17, len(iface['mac']))
self.assertEqual('virtio', iface['model'])
self.assertEqual('network', iface['type'])
# update vm interface
newMacAddr = '54:50:e3:44:8a:af'
req = json.dumps(
{
'network': 'default',
'model': 'virtio',
'type': 'network',
'mac': newMacAddr,
}
)
resp = self.request(
'/plugins/kimchi/vms/test-vm/ifaces/%s' % iface['mac'], req, 'PUT'
)
self.assertEqual(303, resp.status)
iface = json.loads(
self.request(
'/plugins/kimchi/vms/test-vm/ifaces/%s' % newMacAddr
).read()
)
self.assertEqual(newMacAddr, iface['mac'])
# Start the VM
resp = self.request(
'/plugins/kimchi/vms/test-vm/start', '{}', 'POST')
vm = json.loads(self.request('/plugins/kimchi/vms/test-vm').read())
self.assertEqual('running', vm['state'])
# Check for an IP address
iface = json.loads(
self.request(
'/plugins/kimchi/vms/test-vm/ifaces/%s' % newMacAddr
).read()
)
self.assertTrue(len(iface['ips']) > 0)
# Force poweroff the VM
resp = self.request(
'/plugins/kimchi/vms/test-vm/poweroff', '{}', 'POST')
vm = json.loads(self.request('/plugins/kimchi/vms/test-vm').read())
self.assertEqual('shutoff', vm['state'])
# detach network interface from vm
resp = self.request(
'/plugins/kimchi/vms/test-vm/ifaces/%s' % iface['mac'], '{}', 'DELETE'
)
self.assertEqual(204, resp.status)
if os.uname()[4] == 's390x':
# attach macvtap interface to vm
req = json.dumps({'type': 'macvtap', 'source': 'test-network'})
resp = self.request(
'/plugins/kimchi/vms/test-vm/ifaces', req, 'POST')
self.assertEqual(201, resp.status)
iface = json.loads(resp.read())
self.assertEqual('test-network', iface['source'])
self.assertEqual('macvtap', iface['type'])
# Start the VM
resp = self.request(
'/plugins/kimchi/vms/test-vm/start', '{}', 'POST')
vm = json.loads(self.request(
'/plugins/kimchi/vms/test-vm').read())
self.assertEqual('running', vm['state'])
# Force poweroff the VM
resp = self.request(
'/plugins/kimchi/vms/test-vm/poweroff', '{}', 'POST'
)
vm = json.loads(self.request(
'/plugins/kimchi/vms/test-vm').read())
self.assertEqual('shutoff', vm['state'])
# detach network interface from vm
resp = self.request(
'/plugins/kimchi/vms/test-vm/ifaces/%s' % iface['mac'],
'{}',
'DELETE',
)
self.assertEqual(204, resp.status)
# attach ovs interface to vm
req = json.dumps({'type': 'ovs', 'source': 'test-network'})
resp = self.request(
'/plugins/kimchi/vms/test-vm/ifaces', req, 'POST')
self.assertEqual(201, resp.status)
iface = json.loads(resp.read())
self.assertEqual('test-network', iface['source'])
self.assertEqual('ovs', iface['type'])
# Start the VM
resp = self.request(
'/plugins/kimchi/vms/test-vm/start', '{}', 'POST')
vm = json.loads(self.request(
'/plugins/kimchi/vms/test-vm').read())
self.assertEqual('running', vm['state'])
# Force poweroff the VM
resp = self.request(
'/plugins/kimchi/vms/test-vm/poweroff', '{}', 'POST'
)
vm = json.loads(self.request(
'/plugins/kimchi/vms/test-vm').read())
self.assertEqual('shutoff', vm['state'])
# detach ovs interface from vm
resp = self.request(
'/plugins/kimchi/vms/test-vm/ifaces/%s' % iface['mac'],
'{}',
'DELETE',
)
self.assertEqual(204, resp.status)
def test_vm_customise_storage(self):
# Create a Template
req = json.dumps(
{
'name': 'test',
'disks': DISKS,
'source_media': {'type': 'disk', 'path': fake_iso},
}
)
resp = self.request('/plugins/kimchi/templates', req, 'POST')
self.assertEqual(201, resp.status)
# Create alternate storage
req = json.dumps(
{
'name': 'alt',
'capacity': 1024,
'allocated': 512,
'path': '/tmp',
'type': 'dir',
}
)
resp = self.request('/plugins/kimchi/storagepools', req, 'POST')
self.assertEqual(201, resp.status)
resp = self.request(
'/plugins/kimchi/storagepools/alt/activate', req, 'POST')
self.assertEqual(200, resp.status)
# Create a VM
req = json.dumps(
{
'name': 'test-vm',
'template': '/plugins/kimchi/templates/test',
'storagepool': '/plugins/kimchi/storagepools/alt',
}
)
resp = self.request('/plugins/kimchi/vms', req, 'POST')
self.assertEqual(202, resp.status)
task = json.loads(resp.read())
wait_task(self._task_lookup, task['id'])
resp = self.request('/plugins/kimchi/vms/test-vm', '{}', 'GET')
vm_info = json.loads(resp.read())
# Test template not changed after vm customise its pool
t = json.loads(self.request('/plugins/kimchi/templates/test').read())
self.assertEqual(
t['disks'][0]['pool']['name'], '/plugins/kimchi/storagepools/default-pool'
)
# Verify the volume was created
vol_uri = (
'/plugins/kimchi/storagepools/alt/storagevolumes/%s-0.img' % vm_info['uuid']
)
resp = self.request(vol_uri)
vol = json.loads(resp.read())
self.assertEqual(10 << 30, vol['capacity'])
# Delete the VM
resp = self.request('/plugins/kimchi/vms/test-vm', '{}', 'DELETE')
self.assertEqual(204, resp.status)
# Verify the volume was deleted
self.assertHTTPStatus(404, vol_uri)
def test_scsi_fc_storage(self):
# Create scsi fc pool
req = json.dumps(
{
'name': 'scsi_fc_pool',
'type': 'scsi',
'source': {'adapter_name': 'scsi_host2'},
}
)
resp = self.request('/plugins/kimchi/storagepools', req, 'POST')
self.assertEqual(201, resp.status)
# Test create vms using lun of this pool
# activate the storage pool
resp = self.request(
'/plugins/kimchi/storagepools/scsi_fc_pool/activate', '{}', 'POST'
)
# Create template fails because SCSI volume is missing
tmpl_params = {
'name': 'test_fc_pool',
'source_media': {'type': 'disk', 'path': fake_iso},
'disks': [{'pool': {'name': '/plugins/kimchi/storagepools/scsi_fc_pool'}}],
}
req = json.dumps(tmpl_params)
resp = self.request('/plugins/kimchi/templates', req, 'POST')
self.assertEqual(400, resp.status)
# Choose SCSI volume to create template
resp = self.request(
'/plugins/kimchi/storagepools/scsi_fc_pool/storagevolumes')
lun_name = json.loads(resp.read())[0]['name']
pool_name = tmpl_params['disks'][0]['pool']['name']
tmpl_params['disks'] = [
{
'index': 0,
'volume': lun_name,
'pool': {'name': pool_name},
'format': 'raw',
}
]
req = json.dumps(tmpl_params)
resp = self.request('/plugins/kimchi/templates', req, 'POST')
self.assertEqual(201, resp.status)
# Create vm in scsi pool
req = json.dumps(
{'name': 'test-vm', 'template': '/plugins/kimchi/templates/test_fc_pool'}
)
resp = self.request('/plugins/kimchi/vms', req, 'POST')
self.assertEqual(202, resp.status)
task = json.loads(resp.read())
wait_task(self._task_lookup, task['id'])
# Start the VM
resp = self.request('/plugins/kimchi/vms/test-vm/start', '{}', 'POST')
vm = json.loads(self.request('/plugins/kimchi/vms/test-vm').read())
self.assertEqual('running', vm['state'])
# Force poweroff the VM
resp = self.request(
'/plugins/kimchi/vms/test-vm/poweroff', '{}', 'POST')
vm = json.loads(self.request('/plugins/kimchi/vms/test-vm').read())
self.assertEqual('shutoff', vm['state'])
# Delete the VM
resp = self.request('/plugins/kimchi/vms/test-vm', '{}', 'DELETE')
self.assertEqual(204, resp.status)
def test_unnamed_vms(self):
# Create a Template
req = json.dumps(
{'name': 'test', 'source_media': {'type': 'disk', 'path': fake_iso}}
)
resp = self.request('/plugins/kimchi/templates', req, 'POST')
self.assertEqual(201, resp.status)
# Create 5 unnamed vms from this template
for i in range(1, 6):
req = json.dumps({'template': '/plugins/kimchi/templates/test'})
task = json.loads(self.request(
'/plugins/kimchi/vms', req, 'POST').read())
wait_task(self._task_lookup, task['id'])
resp = self.request(
'/plugins/kimchi/vms/test-vm-%i' % i, '{}', 'GET')
self.assertEqual(resp.status, 200)
count = len(json.loads(self.request('/plugins/kimchi/vms').read()))
self.assertEqual(6, count)
def test_create_vm_without_template(self):
req = json.dumps({'name': 'vm-without-template'})
resp = self.request('/plugins/kimchi/vms', req, 'POST')
self.assertEqual(400, resp.status)
resp = json.loads(resp.read())
self.assertIn('KCHVM0016E:', resp['reason'])
def test_create_vm_with_bad_template_uri(self):
req = json.dumps({'name': 'vm-bad-template',
'template': '/mytemplate'})
resp = self.request('/plugins/kimchi/vms', req, 'POST')
self.assertEqual(400, resp.status)
resp = json.loads(resp.read())
self.assertIn('KCHVM0012E', resp['reason'])
def test_vm_migrate(self):
with RollbackContext() as rollback:
req = json.dumps(
{
'name': 'test-migrate',
'source_media': {'type': 'disk', 'path': fake_iso},
}
)
resp = self.request('/plugins/kimchi/templates', req, 'POST')
self.assertEqual(201, resp.status)
rollback.prependDefer(
self.request, '/plugins/kimchi/templates/test-migrate', '{}', 'DELETE'
)
req = json.dumps(
{
'name': 'test-vm-migrate',
'template': '/plugins/kimchi/templates/test-migrate',
}
)
resp = self.request('/plugins/kimchi/vms', req, 'POST')
self.assertEqual(202, resp.status)
task = json.loads(resp.read())
wait_task(self._task_lookup, task['id'])
rollback.prependDefer(
self.request, '/plugins/kimchi/vms/test-vm', '{}', 'DELETE'
)
params = {'remote_host': 'destination_host'}
resp = self.request(
'/plugins/kimchi/vms/test-vm-migrate/migrate',
json.dumps(params),
'POST',
)
self.assertEqual(202, resp.status)
task = json.loads(resp.read())
wait_task(self._task_lookup, task['id'])
task = json.loads(
self.request('/plugins/kimchi/tasks/%s' % task['id']).read()
)
self.assertEqual('finished', task['status'])
params = {'remote_host': 'rdma_host', 'enable_rdma': True}
resp = self.request(
'/plugins/kimchi/vms/test-vm-migrate/migrate',
json.dumps(params),
'POST',
)
self.assertEqual(202, resp.status)
task = json.loads(resp.read())
wait_task(self._task_lookup, task['id'])
task = json.loads(
self.request('/plugins/kimchi/tasks/%s' % task['id']).read()
)
self.assertEqual('finished', task['status'])
def test_create_vm_with_img_based_template(self):
resp = json.loads(
self.request(
'/plugins/kimchi/storagepools/default-pool/storagevolumes'
).read()
)
self.assertEqual(0, len(resp))
# Create a Template
mock_base = '/tmp/mock.img'
os.system('qemu-img create -f qcow2 %s 10M' % mock_base)
req = json.dumps(
{'name': 'test', 'source_media': {'type': 'disk', 'path': mock_base}}
)
resp = self.request('/plugins/kimchi/templates', req, 'POST')
self.assertEqual(201, resp.status)
req = json.dumps({'template': '/plugins/kimchi/templates/test'})
resp = self.request('/plugins/kimchi/vms', req, 'POST')
self.assertEqual(202, resp.status)
task = json.loads(resp.read())
wait_task(self._task_lookup, task['id'])
# Test storage volume created with backing store of base file
resp = json.loads(
self.request(
'/plugins/kimchi/storagepools/default-pool/storagevolumes'
).read()
)
self.assertEqual(1, len(resp))
def _create_pool(self, name):
req = json.dumps(
{
'name': name,
'capacity': 10240,
'allocated': 5120,
'path': '/var/lib/libvirt/images/',
'type': 'dir',
}
)
resp = self.request('/plugins/kimchi/storagepools', req, 'POST')
self.assertEqual(201, resp.status)
# Verify the storage pool
storagepool = json.loads(
self.request('/plugins/kimchi/storagepools/%s' % name).read()
)
self.assertEqual('inactive', storagepool['state'])
return name
def _delete_pool(self, name):
# Delete the storage pool
resp = self.request('/plugins/kimchi/storagepools/%s' %
name, '{}', 'DELETE')
self.assertEqual(204, resp.status)
def test_iso_scan_shallow(self):
# fake environment preparation
self._create_pool('pool-3')
self.request(
'/plugins/kimchi/storagepools/pool-3/activate', '{}', 'POST')
params = {
'name': 'fedora.iso',
'capacity': 1073741824, # 1 GiB
'type': 'file',
'format': 'iso',
}
task_info = model.storagevolumes_create('pool-3', params)
wait_task(self._task_lookup, task_info['id'])
storagevolume = json.loads(
self.request(
'/plugins/kimchi/storagepools/kimchi_isos/storagevolumes/'
).read()
)[0]
self.assertEqual('fedora.iso', storagevolume['name'])
self.assertEqual('iso', storagevolume['format'])
self.assertEqual('/var/lib/libvirt/images/fedora.iso',
storagevolume['path'])
self.assertEqual(1073741824, storagevolume['capacity']) # 1 GiB
self.assertEqual(0, storagevolume['allocation'])
self.assertEqual('17', storagevolume['os_version'])
self.assertEqual('fedora', storagevolume['os_distro'])
self.assertEqual(True, storagevolume['bootable'])
self.assertEqual(True, storagevolume['has_permission'])
# Create a template
# In real model os distro/version can be omitted
# as we will scan the iso
req = json.dumps(
{
'name': 'test',
'source_media': {'type': 'disk', 'path': storagevolume['path']},
'os_distro': storagevolume['os_distro'],
'os_version': storagevolume['os_version'],
}
)
resp = self.request('/plugins/kimchi/templates', req, 'POST')
self.assertEqual(201, resp.status)
# Verify the template
t = json.loads(self.request('/plugins/kimchi/templates/test').read())
self.assertEqual('test', t['name'])
self.assertEqual('fedora', t['os_distro'])
self.assertEqual('17', t['os_version'])
self.assertEqual(get_template_default('old', 'memory'), t['memory'])
# Deactivate or destroy scan pool return 405
resp = self.request(
'/plugins/kimchi/storagepools/kimchi_isos/storagevolumes' '/deactivate',
'{}',
'POST',
)
self.assertEqual(405, resp.status)
resp = self.request(
'/plugins/kimchi/storagepools/kimchi_isos/storagevolumes', '{}', 'DELETE'
)
self.assertEqual(405, resp.status)
# Delete the template
resp = self.request('/plugins/kimchi/templates/%s' %
t['name'], '{}', 'DELETE')
self.assertEqual(204, resp.status)
resp = self.request(
'/plugins/kimchi/storagepools/pool-3/deactivate', '{}', 'POST'
)
self.assertEqual(200, resp.status)
self._delete_pool('pool-3')
def test_screenshot_refresh(self):
# Create a VM
req = json.dumps(
{'name': 'test', 'source_media': {'type': 'disk', 'path': fake_iso}}
)
resp = self.request('/plugins/kimchi/templates', req, 'POST')
req = json.dumps(
{'name': 'test-vm', 'template': '/plugins/kimchi/templates/test'}
)
resp = self.request('/plugins/kimchi/vms', req, 'POST')
task = json.loads(resp.read())
wait_task(self._task_lookup, task['id'])
# Test screenshot for shut-off state vm
resp = self.request('/plugins/kimchi/vms/test-vm/screenshot')
self.assertEqual(404, resp.status)
# Test screenshot for running vm
resp = self.request('/plugins/kimchi/vms/test-vm/start', '{}', 'POST')
vm = json.loads(self.request('/plugins/kimchi/vms/test-vm').read())
resp = self.request('/' + vm['screenshot'], method='HEAD')
self.assertEqual(200, resp.status)
self.assertTrue(resp.getheader('Content-type').startswith('image'))
# Test screenshot sub-resource redirect
resp = self.request('/plugins/kimchi/vms/test-vm/screenshot')
self.assertEqual(200, resp.status)
self.assertEqual('image/png', resp.getheader('content-type'))
lastMod1 = resp.getheader('last-modified')
# Take another screenshot instantly and compare the last Modified date
resp = self.request('/plugins/kimchi/vms/test-vm/screenshot')
lastMod2 = resp.getheader('last-modified')
self.assertEqual(lastMod2, lastMod1)
resp = self.request(
'/plugins/kimchi/vms/test-vm/screenshot', '{}', 'DELETE')
self.assertEqual(405, resp.status)
# No screenshot after stopped the VM
self.request('/plugins/kimchi/vms/test-vm/poweroff', '{}', 'POST')
resp = self.request('/plugins/kimchi/vms/test-vm/screenshot')
self.assertEqual(404, resp.status)
# Picture link not available after VM deleted
self.request('/plugins/kimchi/vms/test-vm/start', '{}', 'POST')
vm = json.loads(self.request('/plugins/kimchi/vms/test-vm').read())
img_lnk = vm['screenshot']
self.request('/plugins/kimchi/vms/test-vm', '{}', 'DELETE')
resp = self.request('/' + img_lnk)
self.assertEqual(404, resp.status)
def test_interfaces(self):
resp = self.request('/plugins/kimchi/interfaces').read()
interfaces = json.loads(resp.decode('utf-8'))
keys = ['name', 'type', 'ipaddr', 'netmask', 'status', 'module']
for interface in interfaces:
self.assertEqual(sorted(keys), sorted(interface.keys()))
def _task_lookup(self, taskid):
return json.loads(self.request('/plugins/kimchi/tasks/%s' % taskid).read())
def test_tasks(self):
id1 = AsyncTask('/plugins/kimchi/tasks/1', self._async_op).id
id2 = AsyncTask('/plugins/kimchi/tasks/2', self._except_op).id
id3 = AsyncTask('/plugins/kimchi/tasks/3', self._intermid_op).id
target_uri = urllib.parse.quote('^/plugins/kimchi/tasks/*', safe='')
filter_data = 'status=running&target_uri=%s' % target_uri
tasks = json.loads(
self.request('/plugins/kimchi/tasks?%s' % filter_data).read()
)
self.assertLessEqual(3, len(tasks))
tasks = json.loads(self.request('/plugins/kimchi/tasks').read())
tasks_ids = [t['id'] for t in tasks]
self.assertEqual(set([id1, id2, id3]) - set(tasks_ids), set([]))
wait_task(self._task_lookup, id2)
foo2 = json.loads(self.request(
'/plugins/kimchi/tasks/%s' % id2).read())
keys = ['id', 'status', 'message', 'target_uri']
self.assertEqual(sorted(keys), sorted(foo2.keys()))
self.assertEqual('failed', foo2['status'])
wait_task(self._task_lookup, id3)
foo3 = json.loads(self.request(
'/plugins/kimchi/tasks/%s' % id3).read())
self.assertEqual('in progress', foo3['message'])
self.assertEqual('running', foo3['status'])
def test_config(self):
resp = self.request('/plugins/kimchi/config').read()
conf = json.loads(resp)
keys = ["version", "with_spice_web_client"]
self.assertEqual(keys, sorted(conf.keys()))
def test_capabilities(self):
resp = self.request('/plugins/kimchi/config/capabilities').read()
conf = json.loads(resp)
keys = [
'libvirt_stream_protocols',
'qemu_stream',
'qemu_spice',
'screenshot',
'kernel_vfio',
'nm_running',
'mem_hotplug_support',
'libvirtd_running',
]
self.assertEqual(sorted(keys), sorted(conf.keys()))
def test_distros(self):
resp = self.request('/plugins/kimchi/config/distros').read()
distros = json.loads(resp)
for distro in distros:
self.assertIn('name', distro)
self.assertIn('os_distro', distro)
self.assertIn('os_version', distro)
self.assertIn('path', distro)
# Test in X86
ident = 'Fedora 29'
resp = self.request(
'/plugins/kimchi/config/distros/%s' % urllib.parse.quote(ident)
).read()
distro = json.loads(resp)
if os.uname()[4] in ['x86_64', 'amd64']:
self.assertEqual(distro['name'], ident)
self.assertEqual(distro['os_distro'], 'fedora')
self.assertEqual(distro['os_version'], '29')
self.assertEqual(distro['os_arch'], 'x86_64')
self.assertIn('path', distro)
else:
# Distro not found error
if distro.get('reason'):
self.assertIn('KCHDISTRO0001E', distro.get('reason'))
# Test in PPC
ident = 'Fedora 24 LE'
resp = self.request(
'/plugins/kimchi/config/distros/%s' % urllib.parse.quote(ident)
).read()
distro = json.loads(resp)
if os.uname()[4] == 'ppc64':
self.assertEqual(distro['name'], ident)
self.assertEqual(distro['os_distro'], 'fedora')
self.assertEqual(distro['os_version'], '24')
self.assertEqual(distro['os_arch'], 'ppc64le')
self.assertIn('path', distro)
else:
# Distro not found error
if distro.get('reason'):
self.assertIn('KCHDISTRO0001E', distro.get('reason'))
def test_ovsbridges(self):
resp = self.request('/plugins/kimchi/ovsbridges')
self.assertEqual(200, resp.status)
class HttpsRestTests(RestTests):
"""
Run all of the same tests as above, but use https instead
"""
def setUp(self):
self.request = partial(request)
model.reset()
================================================
FILE: tests/test_storagepoolxml.py
================================================
#
# Project Kimchi
#
# Copyright IBM Corp, 2015-2016
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
import unittest
import lxml.etree as ET
from wok.plugins.kimchi.model.libvirtstoragepool import StoragePoolDef
class StoragepoolXMLTests(unittest.TestCase):
def test_get_storagepool_xml(self):
poolDefs = [
{
'def': {
'type': 'dir',
'name': 'unitTestDirPool',
'path': '/var/temp/images',
},
'xml': """
unitTestDirPool/var/temp/images
""",
},
{
'def': {
'type': 'netfs',
'name': 'unitTestNFSPool',
'source': {'host': '127.0.0.1', 'path': '/var/export'},
},
'xml': """
unitTestNFSPool/var/lib/kimchi/nfs_mount/unitTestNFSPool
""",
},
{
'def': {
'type': 'logical',
'name': 'unitTestLogicalPool',
'source': {'devices': ['/dev/hda', '/dev/hdb']},
},
'xml': """
unitTestLogicalPool/dev/unitTestLogicalPool
""",
},
{
'def': {
'type': 'iscsi',
'name': 'unitTestISCSIPool',
'source': {
'host': '127.0.0.1',
'target': 'iqn.2003-01.org.linux-iscsi.localhost',
},
},
'xml': """
unitTestISCSIPool/dev/disk/by-id
""",
},
{
'def': {
'type': 'iscsi',
'name': 'unitTestISCSIPoolPort',
'source': {
'host': '127.0.0.1',
'port': 3266,
'target': 'iqn.2003-01.org.linux-iscsi.localhost',
},
},
'xml': """
unitTestISCSIPoolPort/dev/disk/by-id
""",
},
{
'def': {
'type': 'iscsi',
'name': 'unitTestISCSIPoolAuth',
'source': {
'host': '127.0.0.1',
'target': 'iqn.2003-01.org.linux-iscsi.localhost',
'auth': {
'username': 'testUser',
'password': 'ActuallyNotUsedInPoolXML',
},
},
},
'xml': """
unitTestISCSIPoolAuth/dev/disk/by-id
""",
},
{
'def': {
'type': 'scsi',
'name': 'unitTestSCSIFCPool',
'path': '/dev/disk/by-path',
'source': {
'name': 'scsi_host3',
'adapter': {
'type': 'fc_host',
'wwpn': '0123456789abcdef',
'wwnn': 'abcdef0123456789',
},
},
},
'xml': """
unitTestSCSIFCPool/dev/disk/by-path
""",
},
]
for poolDef in poolDefs:
defObj = StoragePoolDef.create(poolDef['def'])
xmlStr = defObj.xml
parser = ET.XMLParser(remove_blank_text=True)
t1 = ET.fromstring(xmlStr, parser)
t2 = ET.fromstring(poolDef['xml'], parser)
self.assertEqual(ET.tostring(t1), ET.tostring(t2))
================================================
FILE: tests/test_template.py
================================================
# -*- coding: utf-8 -*-
#
# Project Kimchi
#
# Copyright IBM Corp, 2015-2017
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
import json
import os
import unittest
import urllib
from functools import partial
import cherrypy
import iso_gen
import psutil
from wok.plugins.kimchi.config import READONLY_POOL_TYPE
from wok.plugins.kimchi.model.featuretests import FeatureTests
from wok.plugins.kimchi.model.templates import MAX_MEM_LIM
from tests.utils import patch_auth
from tests.utils import request
from tests.utils import run_server
model = None
test_server = None
MOCK_ISO = '/tmp/mock.iso'
DEFAULT_POOL = '/plugins/kimchi/storagepools/default-pool'
def setUpModule():
global test_server, model
patch_auth()
test_server = run_server(test_mode=True)
model = cherrypy.tree.apps['/plugins/kimchi'].root.model
iso_gen.construct_fake_iso(MOCK_ISO, True, '14.04', 'ubuntu')
def tearDownModule():
test_server.stop()
class TemplateTests(unittest.TestCase):
def setUp(self):
self.request = partial(request)
model.reset()
def test_tmpl_lifecycle(self):
resp = self.request('/plugins/kimchi/templates')
self.assertEqual(200, resp.status)
self.assertEqual(0, len(json.loads(resp.read())))
# Create a template without cdrom and disk specified fails with 400
t = {
'name': 'test',
'os_distro': 'ImagineOS',
'os_version': '1.0',
'memory': {'current': 1024},
'cpu_info': {'vcpus': 1},
}
req = json.dumps(t)
resp = self.request('/plugins/kimchi/templates', req, 'POST')
self.assertEqual(400, resp.status)
# Create a netboot template
t = {'name': 'test-netboot', 'source_media': {'type': 'netboot'}}
req = json.dumps(t)
resp = self.request('/plugins/kimchi/templates', req, 'POST')
self.assertEqual(201, resp.status)
# Verify the netboot template
tmpl = json.loads(self.request(
'/plugins/kimchi/templates/test-netboot').read())
self.assertIsNone(tmpl['cdrom'])
# Delete the netboot template
resp = self.request(
'/plugins/kimchi/templates/test-netboot', '{}', 'DELETE')
self.assertEqual(204, resp.status)
# Create a template
t = {'name': 'test', 'source_media': {
'type': 'disk', 'path': MOCK_ISO}}
req = json.dumps(t)
resp = self.request('/plugins/kimchi/templates', req, 'POST')
self.assertEqual(201, resp.status)
# Verify the template
keys = [
'name',
'icon',
'invalid',
'os_distro',
'os_version',
'memory',
'cdrom',
'disks',
'networks',
'folder',
'graphics',
'cpu_info',
]
tmpl = json.loads(self.request(
'/plugins/kimchi/templates/test').read())
if os.uname()[4] == 's390x':
keys.append('interfaces')
self.assertEqual(sorted(tmpl.keys()), sorted(keys))
self.assertEqual(t['source_media']['path'], tmpl['cdrom'])
disk_keys = ['index', 'pool', 'size', 'format']
disk_pool_keys = ['name', 'type']
self.assertEqual(sorted(tmpl['disks'][0].keys()), sorted(disk_keys))
self.assertEqual(
sorted(tmpl['disks'][0]['pool'].keys()), sorted(disk_pool_keys)
)
# Clone a template
resp = self.request(
'/plugins/kimchi/templates/test/clone', '{}', 'POST')
self.assertEqual(303, resp.status)
# Verify the cloned template
tmpl_cloned = json.loads(
self.request('/plugins/kimchi/templates/test-clone1').read()
)
del tmpl['name']
del tmpl_cloned['name']
self.assertEqual(tmpl, tmpl_cloned)
# Delete the cloned template
resp = self.request(
'/plugins/kimchi/templates/test-clone1', '{}', 'DELETE')
self.assertEqual(204, resp.status)
# Create a template with same name fails with 400
req = json.dumps(
{'name': 'test', 'source_media': {'type': 'disk', 'path': MOCK_ISO}}
)
resp = self.request('/plugins/kimchi/templates', req, 'POST')
self.assertEqual(400, resp.status)
# Create an image based template
os.system('qemu-img create -f qcow2 %s 10G' % '/tmp/mock.img')
t = {
'name': 'test_img_template',
'source_media': {'type': 'disk', 'path': '/tmp/mock.img'},
}
req = json.dumps(t)
resp = self.request('/plugins/kimchi/templates', req, 'POST')
self.assertEqual(201, resp.status)
os.remove('/tmp/mock.img')
# Test disk format
t = {
'name': 'test-format',
'source_media': {'type': 'disk', 'path': MOCK_ISO},
'disks': [{'size': 10, 'format': 'vmdk', 'pool': {'name': DEFAULT_POOL}}],
}
req = json.dumps(t)
resp = self.request('/plugins/kimchi/templates', req, 'POST')
self.assertEqual(201, resp.status)
tmpl = json.loads(self.request(
'/plugins/kimchi/templates/test-format').read())
self.assertEqual(tmpl['disks'][0]['format'], 'vmdk')
# Create template with memory higher than host max
if hasattr(psutil, 'virtual_memory'):
max_mem = psutil.virtual_memory().total >> 10 >> 10
else:
max_mem = psutil.TOTAL_PHYMEM >> 10 >> 10
memory = max_mem + 1024
t = {
'name': 'test-maxmem',
'source_media': {'type': 'disk', 'path': MOCK_ISO},
'memory': {'current': memory},
}
req = json.dumps(t)
resp = self.request('/plugins/kimchi/templates', req, 'POST')
self.assertEqual(400, resp.status)
self.assertTrue(str(max_mem) in resp.read().decode('utf-8'))
def test_customized_tmpl(self):
# Create a template
t = {'name': 'test', 'source_media': {
'type': 'disk', 'path': MOCK_ISO}}
req = json.dumps(t)
resp = self.request('/plugins/kimchi/templates', req, 'POST')
self.assertEqual(201, resp.status)
tmpl = json.loads(self.request(
'/plugins/kimchi/templates/test').read())
# Create another template to test update template name with one of
# existing template name
req = json.dumps(
{'name': 'test_new', 'source_media': {
'type': 'disk', 'path': MOCK_ISO}}
)
resp = self.request('/plugins/kimchi/templates', req, 'POST')
self.assertEqual(201, resp.status)
# Update name with one of existing name should fail with 400
req = json.dumps({'name': 'test_new'})
resp = self.request('/plugins/kimchi/templates/test', req, 'PUT')
self.assertEqual(400, resp.status)
# Delete the test1 template
resp = self.request(
'/plugins/kimchi/templates/test_new', '{}', 'DELETE')
self.assertEqual(204, resp.status)
# Update name
new_name = 'kīмсhīTmpl'
new_tmpl_uri = urllib.parse.quote(
f'/plugins/kimchi/templates/{new_name}')
req = json.dumps({'name': new_name})
resp = self.request('/plugins/kimchi/templates/test', req, 'PUT')
self.assertEqual(303, resp.status)
resp = self.request(new_tmpl_uri)
update_tmpl = json.loads(resp.read())
self.assertEqual(new_name, update_tmpl['name'])
del tmpl['name']
del update_tmpl['name']
self.assertEqual(tmpl, update_tmpl)
# Update icon
req = json.dumps({'icon': 'plugins/kimchi/images/icon-fedora.png'})
resp = self.request(new_tmpl_uri, req, 'PUT')
self.assertEqual(200, resp.status)
update_tmpl = json.loads(resp.read())
self.assertEqual(
'plugins/kimchi/images/icon-fedora.png', update_tmpl['icon'])
# Update os_distro and os_version
req = json.dumps({'os_distro': 'fedora', 'os_version': '21'})
resp = self.request(new_tmpl_uri, req, 'PUT')
self.assertEqual(200, resp.status)
update_tmpl = json.loads(resp.read())
self.assertEqual('fedora', update_tmpl['os_distro'])
self.assertEqual('21', update_tmpl['os_version'])
# Update maxvcpus only
req = json.dumps({'cpu_info': {'maxvcpus': 2}})
resp = self.request(new_tmpl_uri, req, 'PUT')
self.assertEqual(200, resp.status)
update_tmpl = json.loads(resp.read())
self.assertEqual(2, update_tmpl['cpu_info']['maxvcpus'])
# Update vcpus only
req = json.dumps({'cpu_info': {'vcpus': 2}})
resp = self.request(new_tmpl_uri, req, 'PUT')
self.assertEqual(200, resp.status)
update_tmpl = json.loads(resp.read())
self.assertEqual(2, update_tmpl['cpu_info']['vcpus'])
# Update cpu_info
cpu_info_data = {
'cpu_info': {
'maxvcpus': 2,
'vcpus': 2,
'topology': {'sockets': 1, 'cores': 2, 'threads': 1},
}
}
resp = self.request(new_tmpl_uri, json.dumps(cpu_info_data), 'PUT')
self.assertEqual(200, resp.status)
update_tmpl = json.loads(resp.read())
self.assertEqual(update_tmpl['cpu_info'], cpu_info_data['cpu_info'])
# Test memory and max memory
# - memory greated than max memory
req = json.dumps({'memory': {'current': 4096}})
resp = self.request(new_tmpl_uri, req, 'PUT')
self.assertEqual(400, resp.status)
# - max memory greater than limit: 16TiB to PPC and 4TiB to x86
req = json.dumps({'memory': {'maxmemory': MAX_MEM_LIM + 1024}})
resp = self.request(new_tmpl_uri, req, 'PUT')
self.assertEqual(400, resp.status)
self.assertTrue('KCHVM0079E' in resp.read().decode('utf-8'))
# - change only max memory
req = json.dumps({'memory': {'maxmemory': 3072}})
resp = self.request(new_tmpl_uri, req, 'PUT')
self.assertEqual(200, resp.status)
update_tmpl = json.loads(resp.read())
self.assertEqual(3072, update_tmpl['memory']['maxmemory'])
# - change only memory
req = json.dumps({'memory': {'current': 2048}})
resp = self.request(new_tmpl_uri, req, 'PUT')
self.assertEqual(200, resp.status)
update_tmpl = json.loads(resp.read())
self.assertEqual(2048, update_tmpl['memory']['current'])
self.assertEqual(3072, update_tmpl['memory']['maxmemory'])
# - change both values
req = json.dumps({'memory': {'current': 1024, 'maxmemory': 1024}})
resp = self.request(new_tmpl_uri, req, 'PUT')
self.assertEqual(200, resp.status)
update_tmpl = json.loads(resp.read())
self.assertEqual(1024, update_tmpl['memory']['current'])
self.assertEqual(1024, update_tmpl['memory']['maxmemory'])
# Update cdrom
cdrom_data = {'cdrom': 'inexistent.iso'}
resp = self.request(new_tmpl_uri, json.dumps(cdrom_data), 'PUT')
self.assertEqual(400, resp.status)
cdrom_data = {'cdrom': '/tmp/existent.iso'}
resp = self.request(new_tmpl_uri, json.dumps(cdrom_data), 'PUT')
self.assertEqual(200, resp.status)
update_tmpl = json.loads(resp.read())
self.assertEqual(update_tmpl['cdrom'], cdrom_data['cdrom'])
# Update disks
disk_data = {
'disks': [
{
'index': 0,
'size': 10,
'format': 'raw',
'pool': {'name': DEFAULT_POOL},
},
{
'index': 1,
'size': 20,
'format': 'qcow2',
'pool': {'name': DEFAULT_POOL},
},
]
}
resp = self.request(new_tmpl_uri, json.dumps(disk_data), 'PUT')
self.assertEqual(200, resp.status)
resp = self.request(new_tmpl_uri)
self.assertEqual(200, resp.status)
updated_tmpl = json.loads(resp.read())
disk_data['disks'][0]['pool'] = {'name': DEFAULT_POOL, 'type': 'dir'}
disk_data['disks'][1]['pool'] = {'name': DEFAULT_POOL, 'type': 'dir'}
self.assertEqual(updated_tmpl['disks'], disk_data['disks'])
# For all supported types, edit the template and check if
# the change was made.
disk_types = ['qcow', 'qcow2', 'qed', 'raw', 'vmdk', 'vpc']
for disk_type in disk_types:
disk_data = {
'disks': [
{
'index': 0,
'format': disk_type,
'size': 10,
'pool': {'name': DEFAULT_POOL},
}
]
}
resp = self.request(new_tmpl_uri, json.dumps(disk_data), 'PUT')
self.assertEqual(200, resp.status)
resp = self.request(new_tmpl_uri)
self.assertEqual(200, resp.status)
updated_tmpl = json.loads(resp.read())
disk_data['disks'][0]['pool'] = {
'name': DEFAULT_POOL, 'type': 'dir'}
self.assertEqual(updated_tmpl['disks'], disk_data['disks'])
# Update folder
folder_data = {'folder': ['mock', 'isos']}
resp = self.request(new_tmpl_uri, json.dumps(folder_data), 'PUT')
self.assertEqual(200, resp.status)
update_tmpl = json.loads(resp.read())
self.assertEqual(update_tmpl['folder'], folder_data['folder'])
# Test graphics merge
req = json.dumps({'graphics': {'type': 'spice'}})
resp = self.request(new_tmpl_uri, req, 'PUT')
self.assertEqual(200, resp.status)
update_tmpl = json.loads(resp.read())
self.assertEqual('spice', update_tmpl['graphics']['type'])
# update only listen (type does not reset to default 'vnc')
req = json.dumps({'graphics': {'listen': 'fe00::0'}})
resp = self.request(new_tmpl_uri, req, 'PUT')
self.assertEqual(200, resp.status)
update_tmpl = json.loads(resp.read())
self.assertEqual('spice', update_tmpl['graphics']['type'])
self.assertEqual('fe00::0', update_tmpl['graphics']['listen'])
# update only type (listen does not reset to default '127.0.0.1')
req = json.dumps({'graphics': {'type': 'vnc'}})
resp = self.request(new_tmpl_uri, req, 'PUT')
self.assertEqual(200, resp.status)
update_tmpl = json.loads(resp.read())
self.assertEqual('vnc', update_tmpl['graphics']['type'])
self.assertEqual('fe00::0', update_tmpl['graphics']['listen'])
def test_customized_network(self):
# Create a template
t = {'name': 'test', 'source_media': {
'type': 'disk', 'path': MOCK_ISO}}
req = json.dumps(t)
resp = self.request('/plugins/kimchi/templates', req, 'POST')
self.assertEqual(201, resp.status)
# Create networks to be used for testing
networks = [
{'name': 'kīмсhī-пet', 'connection': 'isolated'},
{'name': 'nat-network', 'connection': 'nat'},
{'name': 'subnet-network', 'connection': 'nat',
'subnet': '127.0.100.0/24'},
]
# Verify the current system has at least one interface to create a
# bridged network
interfaces = json.loads(
self.request(
'/plugins/kimchi/interfaces?_inuse=false&type=nic').read()
)
if len(interfaces) > 0:
iface = interfaces[0]['name']
networks.append(
{
'name': 'bridge-network',
'connection': 'macvtap',
'interfaces': [iface],
}
)
if not FeatureTests.is_nm_running():
networks.append(
{
'name': 'bridge-network-with-vlan',
'connection': 'bridge',
'interfaces': [iface],
'vlan_id': 987,
}
)
tmpl_nets = []
for net in networks:
self.request('/plugins/kimchi/networks', json.dumps(net), 'POST')
tmpl_nets.append(net['name'])
req = json.dumps({'networks': tmpl_nets})
resp = self.request('/plugins/kimchi/templates/test', req, 'PUT')
self.assertEqual(200, resp.status)
def test_customized_storagepool(self):
# Create a template
t = {'name': 'test', 'source_media': {
'type': 'disk', 'path': MOCK_ISO}}
req = json.dumps(t)
resp = self.request('/plugins/kimchi/templates', req, 'POST')
self.assertEqual(201, resp.status)
# MockModel always returns 2 partitions (vdx, vdz)
partitions = json.loads(self.request(
'/plugins/kimchi/host/partitions').read())
devs = [dev['path'] for dev in partitions]
# MockModel always returns 3 FC devices
fc_devs = json.loads(
self.request('/plugins/kimchi/host/devices?_cap=fc_host').read()
)
fc_devs = [dev['name'] for dev in fc_devs]
poolDefs = [
{
'type': 'dir',
'name': 'kīмсhīUnitTestDirPool',
'path': '/tmp/kimchi-images',
},
{
'type': 'netfs',
'name': 'kīмсhīUnitTestNSFPool',
'source': {'host': 'localhost', 'path': '/var/lib/kimchi/nfs-pool'},
},
{
'type': 'scsi',
'name': 'kīмсhīUnitTestSCSIFCPool',
'source': {'adapter_name': fc_devs[0]},
},
{
'type': 'iscsi',
'name': 'kīмсhīUnitTestISCSIPool',
'source': {
'host': '127.0.0.1',
'target': 'iqn.2015-01.localhost.kimchiUnitTest',
},
},
{
'type': 'logical',
'name': 'kīмсhīUnitTestLogicalPool',
'source': {'devices': [devs[0]]},
},
]
for pool in poolDefs:
resp = self.request(
'/plugins/kimchi/storagepools', json.dumps(pool), 'POST'
)
self.assertEqual(201, resp.status)
pool_uri = urllib.parse.quote(
f"/plugins/kimchi/storagepools/{pool['name']}"
)
resp = self.request(pool_uri + '/activate', '{}', 'POST')
self.assertEqual(200, resp.status)
req = None
unquoted_pool_uri = urllib.parse.unquote(pool_uri)
if pool['type'] in READONLY_POOL_TYPE:
resp = self.request(pool_uri + '/storagevolumes')
vols = json.loads(resp.read())
if len(vols) > 0:
vol = vols[0]['name']
req = json.dumps(
{
'disks': [
{
'volume': vol,
'pool': {'name': unquoted_pool_uri},
'format': 'raw',
}
]
}
)
elif pool['type'] == 'logical':
req = json.dumps(
{
'disks': [
{
'pool': {'name': unquoted_pool_uri},
'format': 'raw',
'size': 10,
}
]
}
)
else:
req = json.dumps(
{
'disks': [
{
'pool': {'name': unquoted_pool_uri},
'format': 'qcow2',
'size': 10,
}
]
}
)
if req is not None:
resp = self.request(
'/plugins/kimchi/templates/test', req, 'PUT')
self.assertEqual(200, resp.status)
# Test disk template update with different pool
pool_uri = '/plugins/kimchi/storagepools/kīмсhīUnitTestDirPool'
disk_data = {
'disks': [{'size': 5, 'format': 'qcow2', 'pool': {'name': pool_uri}}]
}
req = json.dumps(disk_data)
resp = self.request('/plugins/kimchi/templates/test', req, 'PUT')
self.assertEqual(200, resp.status)
del disk_data['disks'][0]['pool']
disk_data['disks'][0]['index'] = 0
disk_data['disks'][0]['pool'] = {'name': pool_uri, 'type': 'dir'}
tmpl = json.loads(self.request(
'/plugins/kimchi/templates/test').read())
self.assertListEqual(
sorted(disk_data['disks'][0].keys()), sorted(
tmpl['disks'][0].keys())
)
self.assertListEqual(
list(disk_data['disks'][0].values()), list(
tmpl['disks'][0].values())
)
def test_tmpl_integrity(self):
mock_iso2 = '/tmp/mock2.iso'
iso_gen.construct_fake_iso(mock_iso2, True, '14.04', 'ubuntu')
# Create a network and a pool for testing template integrity
net = {'name': 'nat-network', 'connection': 'nat'}
resp = self.request('/plugins/kimchi/networks',
json.dumps(net), 'POST')
self.assertEqual(201, resp.status)
pool = {'type': 'dir', 'name': 'dir-pool', 'path': '/tmp/dir-pool'}
resp = self.request('/plugins/kimchi/storagepools',
json.dumps(pool), 'POST')
self.assertEqual(201, resp.status)
pool_uri = f"/plugins/kimchi/storagepools/{pool['name']}"
resp = self.request(pool_uri + '/activate', '{}', 'POST')
self.assertEqual(200, resp.status)
# Create a template using the custom network and pool
t = {
'name': 'test',
'source_media': {'type': 'disk', 'path': mock_iso2},
'networks': ['nat-network'],
'disks': [
{
'pool': {'name': '/plugins/kimchi/storagepools/dir-pool'},
'size': 2,
'format': 'qcow2',
}
],
}
req = json.dumps(t)
resp = self.request('/plugins/kimchi/templates', req, 'POST')
self.assertEqual(201, resp.status)
# Try to delete network
# It should fail as it is associated to a template
resp = self.request(
'/plugins/kimchi/networks/nat-network', '{}', 'DELETE')
self.assertIn('KCHNET0017E', json.loads(resp.read())['reason'])
# Update template to release network and then delete it
params = {'networks': []}
req = json.dumps(params)
self.request('/plugins/kimchi/templates/test', req, 'PUT')
resp = self.request(
'/plugins/kimchi/networks/nat-network', '{}', 'DELETE')
self.assertEqual(204, resp.status)
# Try to delete the storagepool
# It should fail as it is associated to a template
resp = self.request(
'/plugins/kimchi/storagepools/dir-pool', '{}', 'DELETE')
self.assertEqual(400, resp.status)
# Verify the template
os.remove(mock_iso2)
res = json.loads(self.request('/plugins/kimchi/templates/test').read())
self.assertEqual(res['invalid']['cdrom'], [mock_iso2])
================================================
FILE: tests/test_vmtemplate.py
================================================
#
# Project Kimchi
#
# Copyright IBM Corp, 2013-2016
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
import os
import unittest
import uuid
import iso_gen
import psutil
from wok.plugins.kimchi.osinfo import get_template_default
from wok.plugins.kimchi.osinfo import MEM_DEV_SLOTS
from wok.plugins.kimchi.vmtemplate import VMTemplate
from wok.xmlutils.utils import xpath_get_text
DISKS = [
{
'size': 10,
'format': 'raw',
'index': 0,
'pool': {'name': '/plugins/kimchi/storagepools/default-pool'},
},
{
'size': 5,
'format': 'qcow2',
'index': 1,
'pool': {'name': '/plugins/kimchi/storagepools/default-pool'},
},
]
class VMTemplateTests(unittest.TestCase):
def setUp(self):
self.iso = '/tmp/mock.iso'
iso_gen.construct_fake_iso(self.iso, True, '12.04', 'ubuntu')
def tearDown(self):
os.unlink(self.iso)
def test_minimal_construct(self):
disk_bus = get_template_default('old', 'disk_bus')
memory = get_template_default('old', 'memory')
nic_model = get_template_default('old', 'nic_model')
fields = (
('name', 'test'),
('cdrom', self.iso),
('os_distro', 'unknown'),
('os_version', 'unknown'),
('cpu_info', {'vcpus': 1, 'maxvcpus': 1}),
('memory', memory),
('networks', ['default']),
('disk_bus', disk_bus),
('nic_model', nic_model),
('graphics', {'type': 'vnc', 'listen': '127.0.0.1'}),
)
args = {'name': 'test', 'cdrom': self.iso}
t = VMTemplate(args)
for name, val in fields:
if os.uname()[4] == 's390x' and name == 'networks':
continue
self.assertEqual(val, t.info.get(name))
def test_construct_overrides(self):
graphics = {'type': 'spice', 'listen': '127.0.0.1'}
args = {'name': 'test', 'disks': DISKS,
'graphics': graphics, 'cdrom': self.iso}
t = VMTemplate(args)
self.assertEqual(2, len(t.info['disks']))
self.assertEqual(graphics, t.info['graphics'])
def test_specified_graphics(self):
# Test specified listen
graphics = {'type': 'vnc', 'listen': '127.0.0.1'}
args = {'name': 'test', 'disks': DISKS,
'graphics': graphics, 'cdrom': self.iso}
t = VMTemplate(args)
self.assertEqual(graphics, t.info['graphics'])
# Test specified type
graphics = {'type': 'spice', 'listen': '127.0.0.1'}
args['graphics'] = graphics
t = VMTemplate(args)
self.assertEqual(graphics, t.info['graphics'])
# If no listen specified, test the default listen
graphics = {'type': 'vnc'}
args['graphics'] = graphics
t = VMTemplate(args)
self.assertEqual(graphics['type'], t.info['graphics']['type'])
self.assertEqual('127.0.0.1', t.info['graphics']['listen'])
def test_mem_dev_slots(self):
vm_uuid = str(uuid.uuid4()).replace('-', '')
t = VMTemplate(
{
'name': 'test-template',
'cdrom': self.iso,
'memory': {'current': 2048, 'maxmemory': 3072},
}
)
xml = t.to_vm_xml('test-vm', vm_uuid)
expr = '/domain/maxMemory/@slots'
slots = str(MEM_DEV_SLOTS[os.uname()[4]])
self.assertEqual(slots, xpath_get_text(xml, expr)[0])
def test_to_xml(self):
if not os.uname()[4] == 's390x':
graphics = {'type': 'spice', 'listen': '127.0.0.1'}
else:
graphics = {'type': 'vnc', 'listen': '127.0.0.1'}
vm_uuid = str(uuid.uuid4()).replace('-', '')
t = VMTemplate({'name': 'test-template', 'cdrom': self.iso})
xml = t.to_vm_xml('test-vm', vm_uuid, graphics=graphics)
self.assertEqual(vm_uuid, xpath_get_text(xml, '/domain/uuid')[0])
self.assertEqual('test-vm', xpath_get_text(xml, '/domain/name')[0])
if not os.uname()[4] == 's390x':
expr = '/domain/devices/graphics/@type'
self.assertEqual(graphics['type'], xpath_get_text(xml, expr)[0])
expr = '/domain/devices/graphics/@listen'
self.assertEqual(graphics['listen'], xpath_get_text(xml, expr)[0])
expr = '/domain/maxMemory/@slots'
# The default is memory and maxmemory have the same value, so
# max memory tag is not set
self.assertEqual(0, len(xpath_get_text(xml, expr)))
expr = '/domain/memory'
self.assertEqual(str(2048), xpath_get_text(xml, expr)[0])
if hasattr(psutil, 'virtual_memory'):
host_memory = psutil.virtual_memory().total >> 10
else:
host_memory = psutil.TOTAL_PHYMEM >> 10
t = VMTemplate(
{
'name': 'test-template',
'cdrom': self.iso,
'memory': {'current': (host_memory >> 10) - 512},
}
)
try:
xml = t.to_vm_xml('test-vm', vm_uuid, graphics=graphics)
except Exception as e:
# Test current memory greater than maxmemory (1024/default)
self.assertTrue('KCHVM0041E' in str(e))
def test_arg_merging(self):
"""
Make sure that default parameters from osinfo do not override user-
provided parameters.
"""
graphics = {'type': 'vnc', 'listen': '127.0.0.1'}
args = {
'name': 'test',
'os_distro': 'opensuse',
'os_version': '12.3',
'cpu_info': {'vcpus': 2, 'maxvcpus': 4},
'memory': {'current': 2048, 'maxmemory': 3072},
'networks': ['foo'],
'cdrom': self.iso,
'graphics': graphics,
}
t = VMTemplate(args)
self.assertEqual(2, t.info.get('cpu_info', {}).get('vcpus'))
self.assertEqual(4, t.info.get('cpu_info', {}).get('maxvcpus'))
self.assertEqual(2048, t.info.get('memory').get('current'))
self.assertEqual(3072, t.info.get('memory').get('maxmemory'))
self.assertEqual(['foo'], t.info.get('networks'))
self.assertEqual(self.iso, t.info.get('cdrom'))
self.assertEqual(graphics, t.info.get('graphics'))
def test_netboot_vmtemplate(self):
disk_bus = get_template_default('old', 'disk_bus')
memory = get_template_default('old', 'memory')
nic_model = get_template_default('old', 'nic_model')
fields = (
('name', 'test'),
('os_distro', 'unknown'),
('os_version', 'unknown'),
('cpu_info', {'vcpus': 1, 'maxvcpus': 1}),
('memory', memory),
('networks', ['default']),
('disk_bus', disk_bus),
('nic_model', nic_model),
('graphics', {'type': 'vnc', 'listen': '127.0.0.1'}),
)
t = VMTemplate({'name': 'test'}, netboot=True)
for name, val in fields:
if os.uname()[4] == 's390x' and name == 'networks':
continue
self.assertEqual(val, t.info.get(name))
self.assertNotIn('cdrom', t.info.keys())
================================================
FILE: ui/Makefile.am
================================================
#
# Kimchi
#
# Copyright IBM Corp, 2013-2016
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
SUBDIRS = config css images js pages spice-html5 spice-web-client serial
uidir = $(datadir)/wok/plugins/kimchi/ui
================================================
FILE: ui/config/Makefile.am
================================================
#
# Kimchi
#
# Copyright IBM Corp, 2015-2016
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
xmldir = $(datadir)/wok/plugins/kimchi/ui/config
dist_xml_DATA = \
tab-ext.xml \
$(NULL)
================================================
FILE: ui/config/tab-ext.xml
================================================
VirtualizationGuestsplugins/kimchi/tabs/guests.html35Templatesplugins/kimchi/tabs/templates.html40Storageplugins/kimchi/tabs/storage.html45Networkplugins/kimchi/tabs/network.html50
================================================
FILE: ui/css/Makefile.am
================================================
#
# Kimchi
#
# Copyright IBM Corp, 2013-2016
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
cssdir = $(datadir)/wok/plugins/kimchi/ui/css
dist_css_DATA = kimchi.css
css: src/*.scss src/modules/*.scss
echo "Compiling .scss file $<"
sassc -s expanded $< kimchi.css
================================================
FILE: ui/css/kimchi.css
================================================
/*
* Project Kimchi
*
* Copyright IBM Corp, 2015-2016
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* A partial implementation of the Ruby list functions from Compass:
* https://github.com/Compass/compass/blob/stable/lib/compass/sass_extensions/functions/lists.rb
*/
/*
* A partial implementation of the Ruby constants functions from Compass:
* https://github.com/Compass/compass/blob/stable/lib/compass/sass_extensions/functions/constants.rb
*/
/*
* A partial implementation of the Ruby display functions from Compass:
* https://github.com/Compass/compass/blob/stable/core/lib/compass/core/sass_extensions/functions/display.rb
*/
.absolute-middle {
margin: auto;
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
text-align: center;
}
.animate-spin {
-webkit-animation: spin 2s infinite linear;
-o-animation: spin 2s infinite linear;
animation: spin 2s infinite linear;
display: inline-block;
}
@keyframes spin {
0% {
-webkit-transform: rotate(0deg);
-moz-transform: rotate(0deg);
-ms-transform: rotate(0deg);
-o-transform: rotate(0deg);
transform: rotate(0deg);
}
100% {
-webkit-transform: rotate(359deg);
-moz-transform: rotate(359deg);
-ms-transform: rotate(359deg);
-o-transform: rotate(359deg);
transform: rotate(359deg);
}
}
.delayed-fadein {
-webkit-animation: fadein 2s;
-o-animation: fadein 2s;
animation: fadein 2s;
}
@keyframes fadein {
0% {
opacity: 0;
}
20% {
opacity: 0;
}
100% {
opacity: 1;
}
}
/* Template & Guests Modal Windows */
#template-add-window.modal-content label.box-iso-outer,
#guest-add-window.modal-content label.box-iso-outer {
font-family: Helvetica, Arial, "Lucida Grande", sans-serif;
font-size: 14px !important;
font-weight: 400;
border-radius: 3px;
overflow: hidden;
display: block;
-webkit-user-select: none;
user-select: none;
}
#template-add-window.modal-content label.box-iso-outer span.box-iso-border,
#guest-add-window.modal-content label.box-iso-outer span.box-iso-border {
display: block;
border: 3px solid transparent;
transition: all .1s ease-in-out;
}
#template-add-window.modal-content label.box-iso-outer .iso-radio-hidden:checked + span.box-iso-border,
#template-add-window.modal-content label.box-iso-outer .iso-checkbox-hidden:checked + span.box-iso-border,
#guest-add-window.modal-content label.box-iso-outer .iso-radio-hidden:checked + span.box-iso-border,
#guest-add-window.modal-content label.box-iso-outer .iso-checkbox-hidden:checked + span.box-iso-border {
border-color: #8cc63f;
}
#template-add-window.modal-content label.box-iso-outer .iso-radio-hidden:checked + span.box-iso-border > .box-iso-inner,
#template-add-window.modal-content label.box-iso-outer .iso-checkbox-hidden:checked + span.box-iso-border > .box-iso-inner,
#guest-add-window.modal-content label.box-iso-outer .iso-radio-hidden:checked + span.box-iso-border > .box-iso-inner,
#guest-add-window.modal-content label.box-iso-outer .iso-checkbox-hidden:checked + span.box-iso-border > .box-iso-inner {
border-color: #000;
}
#template-add-window.modal-content label.box-iso-outer span.box-iso-inner,
#guest-add-window.modal-content label.box-iso-outer span.box-iso-inner {
display: block;
border: 1px solid transparent;
background: #fff;
transition: all .1s ease-in-out;
}
#template-add-window.modal-content label.box-iso-outer span.box-iso-inner .tooltip-inner,
#guest-add-window.modal-content label.box-iso-outer span.box-iso-inner .tooltip-inner {
font-size: 10pt;
padding: 6px 8px;
}
#template-add-window.modal-content label.box-iso-outer span.box-iso-inner .tooltip-inner,
#guest-add-window.modal-content label.box-iso-outer span.box-iso-inner .tooltip-inner {
max-width: 300px;
}
#template-add-window.modal-content label.box-iso-outer span.box-iso-inner .tooltip[style],
#guest-add-window.modal-content label.box-iso-outer span.box-iso-inner .tooltip[style] {
left: 7px !important;
right: 7px !important;
}
#template-add-window.modal-content label.box-iso-outer span.box-iso-inner .tooltip-arrow[style],
#guest-add-window.modal-content label.box-iso-outer span.box-iso-inner .tooltip-arrow[style] {
left: 216px !important;
}
#template-add-window.modal-content li[data-invalid="invalid"] label.box-iso-outer,
#guest-add-window.modal-content li[data-invalid="invalid"] label.box-iso-outer {
color: #999 !important;
}
#template-add-window.modal-content li[data-invalid="invalid"] label.box-iso-outer span.box-iso-inner,
#guest-add-window.modal-content li[data-invalid="invalid"] label.box-iso-outer span.box-iso-inner {
background: rgba(255, 255, 255, 0.4);
}
#template-add-window.modal-content ul.list-template,
#template-add-window.modal-content ul.list-iso,
#guest-add-window.modal-content ul.list-template,
#guest-add-window.modal-content ul.list-iso {
display: block;
overflow-x: hidden;
overflow-y: auto;
max-height: 462px;
list-style: none;
margin: 0 -5px 10px -5px;
padding: 0;
}
#template-add-window.modal-content label.box-iso-outer span.box-iso-inner dl,
#guest-add-window.modal-content label.box-iso-outer span.box-iso-inner dl {
margin-bottom: 16px;
}
#template-add-window.modal-content label.box-iso-outer span.box-iso-inner dt,
#template-add-window.modal-content label.box-iso-outer span.box-iso-inner dd,
#guest-add-window.modal-content label.box-iso-outer span.box-iso-inner dt,
#guest-add-window.modal-content label.box-iso-outer span.box-iso-inner dd {
padding: 0 12px 0 20px;
}
#template-add-window.modal-content label.box-iso-outer span.box-iso-inner dt,
#guest-add-window.modal-content label.box-iso-outer span.box-iso-inner dt {
padding-top: 5px;
text-transform: capitalize;
}
#template-add-window.modal-content label.box-iso-outer span.box-iso-inner dd,
#guest-add-window.modal-content label.box-iso-outer span.box-iso-inner dd {
padding-bottom: 5px;
}
#template-add-window.modal-content ul#templateTile input[type="radio"].iso-radio-hidden,
#template-add-window.modal-content ul#list-local-iso input[type="checkbox"].iso-checkbox-hidden,
#template-add-window.modal-content ul#list-remote-iso input[type="checkbox"].iso-checkbox-hidden,
#guest-add-window.modal-content ul#templateTile input[type="radio"].iso-radio-hidden,
#guest-add-window.modal-content ul#list-local-iso input[type="checkbox"].iso-checkbox-hidden,
#guest-add-window.modal-content ul#list-remote-iso input[type="checkbox"].iso-checkbox-hidden {
display: none;
}
#template-add-window.modal-content label.box-iso-outer,
#guest-add-window.modal-content label.box-iso-outer {
cursor: pointer;
}
#template-add-window.modal-content ul#list-local-iso li.col-md-3,
#template-add-window.modal-content ul#list-remote-iso li.col-md-3,
#guest-add-window.modal-content ul#list-local-iso li.col-md-3,
#guest-add-window.modal-content ul#list-remote-iso li.col-md-3 {
width: 239px;
margin: 10px 5px 0;
}
#template-add-window.modal-content h3.iso-title,
#guest-add-window.modal-content h3.iso-title {
font-size: 22px;
font-weight: 300;
line-height: 22px;
margin: 0;
padding: 13px 40px 13px 20px;
background-color: transparent;
background-position: right 10px center;
background-repeat: no-repeat;
background-size: auto 27px;
background-origin: padding-box;
max-width: 100%;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
#template-add-window.modal-content h3.iso-title.centos,
#guest-add-window.modal-content h3.iso-title.centos {
background-image: url("../images/icon-centos.png");
}
#template-add-window.modal-content h3.iso-title.debian,
#guest-add-window.modal-content h3.iso-title.debian {
background-image: url("../images/icon-debian.png");
}
#template-add-window.modal-content h3.iso-title.fedora,
#guest-add-window.modal-content h3.iso-title.fedora {
background-image: url("../images/icon-fedora.png");
}
#template-add-window.modal-content h3.iso-title.opensuse,
#guest-add-window.modal-content h3.iso-title.opensuse {
background-image: url("../images/icon-opensuse.png");
}
#template-add-window.modal-content h3.iso-title.sles,
#guest-add-window.modal-content h3.iso-title.sles {
background-image: url("../images/icon-sles.png");
}
#template-add-window.modal-content h3.iso-title.ubuntu,
#guest-add-window.modal-content h3.iso-title.ubuntu {
background-image: url("../images/icon-ubuntu.png");
}
#template-add-window.modal-content h3.iso-title.gentoo,
#guest-add-window.modal-content h3.iso-title.gentoo {
background-image: url("../images/icon-gentoo.png");
}
#template-add-window.modal-content h3.iso-title.unknown,
#guest-add-window.modal-content h3.iso-title.unknown {
background-image: url("../images/icon-vm.png");
}
/* Create Guest Modal */
.guests-modal .modal-dialog {
width: 1100px;
}
.guests-modal .page-list {
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
overflow: hidden;
}
.guests-modal .page {
position: absolute;
left: 0;
width: 100%;
height: 100%;
overflow: auto;
padding: 10px 30px;
}
.guests-modal .template-status {
position: absolute;
right: 15px;
bottom: 15px;
font-size: 32px;
}
#wok-confirm-modal .modal-body strong,
.modal-dialog .modal-body strong {
border-bottom: 1px dotted;
}
#guest-add-window .modal-body {
margin: 0;
padding: 0;
}
#guest-add-window .modal-footer {
margin-top: 0;
}
#guest-add-window .modal-footer .btn + .btn {
margin-left: 0;
}
#guest-add-window .modal-footer .btn {
margin-right: 5px;
}
#guest-add-window .modal-dialog {
width: 900px;
}
#guest-add-window .guest-modal-container {
padding: 10px 30px;
position: relative;
}
#guest-add-window .guest-pager {
background: #eee;
overflow: hidden;
position: relative;
height: 530px;
}
#guest-add-window.modal-content p {
margin: 0 0 10px 0;
}
#guest-add-window.modal-content h5 {
font-size: 13pt;
font-weight: 400;
margin-top: 0;
}
#guest-add-window.modal-content label {
font-size: 16px;
font-weight: 400;
font-family: Helvetica, Arial, "Lucida Grande", sans-serif;
}
#guest-add-window form#form-vm-add {
margin: 0;
}
#guest-add-window input#guest-vm-name,
#guest-add-window p.help-block {
width: 592px;
}
#guest-content-container .wok-guest-list {
display: block;
width: 100%;
padding: 0;
list-style-type: none;
}
#guest-content-container .wok-guest-list .wok-guest-list-body > ul {
list-style: none;
padding: 0;
}
#guest-content-container .wok-guest-list .wok-guest-list-body > ul > li:nth-child(even) {
background-color: #fcfcfc;
}
#guest-content-container .wok-guest-list .wok-guest-list-body > ul > li:nth-child(odd) {
background-color: #fff;
}
#guest-content-container .wok-guest-list .wok-guest-list-body > ul > li:first-child {
border-top: 0;
}
#guest-content-container .wok-guest-list .wok-guest-list-header {
border-top: 0 none;
height: 36px;
}
#guest-content-container .wok-guest-list .wok-guest-list-header > span {
height: 36px;
padding: 6px 2px;
display: inline-block;
vertical-align: middle;
font-family: Helvetica, Arial, "Lucida Grande", sans-serif;
font-weight: 300;
font-size: 12.5pt;
line-height: 1.42857;
border-bottom: none;
border-top: 0;
overflow: hidden;
}
#guest-content-container .wok-guest-list .wok-guest-list-header > span > span {
width: 100%;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
display: block;
}
#guest-content-container .wok-guest-list .wok-guest-list-item {
border-top: 1px solid #eee;
}
#guest-content-container .wok-guest-list .wok-guest-list-item > span {
padding: 6px 2px;
display: inline-block;
vertical-align: middle;
font-family: Helvetica, Arial, "Lucida Grande", sans-serif;
font-size: 12.5pt;
line-height: 2.42857;
font-weight: 400;
}
#guest-content-container .wok-guest-list .wok-guest-list-item .nodata,
#guest-content-container .wok-guest-list .wok-guest-list-item .screenshot {
display: none;
}
#guest-content-container .wok-guest-list .wok-guest-list-item .column-name.distro-icon {
background: none;
}
#guest-content-container .wok-guest-list .wok-guest-list-item .progress {
display: inline-block;
width: 60%;
position: relative;
vertical-align: top;
margin-top: 15px;
border-radius: 0;
-webkit-box-shadow: none;
box-shadow: none;
}
#guest-content-container .wok-guest-list .wok-guest-list-item .progress-bar {
position: absolute;
top: 0;
left: 0;
-webkit-box-shadow: none;
box-shadow: none;
}
#guest-content-container .wok-guest-list .wok-guest-list-item .progress-bar.dark-grey {
background-color: #929497;
}
#guest-content-container .wok-guest-list .wok-guest-list-item .progress-bar.medium-grey {
background-color: #bbbdbf;
}
#guest-content-container .wok-guest-list .wok-guest-list-item .progress-bar.light-grey {
background-color: #e6e7e8;
}
#guest-content-container .wok-guest-list .wok-guest-list-item .column-type {
padding-left: 40px;
}
#guest-content-container .wok-guest-list .wok-guest-list-item .column-actions .btn {
margin-top: 6px;
}
#guest-content-container .wok-guest-list .wok-guest-list-item div.percentage-label {
display: inline-block;
width: 25%;
margin-top: 6px;
}
#guest-content-container .wok-guest-list .wok-guest-list-item div.measure-label {
display: inline-block;
width: 35%;
margin-top: 6px;
}
#guest-content-container .wok-guest-list .wok-guest-list-item .item-hidden {
display: none;
}
#guest-content-container .wok-guest-list .wok-guest-list-item .btn .guest-state {
display: none;
}
#guest-content-container .wok-guest-gallery {
list-style: none;
padding: 0 0 0 5px;
}
#guest-content-container .wok-guest-gallery > li.wok-guest-list-header {
display: none;
}
#guest-content-container .wok-guest-gallery > li > ul {
list-style: none;
padding: 0;
}
#guest-content-container .wok-guest-gallery .wok-guest-list-item {
padding: 0;
width: 290px;
height: 435px;
display: inline-block;
border: 0;
background: #fff;
margin-right: 20px;
margin-bottom: 20px;
position: relative;
vertical-align: top;
}
#guest-content-container .wok-guest-gallery .wok-guest-list-item.inactive .progress,
#guest-content-container .wok-guest-gallery .wok-guest-list-item.inactive .item-hidden,
#guest-content-container .wok-guest-gallery .wok-guest-list-item.inactive [class^="column-"] {
display: none;
}
#guest-content-container .wok-guest-gallery .wok-guest-list-item.inactive .nodata {
display: block;
padding-top: 115px;
padding-bottom: 115px;
text-align: center;
}
#guest-content-container .wok-guest-gallery .wok-guest-list-item.inactive span.column-action,
#guest-content-container .wok-guest-gallery .wok-guest-list-item.inactive span.column-name {
display: block !important;
}
#guest-content-container .wok-guest-gallery .wok-guest-list-item.inactive .btn {
background: #4d4c4e !important;
}
#guest-content-container .wok-guest-gallery .wok-guest-list-item > span {
display: inline-block;
width: 100%;
font-family: Helvetica, Arial, "Lucida Grande", sans-serif;
font-size: 12.5pt;
line-height: 1.42857;
font-weight: 400;
}
#guest-content-container .wok-guest-gallery .wok-guest-list-item .progress {
display: block;
float: right;
width: 125px;
height: 18px;
position: relative;
vertical-align: top;
margin-top: 0;
margin-bottom: 0;
border-radius: 0;
-webkit-box-shadow: none;
box-shadow: none;
}
#guest-content-container .wok-guest-gallery .wok-guest-list-item .progress-bar {
position: absolute;
top: 0;
left: 0;
-webkit-box-shadow: none;
box-shadow: none;
}
#guest-content-container .wok-guest-gallery .wok-guest-list-item .progress-bar.dark-grey {
background-color: #929497;
}
#guest-content-container .wok-guest-gallery .wok-guest-list-item .progress-bar.medium-grey {
background-color: #bbbdbf;
}
#guest-content-container .wok-guest-gallery .wok-guest-list-item .progress-bar.light-grey {
background-color: #e6e7e8;
}
#guest-content-container .wok-guest-gallery .wok-guest-list-item .item-hidden {
clear: both;
display: block;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
position: relative;
top: -10px;
}
#guest-content-container .wok-guest-gallery .wok-guest-list-item .column-action.pull-right {
position: absolute;
}
#guest-content-container .wok-guest-gallery .wok-guest-list-item .ul-body {
display: inline-block;
padding: 0;
margin: 0;
list-style: none;
}
#guest-content-container .wok-guest-gallery .wok-guest-list-item .column-type,
#guest-content-container .wok-guest-gallery .wok-guest-list-item .nodata,
#guest-content-container .wok-guest-gallery .wok-guest-list-item .column-vnc,
#guest-content-container .wok-guest-gallery .wok-guest-list-item .column-state {
display: none;
}
#guest-content-container .wok-guest-gallery .wok-guest-list-item .column-name {
line-height: 2.5 !important;
font-size: 15.3pt !important;
font-weight: 500 !important;
text-overflow: ellipsis !important;
overflow: hidden !important;
padding-right: 35px !important;
padding-left: 20px;
margin-right: 20px;
display: block;
width: 290px;
white-space: nowrap;
cursor: default;
}
#guest-content-container .wok-guest-gallery .wok-guest-list-item .column-processors,
#guest-content-container .wok-guest-gallery .wok-guest-list-item .column-memory,
#guest-content-container .wok-guest-gallery .wok-guest-list-item .column-storage,
#guest-content-container .wok-guest-gallery .wok-guest-list-item .column-network {
margin-top: 14px;
display: block;
height: 38px;
padding-left: 20px;
padding-right: 18px;
}
#guest-content-container .wok-guest-gallery .wok-guest-list-item .column-processors {
margin-top: 18px !important;
}
#guest-content-container .wok-guest-gallery .wok-guest-list-item .percentage-label,
#guest-content-container .wok-guest-gallery .wok-guest-list-item .measure-label {
float: left;
display: block;
width: 68px;
font-size: 21px;
font-weight: 600;
top: -7px;
position: relative;
}
#guest-content-container .wok-guest-gallery .wok-guest-list-item .font-bold {
font-weight: bold !important;
}
#guest-content-container .wok-guest-gallery .wok-guest-list-item .pull-right {
float: none !important;
}
#guest-content-container .wok-guest-gallery .wok-guest-list-item .dropdown-menu {
width: 100%;
}
#guest-content-container .wok-guest-gallery .wok-guest-list-item .screenshot {
width: 100%;
height: 148px;
background-size: cover;
background-repeat: no-repeat;
}
#guest-content-container .wok-guest-gallery .wok-guest-list-item .menu-flat {
width: 290px;
}
#guest-content-container .wok-guest-gallery .wok-guest-list-item .btn {
width: 100%;
text-align: left;
padding-left: 21px;
border-radius: 0;
background: rgba(0, 0, 0, 0.6) !important;
}
#guest-content-container .wok-guest-gallery .wok-guest-list-item .btn > span.guest-state .fa {
margin-right: 10px;
}
#guest-content-container .wok-guest-gallery .wok-guest-list-item .btn > span.guest-state.running span.running {
display: block;
}
#guest-content-container .wok-guest-gallery .wok-guest-list-item .btn > span.guest-state.running span.shutoff,
#guest-content-container .wok-guest-gallery .wok-guest-list-item .btn > span.guest-state.running span.starting,
#guest-content-container .wok-guest-gallery .wok-guest-list-item .btn > span.guest-state.running span.crashed,
#guest-content-container .wok-guest-gallery .wok-guest-list-item .btn > span.guest-state.running span.nostate,
#guest-content-container .wok-guest-gallery .wok-guest-list-item .btn > span.guest-state.running span.paused,
#guest-content-container .wok-guest-gallery .wok-guest-list-item .btn > span.guest-state.running span.pmsuspended,
#guest-content-container .wok-guest-gallery .wok-guest-list-item .btn > span.guest-state.running span.resetting {
display: none;
}
#guest-content-container .wok-guest-gallery .wok-guest-list-item .btn > span.guest-state.shutoff span.shutoff {
display: block;
}
#guest-content-container .wok-guest-gallery .wok-guest-list-item .btn > span.guest-state.shutoff span.running,
#guest-content-container .wok-guest-gallery .wok-guest-list-item .btn > span.guest-state.shutoff span.starting,
#guest-content-container .wok-guest-gallery .wok-guest-list-item .btn > span.guest-state.shutoff span.crashed,
#guest-content-container .wok-guest-gallery .wok-guest-list-item .btn > span.guest-state.shutoff span.nostate,
#guest-content-container .wok-guest-gallery .wok-guest-list-item .btn > span.guest-state.shutoff span.paused,
#guest-content-container .wok-guest-gallery .wok-guest-list-item .btn > span.guest-state.shutoff span.pmsuspended,
#guest-content-container .wok-guest-gallery .wok-guest-list-item .btn > span.guest-state.shutoff span.resetting {
display: none;
}
#guest-content-container .wok-guest-gallery .wok-guest-list-item .btn > span.guest-state.starting span.starting {
display: block;
}
#guest-content-container .wok-guest-gallery .wok-guest-list-item .btn > span.guest-state.starting span.running,
#guest-content-container .wok-guest-gallery .wok-guest-list-item .btn > span.guest-state.starting span.shutoff,
#guest-content-container .wok-guest-gallery .wok-guest-list-item .btn > span.guest-state.starting span.crashed,
#guest-content-container .wok-guest-gallery .wok-guest-list-item .btn > span.guest-state.starting span.nostate,
#guest-content-container .wok-guest-gallery .wok-guest-list-item .btn > span.guest-state.starting span.paused,
#guest-content-container .wok-guest-gallery .wok-guest-list-item .btn > span.guest-state.starting span.pmsuspended,
#guest-content-container .wok-guest-gallery .wok-guest-list-item .btn > span.guest-state.starting span.resetting {
display: none;
}
#guest-content-container .wok-guest-gallery .wok-guest-list-item .btn > span.guest-state.crashed span.crashed {
display: block;
}
#guest-content-container .wok-guest-gallery .wok-guest-list-item .btn > span.guest-state.crashed span.running,
#guest-content-container .wok-guest-gallery .wok-guest-list-item .btn > span.guest-state.crashed span.shutoff,
#guest-content-container .wok-guest-gallery .wok-guest-list-item .btn > span.guest-state.crashed span.starting,
#guest-content-container .wok-guest-gallery .wok-guest-list-item .btn > span.guest-state.crashed span.nostate,
#guest-content-container .wok-guest-gallery .wok-guest-list-item .btn > span.guest-state.crashed span.paused,
#guest-content-container .wok-guest-gallery .wok-guest-list-item .btn > span.guest-state.crashed span.pmsuspended,
#guest-content-container .wok-guest-gallery .wok-guest-list-item .btn > span.guest-state.crashed span.resetting {
display: none;
}
#guest-content-container .wok-guest-gallery .wok-guest-list-item .btn > span.guest-state.nostate span.nostate {
display: block;
}
#guest-content-container .wok-guest-gallery .wok-guest-list-item .btn > span.guest-state.nostate span.running,
#guest-content-container .wok-guest-gallery .wok-guest-list-item .btn > span.guest-state.nostate span.shutoff,
#guest-content-container .wok-guest-gallery .wok-guest-list-item .btn > span.guest-state.nostate span.starting,
#guest-content-container .wok-guest-gallery .wok-guest-list-item .btn > span.guest-state.nostate span.crashed,
#guest-content-container .wok-guest-gallery .wok-guest-list-item .btn > span.guest-state.nostate span.paused,
#guest-content-container .wok-guest-gallery .wok-guest-list-item .btn > span.guest-state.nostate span.pmsuspended,
#guest-content-container .wok-guest-gallery .wok-guest-list-item .btn > span.guest-state.nostate span.resetting {
display: none;
}
#guest-content-container .wok-guest-gallery .wok-guest-list-item .btn > span.guest-state.paused span.paused {
display: block;
}
#guest-content-container .wok-guest-gallery .wok-guest-list-item .btn > span.guest-state.paused span.running,
#guest-content-container .wok-guest-gallery .wok-guest-list-item .btn > span.guest-state.paused span.shutoff,
#guest-content-container .wok-guest-gallery .wok-guest-list-item .btn > span.guest-state.paused span.starting,
#guest-content-container .wok-guest-gallery .wok-guest-list-item .btn > span.guest-state.paused span.crashed,
#guest-content-container .wok-guest-gallery .wok-guest-list-item .btn > span.guest-state.paused span.nostate,
#guest-content-container .wok-guest-gallery .wok-guest-list-item .btn > span.guest-state.paused span.pmsuspended,
#guest-content-container .wok-guest-gallery .wok-guest-list-item .btn > span.guest-state.paused span.resetting {
display: none;
}
#guest-content-container .wok-guest-gallery .wok-guest-list-item .btn > span.guest-state.pmsuspended span.pmsuspended {
display: block;
}
#guest-content-container .wok-guest-gallery .wok-guest-list-item .btn > span.guest-state.pmsuspended span.running,
#guest-content-container .wok-guest-gallery .wok-guest-list-item .btn > span.guest-state.pmsuspended span.shutoff,
#guest-content-container .wok-guest-gallery .wok-guest-list-item .btn > span.guest-state.pmsuspended span.starting,
#guest-content-container .wok-guest-gallery .wok-guest-list-item .btn > span.guest-state.pmsuspended span.crashed,
#guest-content-container .wok-guest-gallery .wok-guest-list-item .btn > span.guest-state.pmsuspended span.nostate,
#guest-content-container .wok-guest-gallery .wok-guest-list-item .btn > span.guest-state.pmsuspended span.paused,
#guest-content-container .wok-guest-gallery .wok-guest-list-item .btn > span.guest-state.pmsuspended span.resetting {
display: none;
}
#guest-content-container .wok-guest-gallery .wok-guest-list-item .btn > span.guest-state.resetting span.resetting {
display: block;
}
#guest-content-container .wok-guest-gallery .wok-guest-list-item .btn > span.guest-state.resetting span.running,
#guest-content-container .wok-guest-gallery .wok-guest-list-item .btn > span.guest-state.resetting span.shutoff,
#guest-content-container .wok-guest-gallery .wok-guest-list-item .btn > span.guest-state.resetting span.starting,
#guest-content-container .wok-guest-gallery .wok-guest-list-item .btn > span.guest-state.resetting span.crashed,
#guest-content-container .wok-guest-gallery .wok-guest-list-item .btn > span.guest-state.resetting span.nostate,
#guest-content-container .wok-guest-gallery .wok-guest-list-item .btn > span.guest-state.resetting span.paused,
#guest-content-container .wok-guest-gallery .wok-guest-list-item .btn > span.guest-state.resetting span.pmsuspended {
display: none;
}
#guest-content-container .wok-guest-gallery .wok-guest-list-item .guest-actions {
display: none;
}
#guest-content-container .wok-guest-gallery .wok-guest-list-item .guest-state {
display: block;
}
#guest-content-container .wok-guest-list .wok-guest-list-body .wok-guest-list-item > span.column-processors > div > div.progress-bar.cpu-progress-bar,
#guest-content-container .wok-guest-gallery .wok-guest-list-body .wok-guest-list-item > span.column-processors > div > div.progress-bar.cpu-progress-bar {
background-color: #d9182d;
}
#guest-content-container .wok-guest-list .wok-guest-list-body .wok-guest-list-item > span.column-memory > div > div.progress-bar.memory-progress-bar,
#guest-content-container .wok-guest-gallery .wok-guest-list-body .wok-guest-list-item > span.column-memory > div > div.progress-bar.memory-progress-bar {
background-color: #008abf;
}
#guest-content-container .wok-guest-list .wok-guest-list-body .wok-guest-list-item > span.column-storage > div > div.progress-bar.storage-progress-bar,
#guest-content-container .wok-guest-gallery .wok-guest-list-body .wok-guest-list-item > span.column-storage > div > div.progress-bar.storage-progress-bar {
background-color: #fdb813;
}
#guest-content-container .wok-guest-list .wok-guest-list-body .wok-guest-list-item > span.column-network > div > div.progress-bar.network-progress-bar,
#guest-content-container .wok-guest-gallery .wok-guest-list-body .wok-guest-list-item > span.column-network > div > div.progress-bar.network-progress-bar {
background-color: #7f1c7d;
}
#guest-content-container .wok-guest-list .wok-guest-list-body .wok-guest-list-item > span.column-state > span.guest-state.running span.running {
display: block;
}
#guest-content-container .wok-guest-list .wok-guest-list-body .wok-guest-list-item > span.column-state > span.guest-state.running .fa {
color: #a8d46f;
}
#guest-content-container .wok-guest-list .wok-guest-list-body .wok-guest-list-item > span.column-state > span.guest-state.pmsuspended span.pmsuspended {
display: block;
}
#guest-content-container .wok-guest-list .wok-guest-list-body .wok-guest-list-item > span.column-state > span.guest-state.pmsuspended .fa {
color: #999;
}
#guest-content-container .wok-guest-list .wok-guest-list-body .wok-guest-list-item > span.column-state > span.guest-state.nostate span.nostate {
display: block;
}
#guest-content-container .wok-guest-list .wok-guest-list-body .wok-guest-list-item > span.column-state > span.guest-state.nostate .fa {
color: #999;
}
#guest-content-container .wok-guest-list .wok-guest-list-body .wok-guest-list-item > span.column-state > span.guest-state.crashed span.crashed {
display: block;
}
#guest-content-container .wok-guest-list .wok-guest-list-body .wok-guest-list-item > span.column-state > span.guest-state.crashed .fa {
color: #999;
}
#guest-content-container .wok-guest-list .wok-guest-list-body .wok-guest-list-item > span.column-state > span.guest-state.shutdown span.shutoff,
#guest-content-container .wok-guest-list .wok-guest-list-body .wok-guest-list-item > span.column-state > span.guest-state.shutdown span.blocked,
#guest-content-container .wok-guest-list .wok-guest-list-body .wok-guest-list-item > span.column-state > span.guest-state.shutdown span.shutdown,
#guest-content-container .wok-guest-list .wok-guest-list-body .wok-guest-list-item > span.column-state > span.guest-state.blocked span.shutoff,
#guest-content-container .wok-guest-list .wok-guest-list-body .wok-guest-list-item > span.column-state > span.guest-state.blocked span.blocked,
#guest-content-container .wok-guest-list .wok-guest-list-body .wok-guest-list-item > span.column-state > span.guest-state.blocked span.shutdown,
#guest-content-container .wok-guest-list .wok-guest-list-body .wok-guest-list-item > span.column-state > span.guest-state.shutoff span.shutoff,
#guest-content-container .wok-guest-list .wok-guest-list-body .wok-guest-list-item > span.column-state > span.guest-state.shutoff span.blocked,
#guest-content-container .wok-guest-list .wok-guest-list-body .wok-guest-list-item > span.column-state > span.guest-state.shutoff span.shutdown {
display: block;
}
#guest-content-container .wok-guest-list .wok-guest-list-body .wok-guest-list-item > span.column-state > span.guest-state.shutdown .fa,
#guest-content-container .wok-guest-list .wok-guest-list-body .wok-guest-list-item > span.column-state > span.guest-state.blocked .fa,
#guest-content-container .wok-guest-list .wok-guest-list-body .wok-guest-list-item > span.column-state > span.guest-state.shutoff .fa {
color: #999;
}
#guest-content-container .wok-guest-list .wok-guest-list-body .wok-guest-list-item > span.column-state > span.guest-state.starting span.starting {
display: block;
}
#guest-content-container .wok-guest-list .wok-guest-list-body .wok-guest-list-item > span.column-state > span.guest-state.starting .fa {
color: #999;
}
#guest-content-container .wok-guest-list .wok-guest-list-body .wok-guest-list-item > span.column-state > span.guest-state.paused span.paused {
display: block;
}
#guest-content-container .wok-guest-list .wok-guest-list-body .wok-guest-list-item > span.column-state > span.guest-state.paused .fa {
color: #999;
}
#guest-content-container .wok-guest-list .wok-guest-list-body .wok-guest-list-item > span.column-state > span.guest-state.resetting span.resetting {
display: block;
}
#guest-content-container .wok-guest-list .wok-guest-list-body .wok-guest-list-item > span.column-state > span.guest-state.resetting .fa {
color: #a8d46f;
}
#guest-content-container .wok-guest-list .wok-guest-list-header > span.column-state,
#guest-content-container .wok-guest-list .wok-guest-list-body .wok-guest-list-item > span.column-state {
width: 40px;
text-align: center;
}
#guest-content-container .wok-guest-list .wok-guest-list-header > span.column-state > span.guest-state,
#guest-content-container .wok-guest-list .wok-guest-list-body .wok-guest-list-item > span.column-state > span.guest-state {
font-size: 22px;
position: relative;
}
#guest-content-container .wok-guest-list .wok-guest-list-header > span.column-state > span.guest-state span.text-status,
#guest-content-container .wok-guest-list .wok-guest-list-body .wok-guest-list-item > span.column-state > span.guest-state span.text-status {
display: none;
}
#guest-content-container .wok-guest-list .wok-guest-list-header > span.column-state > span.guest-state span,
#guest-content-container .wok-guest-list .wok-guest-list-body .wok-guest-list-item > span.column-state > span.guest-state span {
display: none;
}
#guest-content-container .wok-guest-list .wok-guest-list-header > span.column-name,
#guest-content-container .wok-guest-list .wok-guest-list-body .wok-guest-list-item > span.column-name {
width: 13.7%;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
@media (min-width: 1330px) {
#guest-content-container .wok-guest-list .wok-guest-list-header > span.column-name,
#guest-content-container .wok-guest-list .wok-guest-list-body .wok-guest-list-item > span.column-name {
width: 9.7%;
}
}
@media (min-width: 1540px) {
#guest-content-container .wok-guest-list .wok-guest-list-header > span.column-name,
#guest-content-container .wok-guest-list .wok-guest-list-body .wok-guest-list-item > span.column-name {
width: 12%;
}
}
#guest-content-container .wok-guest-list .wok-guest-list-header > span.column-type,
#guest-content-container .wok-guest-list .wok-guest-list-body .wok-guest-list-item > span.column-type {
width: 11.74%;
background-position: 0 50%;
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
}
@media (min-width: 1330px) {
#guest-content-container .wok-guest-list .wok-guest-list-header > span.column-type,
#guest-content-container .wok-guest-list .wok-guest-list-body .wok-guest-list-item > span.column-type {
width: 10.74%;
}
}
#guest-content-container .wok-guest-list .wok-guest-list-header > span.column-vnc > a,
#guest-content-container .wok-guest-list .wok-guest-list-body .wok-guest-list-item > span.column-vnc > a {
font-weight: normal;
color: #5ab3d4 !important;
}
#guest-content-container .wok-guest-list .wok-guest-list-header > span.column-vnc .fa-spin,
#guest-content-container .wok-guest-list .wok-guest-list-body .wok-guest-list-item > span.column-vnc .fa-spin {
display: none;
}
#guest-content-container .wok-guest-list .wok-guest-list-header > span.column-vnc .fa-spin.active,
#guest-content-container .wok-guest-list .wok-guest-list-body .wok-guest-list-item > span.column-vnc .fa-spin.active {
display: inline-block;
margin-right: 8px;
font-size: 22px;
color: #5ab3d4 !important;
}
@media (min-width: 1330px) {
#guest-content-container .wok-guest-list .wok-guest-list-header > span.column-vnc,
#guest-content-container .wok-guest-list .wok-guest-list-body .wok-guest-list-item > span.column-vnc {
width: 10%;
display: inline-block;
}
}
#guest-content-container .wok-guest-list .wok-guest-list-header > span.column-processors,
#guest-content-container .wok-guest-list .wok-guest-list-header > span.column-memory,
#guest-content-container .wok-guest-list .wok-guest-list-header > span.column-storage,
#guest-content-container .wok-guest-list .wok-guest-list-header > span.column-network,
#guest-content-container .wok-guest-list .wok-guest-list-body .wok-guest-list-item > span.column-processors,
#guest-content-container .wok-guest-list .wok-guest-list-body .wok-guest-list-item > span.column-memory,
#guest-content-container .wok-guest-list .wok-guest-list-body .wok-guest-list-item > span.column-storage,
#guest-content-container .wok-guest-list .wok-guest-list-body .wok-guest-list-item > span.column-network {
width: 13%;
}
#guest-content-container .wok-guest-list .wok-guest-list-header > span.column-action,
#guest-content-container .wok-guest-list .wok-guest-list-body .wok-guest-list-item > span.column-action {
width: 165px;
}
#guest-content-container .wok-guest-list .wok-guest-list-header > span.item-hidden,
#guest-content-container .wok-guest-list .wok-guest-list-body .wok-guest-list-item > span.item-hidden {
display: none !important;
}
#guest-content-container .wok-guest-list .wok-guest-list-header .btn .guest-pending,
#guest-content-container .wok-guest-list .wok-guest-list-body .wok-guest-list-item .btn .guest-pending {
margin-left: -38px;
margin-right: -45px;
}
#guest-content-container .wok-guest-list .distro-icon.inactive {
-webkit-filter: grayscale(100%) contrast(0.8) brightness(110%);
-moz-filter: grayscale(100%) contrast(0.8) brightness(110%);
filter: grayscale(100%) contrast(0.8) brightness(110%);
}
#guest-content-container .wok-guest-list .wok-guest-list-body.inactive {
color: #999 !important;
}
#guest-content-container .distro-icon {
background-color: transparent;
background-size: 32px 32px;
background-repeat: no-repeat;
background-position: 100% 50%;
}
#guest-content-container .distro-icon.icon-centos {
background-image: url("../images/icon-centos.png");
}
#guest-content-container .distro-icon.icon-debian {
background-image: url("../images/icon-debian.png");
}
#guest-content-container .distro-icon.icon-fedora {
background-image: url("../images/icon-fedora.png");
}
#guest-content-container .distro-icon.icon-opensuse {
background-image: url("../images/icon-opensuse.png");
}
#guest-content-container .distro-icon.icon-sles {
background-image: url("../images/icon-sles.png");
}
#guest-content-container .distro-icon.icon-ubuntu {
background-image: url("../images/icon-ubuntu.png");
}
#guest-content-container .distro-icon.icon-gentoo {
background-image: url("../images/icon-gentoo.png");
}
#guest-content-container .distro-icon.icon-unknown {
background-image: url("../images/icon-vm.png");
}
body.wok-gallery {
background: #eee;
}
#guest-edit-window .tab-content {
overflow: hidden;
height: auto;
}
#guest-edit-window .tab-content .tab-pane {
position: relative;
}
#guest-edit-window #form-guest-edit-general #guest-max-memory-panel,
#guest-edit-window #form-guest-edit-general #guest-max-processor-panel {
display: none;
}
#guest-edit-window #form-guest-edit-general #guest-edit-memory-textbox,
#guest-edit-window #form-guest-edit-general #guest-edit-max-memory-textbox,
#guest-edit-window #form-guest-edit-general #guest-edit-cores-textbox,
#guest-edit-window #form-guest-edit-general #guest-edit-max-processor-textbox {
width: 590px;
}
#guest-edit-window #form-guest-edit-general #guest-edit-memory-textbox,
#guest-edit-window #form-guest-edit-general #guest-show-max-memory {
display: inline-block;
}
#guest-edit-window #form-guest-edit-storage .column-actions {
width: 26%;
}
#guest-edit-window #form-guest-edit-snapshot .column-actions {
width: 22%;
}
#guest-edit-window #form-guest-edit-pci .wok-mask {
top: 0 !important;
z-index: 2 !important;
}
#guest-edit-window #form-guest-edit-pci .column-actions {
width: 4.47%;
}
#guest-edit-window #form-edit-processor #guest-processor label {
display: block;
}
#guest-edit-window #form-edit-processor #guest-max-processor-panel label {
display: block;
}
#guest-edit-window #form-edit-processor #guest-max-processor-panel .form-control,
#guest-edit-window #form-edit-processor #guest-processor .form-control {
display: inline-block;
width: 184px;
}
#guest-edit-window #form-edit-processor .manual {
margin-top: 5px;
margin-bottom: 10px;
}
#guest-edit-window #form-edit-processor .topology {
display: none;
margin: 0 24px;
}
#guest-edit-window #form-edit-processor .topology label {
display: block;
}
#guest-edit-window form {
margin: 15px 0 0;
}
#guest-edit-window form .header .cell.column-network,
#guest-edit-window form .header .cell.column-mac {
display: inline-block;
overflow-x: hidden;
overflow-y: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
#guest-edit-window form .column-actions,
#guest-edit-window form .task .column-actions,
#guest-edit-window form .body .column-actions {
text-align: right;
}
#guest-edit-window form .column-device,
#guest-edit-window form .task .column-device,
#guest-edit-window form .body .column-device {
width: 12.7%;
}
#guest-edit-window form .column-path,
#guest-edit-window form .task .column-path,
#guest-edit-window form .body .column-path {
width: 60.25%;
}
#guest-edit-window form .cell.column-network,
#guest-edit-window form .task .cell.column-network,
#guest-edit-window form .body .cell.column-network {
width: 184px;
}
#guest-edit-window form .cell.column-network > span,
#guest-edit-window form .task .cell.column-network > span,
#guest-edit-window form .body .cell.column-network > span {
width: 100%;
display: inline-block;
text-overflow: ellipsis;
overflow: hidden;
}
#guest-edit-window form .cell.column-type,
#guest-edit-window form .task .cell.column-type,
#guest-edit-window form .body .cell.column-type {
width: 184px;
}
#guest-edit-window form .cell.column-mode,
#guest-edit-window form .task .cell.column-mode,
#guest-edit-window form .body .cell.column-mode {
width: 164px;
}
#guest-edit-window form .cell.column-mac,
#guest-edit-window form .task .cell.column-mac,
#guest-edit-window form .body .cell.column-mac {
width: 174px;
}
#guest-edit-window form .cell.column-ip,
#guest-edit-window form .task .cell.column-ip,
#guest-edit-window form .body .cell.column-ip {
width: 150px;
display: inline-block;
text-overflow: ellipsis;
white-space: nowrap;
}
#guest-edit-window form .cell.column-sel,
#guest-edit-window form .task .cell.column-sel,
#guest-edit-window form .body .cell.column-sel {
width: 1.77%;
}
#guest-edit-window form .cell.column-snapshot-name,
#guest-edit-window form .task .cell.column-snapshot-name,
#guest-edit-window form .body .cell.column-snapshot-name {
width: 58%;
}
#guest-edit-window form .cell.column-snapshot-created,
#guest-edit-window form .task .cell.column-snapshot-created,
#guest-edit-window form .body .cell.column-snapshot-created {
width: 16.5%;
}
#guest-edit-window form .cell.column-pci-status,
#guest-edit-window form .task .cell.column-pci-status,
#guest-edit-window form .body .cell.column-pci-status {
width: 3.7%;
}
#guest-edit-window form .cell.column-pci-status .fa,
#guest-edit-window form .task .cell.column-pci-status .fa,
#guest-edit-window form .body .cell.column-pci-status .fa {
color: #8cc63f;
font-size: 24px;
}
#guest-edit-window form .cell.column-pci-name,
#guest-edit-window form .task .cell.column-pci-name,
#guest-edit-window form .body .cell.column-pci-name {
width: 21%;
}
#guest-edit-window form .cell.column-product,
#guest-edit-window form .task .cell.column-product,
#guest-edit-window form .body .cell.column-product {
width: 45%;
}
#guest-edit-window form .cell.column-vendor,
#guest-edit-window form .task .cell.column-vendor,
#guest-edit-window form .body .cell.column-vendor {
width: 24.1%;
}
#guest-edit-window form .header {
background: #fff;
display: block;
border-bottom: 1px solid #eee;
overflow: hidden;
clear: both;
}
#guest-edit-window form .header > span {
padding: 6px 2px;
display: inline-block;
font-family: Helvetica, Arial, "Lucida Grande", sans-serif;
font-weight: 400;
font-size: 12.5pt;
vertical-align: bottom;
border-bottom: none;
border-top: 0;
line-height: 1.42857;
}
#guest-edit-window form .header > span.column-actions {
height: 36px;
}
#guest-edit-window form .body {
overflow-y: auto;
overflow-x: hidden;
height: 471px;
}
#guest-edit-window form .body .item,
#guest-edit-window form .task .item {
border-top: 1px solid #eee;
height: 53px;
}
#guest-edit-window form .body .item:first-child,
#guest-edit-window form .task .item:first-child {
border-top: 0;
}
#guest-edit-window form .body .item > span,
#guest-edit-window form .task .item > span {
padding: 6px 2px;
display: inline-block;
vertical-align: middle;
}
#guest-edit-window form .body .item > span input[type="text"],
#guest-edit-window form .task .item > span input[type="text"] {
height: 40px;
}
#guest-edit-window form .body .item > span input[readonly],
#guest-edit-window form .body .item > span input[readonly]:hover,
#guest-edit-window form .body .item > span input[readonly]:focus,
#guest-edit-window form .body .item > span input[readonly]:active,
#guest-edit-window form .task .item > span input[readonly],
#guest-edit-window form .task .item > span input[readonly]:hover,
#guest-edit-window form .task .item > span input[readonly]:focus,
#guest-edit-window form .task .item > span input[readonly]:active {
background-color: transparent !important;
border-color: transparent !important;
box-shadow: none !important;
border-radius: 0 !important;
text-overflow: ellipsis;
padding-right: 0 !important;
padding-left: 0 !important;
width: 100%;
}
#guest-edit-window form .body .item:nth-child(even),
#guest-edit-window form .task .item:nth-child(even) {
background-color: #fcfcfc;
}
#guest-edit-window form .body .item:nth-child(odd),
#guest-edit-window form .task .item:nth-child(odd) {
background-color: #fff;
}
#guest-edit-window form .header .cell.column-network .bootstrap-select:not([class*=col-]):not([class*=form-control]):not(.input-group-btn),
#guest-edit-window form .task .cell.column-network .bootstrap-select:not([class*=col-]):not([class*=form-control]):not(.input-group-btn),
#guest-edit-window form .body .cell.column-network .bootstrap-select:not([class*=col-]):not([class*=form-control]):not(.input-group-btn) {
width: 180px;
}
#guest-edit-window form .header .cell.column-mode .bootstrap-select:not([class*=col-]):not([class*=form-control]):not(.input-group-btn),
#guest-edit-window form .task .cell.column-mode .bootstrap-select:not([class*=col-]):not([class*=form-control]):not(.input-group-btn),
#guest-edit-window form .body .cell.column-mode .bootstrap-select:not([class*=col-]):not([class*=form-control]):not(.input-group-btn) {
width: 160px;
}
#guest-edit-window form .header .cell.column-type .bootstrap-select:not([class*=col-]):not([class*=form-control]):not(.input-group-btn),
#guest-edit-window form .task .cell.column-type .bootstrap-select:not([class*=col-]):not([class*=form-control]):not(.input-group-btn),
#guest-edit-window form .body .cell.column-type .bootstrap-select:not([class*=col-]):not([class*=form-control]):not(.input-group-btn) {
width: 180px;
}
.guest-edit-snapshot .hide,
.guest-edit-interface .hide {
display: none !important;
}
.guest-edit-pci .filter {
height: 40px;
overflow: visible;
clear: both;
}
.guest-edit-pci .pull-right .bootstrap-select:not([class*=col-]):not([class*=form-control]):not(.input-group-btn) {
width: 133px;
}
.guest-edit-pci .filter input[type="text"].form-control {
width: 460px;
height: 40px;
float: right;
border-top-left-radius: 0;
border-bottom-left-radius: 0;
}
.guest-edit-pci .filter .bootstrap-select.btn-group .btn .caret {
border-left: 0;
}
.guest-edit-pci .filter button.btn.dropdown-toggle.form-control.selectpicker.btn-default {
border-top-right-radius: 0 !important;
border-bottom-right-radius: 0 !important;
background: #fcfcfc;
border-right: 0;
}
.guest-edit-pci .body {
overflow-y: auto;
overflow-x: hidden;
height: 442px !important;
}
.guest-edit-pci .body .item.disabled input[type="text"].form-control {
color: #999;
}
.guest-edit-pci .body .item.disabled span.column-pci-status i {
display: none;
}
.guest-edit-permission .pam {
height: 540px;
}
.guest-edit-permission .pam .column {
display: inline-block;
vertical-align: top;
}
.guest-edit-permission .pam .v-center {
min-height: 532px;
display: flex;
justify-content: center;
flex-flow: column wrap;
}
.guest-edit-permission .pam .center-block {
display: block;
margin-left: auto;
margin-right: auto;
}
.guest-edit-permission .pam .center-block + .center-block {
margin-top: 5px;
}
.guest-edit-permission .pam .title {
font-size: 13pt;
}
.guest-edit-permission .pam .body {
margin-top: 4px;
border-radius: 3px;
border: 1px solid #eee;
height: 460px !important;
}
.guest-edit-permission .pam .body .head .item {
display: block;
padding: 6px 2px;
margin-bottom: 5px;
font-family: Helvetica, Arial, "Lucida Grande", sans-serif;
font-weight: 400;
font-size: 12.5pt;
vertical-align: bottom;
line-height: 1.42857;
height: auto !important;
background: #fff;
border-top: 0;
border-bottom: 1px solid #eee;
cursor: default;
}
.guest-edit-permission .pam .body > .column-user .item,
.guest-edit-permission .pam .body > .column-group .item {
height: auto !important;
margin-bottom: 0;
margin-left: 5px;
}
.guest-edit-permission .pam .body > .column-group .item {
margin-right: 5px;
}
.guest-edit-permission .pam .column-user label,
.guest-edit-permission .pam .column-group label {
cursor: pointer;
margin-bottom: 0;
margin-left: 5px;
width: 160px;
height: 24px;
line-height: 22px;
overflow: hidden;
text-overflow: ellipsis;
vertical-align: middle;
}
.guest-edit-permission .pam .body > .column .item {
background-color: #fff !important;
border: 1px solid #eee !important;
margin-bottom: 3px;
display: block;
padding: .2em .6em .3em;
font-weight: 700;
line-height: 1;
text-align: left;
white-space: nowrap;
vertical-align: middle;
border-radius: .25em;
overflow: hidden;
}
.guest-edit-permission .pam .body > .column .item:hover {
color: #444 !important;
background-color: #e6e6e6 !important;
border-color: #adadad !important;
}
.guest-edit-permission .pam .body > .column .item:hover label {
color: #444 !important;
}
.guest-edit-permission .pam .body > .column .item.item-picked {
color: #fff !important;
background-color: #3a393b !important;
border-color: #1b1b1c !important;
outline: 5px auto -webkit-focus-ring-color;
outline-offset: -2px;
}
.guest-edit-permission .pam .body > .column .item.item-picked label {
color: #fff !important;
}
.guest-edit-permission .hide {
display: none;
}
#form-guest-edit-permission .ldap .body .item {
margin: 8px 0;
}
#form-guest-edit-permission .ldap .cell {
width: 250px;
}
#form-guest-edit-permission .ldap .action-area {
float: right;
line-height: 24px;
}
#form-guest-edit-permission .ldap .header button {
margin-bottom: 1px;
}
#form-guest-edit-permission .ldap .checked {
border-color: red;
border-style: solid;
border-width: 1px;
}
#form-guest-edit-permission .ldap .checked.hide {
display: none;
}
#form-guest-storage-add .form-section .field {
overflow: visible;
}
ul {
cursor: default;
}
.boot-order {
display: block;
width: 85%;
font-size: 14px;
line-height: 1.42857;
color: #444;
overflow: hidden;
background-color: #fff;
background-image: none;
border: 1px solid #ccc;
border-radius: 3px;
-webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
-webkit-transition: border-color ease-in-out 0.15s, box-shadow ease-in-out 0.15s;
-o-transition: border-color ease-in-out 0.15s, box-shadow ease-in-out 0.15s;
transition: border-color ease-in-out 0.15s, box-shadow ease-in-out 0.15s;
}
.boot-order:focus,
.boot-order.focus {
border-color: #66afe9;
outline: 0;
-webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(102, 175, 233, 0.6);
box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(102, 175, 233, 0.6);
}
.boot-order > li {
cursor: move;
/* fallback if grab cursor is unsupported */
cursor: grab;
cursor: -moz-grab;
cursor: -webkit-grab;
border-left: 0;
border-right: 0;
}
.boot-order > li:first-child {
border-top: 0;
}
.boot-order > li:last-child {
border-bottom: 0;
}
.boot-order > li.ui-sortable-helper {
cursor: grabbing;
cursor: -moz-grabbing;
cursor: -webkit-grabbing;
border: 1px solid #ccc !important;
}
.boot-order li i {
text-align: right;
}
/* Add Template Modal Window */
.templates-modal .modal-dialog {
width: 1100px;
}
.templates-modal .page-list {
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
overflow: hidden;
}
.templates-modal .page {
position: absolute;
left: 100%;
width: 100%;
height: 100%;
overflow: auto;
padding: 10px 30px;
}
#template-edit-window .wok-mask {
top: 0 !important;
z-index: 3;
}
#template-edit-window .tab-content .tab-pane {
position: relative;
}
#template-edit-window form {
margin: 15px 0 0;
}
#template-edit-window label.check-all {
margin: 0 !important;
padding: 0 !important;
width: 100px;
display: inline-block;
vertical-align: middle;
}
#template-edit-window .hide {
display: none;
}
#template-edit-window .form-template-inline-wrapper {
display: inline-block;
vertical-align: top;
}
#template-edit-window .template-edit-wrapper-label {
vertical-align: top;
min-width: 172px;
height: 35px;
line-height: 35px;
margin: 7px 0 8px;
}
#template-edit-window .template-edit-wrapper-controls {
vertical-align: top;
width: 480px;
height: 35px;
line-height: 35px;
margin: 7px 0 8px;
}
#template-edit-window .template-tab-header {
background: #fff;
display: block;
border-bottom: 1px solid #eee;
}
#template-edit-window .template-tab-header > span {
padding: 6px 2px;
display: inline-block;
font-family: Helvetica, Arial, "Lucida Grande", sans-serif;
font-weight: 400;
font-size: 12.5pt;
vertical-align: baseline;
border-bottom: none;
border-top: 0;
line-height: 42px;
height: 42px;
}
#template-edit-window .template-tab-body .item {
border-top: 1px solid #eee;
height: 53px;
}
#template-edit-window .template-tab-body .item:first-child {
border-top: 0;
}
#template-edit-window .template-tab-body .item:nth-child(even) {
background-color: #fcfcfc;
}
#template-edit-window .template-tab-body .item:nth-child(odd) {
background-color: #fff;
}
#template-edit-window .template-tab-body .item > span {
padding: 6px 2px;
display: inline-block;
vertical-align: middle;
}
#template-edit-window .template-tab-body .item > span input[type="text"].form-control {
height: 40px;
}
#template-edit-window #template-edit-memory-textbox {
width: 308px !important;
display: inline;
}
#template-edit-window #guest-show-max-processor {
display: inline-block;
}
#template-edit-window #guest-processor label {
display: block;
}
#template-edit-window #guest-max-processor-panel label {
display: block;
}
#template-edit-window #guest-max-processor-panel .form-control,
#template-edit-window #guest-processor .form-control {
display: inline-block;
width: 184px;
}
#template-edit-window .manual {
margin-top: 5px;
margin-bottom: 10px;
}
#template-edit-window .topology {
display: none;
margin: 0 24px;
}
#template-edit-window .topology label {
display: block;
}
#template-edit-window .bootstrap-select .btrn .caret {
height: selectpicker height-2px;
}
#template-edit-window .template-storage-cell.storage-pool {
width: 180px !important;
}
#template-edit-window .template-storage-cell.storage {
width: 180px !important;
}
#template-edit-window .template-storage-cell.storage-path {
width: 180px !important;
}
#template-edit-window .template-storage-cell.source {
width: 180px !important;
}
#template-edit-window .template-storage-cell.type {
width: 110px;
}
#template-edit-window .template-storage-cell.disk {
width: 133px;
}
#template-edit-window .template-storage-cell.format {
width: 162px;
}
#template-edit-window .template-interface-cell.network {
width: 220px;
}
#template-edit-window .template-interface-cell.type {
width: 250px;
}
#template-add-window .modal-body {
margin: 0;
padding: 0;
}
#template-add-window .modal-footer {
margin-top: 0;
}
#template-add-window .modal-footer .btn + .btn {
margin-left: 0;
}
#template-add-window .modal-footer .btn {
margin-right: 5px;
}
#template-add-window .template-modal-container {
padding: 10px 30px;
position: relative;
}
#template-add-window .template-pager {
background: #eee;
width: 1082px;
height: 689px;
position: relative;
overflow: hidden;
}
#template-add-window .template-pager-container {
position: absolute;
height: 664px;
width: 2164px;
left: 0;
transition: left .2s ease-in-out;
}
#template-add-window.modal-content p {
margin: 0;
}
#template-add-window.modal-content h5 {
font-size: 13pt;
font-weight: 400;
margin-top: 0;
}
#template-add-window.modal-content label {
font-size: 16px;
font-weight: 400;
font-family: Helvetica, Arial, "Lucida Grande", sans-serif;
}
#template-add-window.modal-content label.check-all {
display: inline-block;
vertical-align: middle;
padding-top: 8px;
}
#template-add-window.modal-content button#iso-more,
#template-add-window.modal-content button#iso-more-loading {
clear: both;
}
#template-add-window.modal-content div#iso-remote-box {
left: 1082px;
}
#template-add-window.modal-content div#iso-local-box {
left: 0;
}
#template-add-window .check-all {
margin-right: 0 !important;
padding-left: 0 !important;
}
#template-add-window .filter {
float: right;
height: 40px;
overflow: visible;
clear: both;
margin-bottom: 0;
display: inline-block;
vertical-align: middle;
}
#template-add-window .pull-right .bootstrap-select:not([class*=col-]):not([class*=form-control]):not(.input-group-btn) {
width: 133px;
}
#template-add-window .filter input[type="text"].form-control {
width: 460px;
height: 40px;
float: right;
border-top-left-radius: 0;
border-bottom-left-radius: 0;
}
#template-add-window .filter .bootstrap-select.btn-group .btn .caret {
border-left: 0;
}
#template-add-window .filter button.btn.dropdown-toggle.form-control.selectpicker.btn-default {
border-top-right-radius: 0 !important;
border-bottom-right-radius: 0 !important;
background: #fcfcfc;
border-right: 0;
}
#template-add-window span.iso-image-indicator {
position: absolute;
bottom: 10px;
right: 10px;
font-size: 32px;
}
#template-add-window span.iso-image-indicator .fa {
display: inline-block;
vertical-align: middle;
}
#template-add-window span.iso-image-indicator i.fa.fa-file-iso,
#template-add-window span.iso-image-indicator i.fa.fa-file-img {
display: inline-block;
width: 27px;
height: 25px;
margin-right: 3px;
}
#template-add-window span.iso-image-indicator i.fa.fa-file-iso {
background: url("../images/file-o-iso.svg") no-repeat 50% 50%;
background-size: contain;
}
#template-add-window span.iso-image-indicator i.fa.fa-file-img {
background: url("../images/file-o-img.svg") no-repeat 50% 50%;
background-size: contain;
}
#template-add-window span.iso-image-alert {
position: absolute;
bottom: 15px;
right: 70px;
font-size: 20px;
}
#template-add-window .tooltip-arrow {
display: none;
}
#template-add-window #loading-isos {
top: 0 !important;
z-index: 4 !important;
}
/* VM List View classes*/
#templatestatusselect {
width: 240px !important;
}
#templates-root-container .grid-control input[type="text"] {
height: 38px;
display: inline-block;
vertical-align: top;
}
#templates-root-container .bootstrap-select:not([class*=col-]):not([class*=form-control]):not(.input-group-btn) {
width: 162px;
margin-right: 10px;
}
#templates-root-container .bootstrap-select.btn-group .dropdown-menu {
margin: 0px;
}
#templates-root-container .bootstrap-select.btn-group .dropdown-menu > li > a {
border-top: 1px solid #fff;
border-bottom: 1px solid #eee;
height: 38px;
padding: 4px 12px;
font-family: Helvetica, Arial, "Lucida Grande", sans-serif;
font-size: 13pt;
}
#templates-root-container .bootstrap-select.btn-group .dropdown-menu > li:last-child > a {
border-bottom: 0;
}
#templates-root-container .control.open > .dropdown-menu {
display: block;
display: block;
width: 188px;
margin-left: -26px;
border-radius: 0;
}
#templates-root-container .control.open .caret {
background: #3a393b;
}
#templates-root-container .control.open .caret:before {
content: '\f077';
}
#templates-root-container .control.open > a {
outline: 0;
}
#templates-root-container .sort-button {
height: 38px;
padding: 4px 12px;
}
#templates-root-container .sort-button .caret {
height: 36px;
}
#templates-root-container .sort-button .caret:before {
top: 6px;
}
#templates-root-container .wok-vm-list {
display: block;
width: 100%;
list-style-type: none;
margin: 0;
padding-left: 0;
background: #fff;
}
#templates-root-container .wok-vm-list .wok-vm-header {
border-bottom: 1px solid #e3e3e3;
}
#templates-root-container .wok-vm-list .wok-vm-header > span {
padding: 6px 2px;
display: inline-block;
vertical-align: bottom;
height: 36px;
font-family: Helvetica, Arial, "Lucida Grande", sans-serif;
font-weight: 300;
font-size: 12.5pt;
line-height: 1.42857;
border-bottom: none;
border-top: 0;
background-color: #fff;
width: 200px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
#templates-root-container .wok-vm-list .wok-vm-body {
clear: both;
border-top: 1px solid #eee;
}
#templates-root-container .wok-vm-list .wok-vm-body:first-child {
border-top: 0;
}
#templates-root-container .wok-vm-list .wok-vm-body > span {
padding: 6px 2px;
display: inline-block;
vertical-align: top;
font-family: Helvetica, Arial, "Lucida Grande", sans-serif;
font-size: 12.5pt;
line-height: 2.42857;
font-weight: 400;
width: 200px;
}
#templates-root-container .wok-vm-list .wok-vm-body .column-type {
padding-left: 40px !important;
}
#templates-root-container .wok-vm-list .ul-body {
display: block;
width: 100%;
clear: both;
padding: 0;
margin: 0;
list-style: none;
}
#templates-root-container .wok-vm-list .ul-body > li:nth-child(even) {
background-color: #fcfcfc;
}
#templates-root-container .wok-vm-list .ul-body > li:nth-child(odd) {
background-color: #fff;
}
#templates-root-container .wok-vm-list .column-name {
width: 17.4900%;
font-weight: bold;
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
}
#templates-root-container .wok-vm-list .column-type {
width: 14.2435%;
font-weight: bold;
}
#templates-root-container .wok-vm-list .column-version {
width: 12.2435%;
font-weight: bold;
}
#templates-root-container .wok-vm-list .column-processors {
width: 10.8413%;
}
#templates-root-container .wok-vm-list .column-memory {
width: 9.6900%;
}
#templates-root-container .wok-vm-list .column-status {
width: 1.6900%;
}
#templates-root-container .wok-vm-list .column-action {
width: 232px;
}
#templates-root-container .wok-vm-list .item-hidden {
display: none !important;
}
#templates-root-container .wok-vm-list .distro-icon {
background-color: transparent;
background-size: 27px 27px;
background-repeat: no-repeat;
background-position: 8px 50%;
}
#templates-root-container .wok-vm-list .distro-icon.icon-centos {
background-image: url("../images/icon-centos.png");
}
#templates-root-container .wok-vm-list .distro-icon.icon-debian {
background-image: url("../images/icon-debian.png");
}
#templates-root-container .wok-vm-list .distro-icon.icon-fedora {
background-image: url("../images/icon-fedora.png");
}
#templates-root-container .wok-vm-list .distro-icon.icon-opensuse {
background-image: url("../images/icon-opensuse.png");
}
#templates-root-container .wok-vm-list .distro-icon.icon-sles {
background-image: url("../images/icon-sles.png");
}
#templates-root-container .wok-vm-list .distro-icon.icon-ubuntu {
background-image: url("../images/icon-ubuntu.png");
}
#templates-root-container .wok-vm-list .distro-icon.icon-gentoo {
background-image: url("../images/icon-gentoo.png");
}
#templates-root-container .wok-vm-list .distro-icon.icon-unknown {
background-image: url("../images/icon-vm.png");
}
#templates-root-container .wok-vm-gallery {
display: block;
width: 100%;
list-style-type: none;
margin: 0;
padding-left: 5px;
}
#templates-root-container .wok-vm-gallery .wok-vm-header {
display: none;
}
#templates-root-container .wok-vm-gallery .wok-vm-body {
position: relative;
padding: 0 20px 0 20px;
width: 240px;
display: inline-block;
border: 0;
background: #fff;
margin-right: 20px;
margin-bottom: 20px;
}
#templates-root-container .wok-vm-gallery .wok-vm-body > span {
display: inline-block;
width: 100%;
font-family: Helvetica, Arial, "Lucida Grande", sans-serif;
font-size: 12.5pt;
line-height: 1.42857;
font-weight: 400;
}
#templates-root-container .wok-vm-gallery .ul-body {
display: inline-block;
padding: 0;
margin: 0;
list-style: none;
}
#templates-root-container .wok-vm-gallery .column-name {
line-height: 2.5 !important;
font-size: 15.3pt !important;
font-weight: 500 !important;
text-overflow: ellipsis !important;
overflow: hidden !important;
padding-right: 35px !important;
white-space: nowrap;
cursor: default;
}
#templates-root-container .wok-vm-gallery span.template-status {
position: absolute;
bottom: 10px;
right: 10px;
width: 32px;
height: 32px;
}
#templates-root-container .wok-vm-gallery .invalid-icon {
position: absolute;
font-size: 32px;
}
#templates-root-container .wok-vm-gallery .item-hidden.column-type, #templates-root-container .wok-vm-gallery .item-hidden.column-version, #templates-root-container .wok-vm-gallery .item-hidden.column-processors {
padding-bottom: 11px;
}
#templates-root-container .wok-vm-gallery .item-hidden.column-memory {
padding-bottom: 38px;
}
#templates-root-container .wok-vm-gallery .font-bold {
font-weight: bold !important;
}
#templates-root-container .wok-vm-gallery .pull-right {
float: none !important;
padding-bottom: 22px;
}
#templates-root-container .wok-vm-gallery .dropdown-menu {
width: 100%;
}
#templates-root-container .wok-vm-gallery .menu-flat {
width: 240px;
margin-left: -20px;
}
#templates-root-container .wok-vm-gallery .btn {
width: 100%;
text-align: left;
padding-left: 42px;
border-radius: 0;
}
#templates-root-container .wok-vm-gallery .name-distro-icon {
background-color: transparent;
background-size: 32px 32px;
background-repeat: no-repeat;
background-position: 100% 50%;
}
#templates-root-container .wok-vm-gallery .name-distro-icon.icon-centos {
background-image: url("../images/icon-centos.png");
}
#templates-root-container .wok-vm-gallery .name-distro-icon.icon-debian {
background-image: url("../images/icon-debian.png");
}
#templates-root-container .wok-vm-gallery .name-distro-icon.icon-fedora {
background-image: url("../images/icon-fedora.png");
}
#templates-root-container .wok-vm-gallery .name-distro-icon.icon-opensuse {
background-image: url("../images/icon-opensuse.png");
}
#templates-root-container .wok-vm-gallery .name-distro-icon.icon-sles {
background-image: url("../images/icon-sles.png");
}
#templates-root-container .wok-vm-gallery .name-distro-icon.icon-ubuntu {
background-image: url("../images/icon-ubuntu.png");
}
#templates-root-container .wok-vm-gallery .name-distro-icon.icon-gentoo {
background-image: url("../images/icon-gentoo.png");
}
#templates-root-container .wok-vm-gallery .name-distro-icon.icon-unknown {
background-image: url("../images/icon-vm.png");
}
#templates-root-container span.template-status {
color: #999;
}
#templates-root-container .tooltip-inner {
font-size: 10pt;
padding: 6px 8px;
}
#templates-root-container .wok-vm-list .tooltip-inner {
max-width: 300px;
}
#templates-root-container .wok-vm-list .tooltip[style] {
left: 79px !important;
}
#templates-root-container .wok-vm-list .tooltip-arrow[style] {
left: 10px !important;
}
#templates-root-container .wok-vm-gallery .tooltip-inner {
max-width: 320px;
}
#templates-root-container .wok-vm-gallery .tooltip[style] {
left: 7px !important;
right: 7px !important;
}
#templates-root-container .wok-vm-gallery .tooltip-arrow[style] {
left: 207px !important;
}
.network-config input.invalid-field[type="text"] {
border-color: #FF4444;
}
.network-config input.invalid-field[type="text"][disabled] {
border-color: #666666;
}
#add-network-window #vlan-enabled {
padding-left: 26px;
}
#add-network-window #vlan-enabled label, #add-network-window #vlan-enabled input[type="text"] {
display: block;
}
#networkConfig .alert-dismissable .close, .alert-dismissible .close {
right: -2px !important;
}
#network-root-container .wok-datagrid-body span > .fa {
font-size: 22px;
width: 22px;
position: relative;
}
#network-root-container .wok-datagrid-body .loading .fa-spinner {
display: inline-block;
}
#network-root-container .wok-datagrid-body .up .fa-power-off {
color: #a8d46f;
}
#network-root-container .wok-datagrid-body .down .fa-power-off {
display: none;
}
#network-root-container .wok-datagrid > .wok-datagrid-header > span.column-state,
#network-root-container .wok-datagrid > .wok-datagrid-body > .wok-datagrid-row > span.column-state {
width: 2.92207%;
text-align: center;
}
#network-root-container .wok-datagrid > .wok-datagrid-header > span.column-name,
#network-root-container .wok-datagrid > .wok-datagrid-body > .wok-datagrid-row > span.column-name {
width: 19.2207%;
}
#network-root-container .wok-datagrid > .wok-datagrid-header > span.column-type,
#network-root-container .wok-datagrid > .wok-datagrid-body > .wok-datagrid-row > span.column-type {
width: 11.3896%;
}
#network-root-container .wok-datagrid > .wok-datagrid-header > span.column-interface,
#network-root-container .wok-datagrid > .wok-datagrid-body > .wok-datagrid-row > span.column-interface {
width: 15.3896%;
padding-right: 40px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
#network-root-container .wok-datagrid > .wok-datagrid-header > span.column-space,
#network-root-container .wok-datagrid > .wok-datagrid-body > .wok-datagrid-row > span.column-space {
width: 25%;
}
#network-root-container .wok-datagrid > .wok-datagrid-header > span.column-action,
#network-root-container .wok-datagrid > .wok-datagrid-body > .wok-datagrid-row > span.column-action {
width: 25.909%;
text-align: right;
}
#network-root-container .wok-datagrid > .wok-datagrid-body > .wok-datagrid-row > span.column-state {
height: 53px;
vertical-align: middle;
}
#add-network-window #networkConfig #alert-modal-container .alert {
padding: 8px 34px 8px 16px;
}
#storage-root-container .wok-datagrid-body span > .fa {
font-size: 22px;
width: 20px;
height: 20px;
position: relative;
}
#storage-root-container .wok-datagrid-body .handle {
-webkit-user-select: none;
-moz-user-select: none;
user-select: none;
position: relative;
}
#storage-root-container .wok-datagrid-body .active .handle {
cursor: pointer;
}
#storage-root-container .wok-datagrid-body .active .fa-power-off {
color: #a8d46f;
}
#storage-root-container .wok-datagrid-body .inactive .handle {
cursor: default;
}
#storage-root-container .wok-datagrid-body .inactive .fa-power-off {
display: none;
}
#storage-root-container .wok-datagrid-body .inactive .usage-icon.icon-high {
background-image: url("../../../images/theme-default/high_disabled.png") !important;
}
#storage-root-container .wok-datagrid-body .inactive .usage-icon.icon-med {
background-image: url("../../../images/theme-default/med_disabled.png") !important;
}
#storage-root-container .wok-datagrid-body .inactive .usage-icon.icon-low {
background-image: url("../../../images/theme-default/low_disabled.png") !important;
}
#storage-root-container .volumes {
width: 100%;
background: #ddd;
display: none;
}
#storage-root-container .volumes .tooltip > .tooltip-inner {
width: 150px;
}
#storage-root-container .volumes input[type=checkbox][disabled].wok-checkbox + label:before {
content: '';
}
#storage-root-container .volumes .toggle-gallery {
left: 202px;
}
@media (min-width: 1200px) {
#storage-root-container .volumes .toggle-gallery {
left: 282px;
}
}
#storage-root-container .volumes > .footer {
z-index: 100;
}
#storage-root-container .volumes .volumeslist {
padding: 22px;
min-height: 188px;
max-height: 505px;
overflow: hidden;
}
#storage-root-container .volumes .volumeslist .wok-list {
min-height: inherit;
}
#storage-root-container .volumes .volumeslist .row {
font-size: 0;
margin-bottom: 22px;
}
#storage-root-container .volumes .volumeslist .filter {
width: 344px;
height: 38px;
margin-top: 1px;
}
@media (min-width: 992px) {
#storage-root-container .volumes .volumeslist .filter {
width: 514px;
}
}
#storage-root-container .volumes .pool-action {
display: inline-block;
margin-right: 20px;
}
#storage-root-container .volumes .volume-icon {
display: inline-block;
vertical-align: middle;
width: 27px;
height: 27px;
line-height: 27px;
background-repeat: no-repeat;
background-position: 50%;
background-color: transparent;
}
#storage-root-container .volumes .volume-icon.icon-high {
background-image: url("../../../images/theme-default/high.png");
}
#storage-root-container .volumes .volume-icon.icon-med {
background-image: url("../../../images/theme-default/med.png");
}
#storage-root-container .volumes .volume-icon.icon-low {
background-image: url("../../../images/theme-default/low.png");
}
#storage-root-container .volumes .volume-progress {
position: absolute;
margin: 0;
width: 407px;
top: 4px;
left: 4px;
}
#storage-root-container .volumes .volume-progress .progress-bar-outer {
background: #ddd;
height: 6px;
overflow: hidden;
width: 100%;
}
#storage-root-container .volumes .volume-progress .progress-bar-inner {
background: #8BC53E;
height: 100%;
width: 100%;
}
#storage-root-container .volumes .volume-data {
margin: 0;
padding: 0;
list-style: none;
}
#storage-root-container .volumes .volume-data > li {
display: inline-block;
width: 89px;
}
#storage-root-container .volumes .volume-data > li span {
display: block;
font-size: 12pt;
}
#storage-root-container .volumes .volume-data > li span.value {
font-weight: 600;
}
#storage-root-container .volumes .volume-data > li span.key {
font-weight: 300;
}
#storage-root-container .volumes .pool-empty {
width: 100%;
cursor: default !important;
}
#storage-root-container .volumes .pool-empty > span {
width: 100%;
text-align: center;
line-height: 136px;
vertical-align: middle !important;
}
#storage-root-container .volumes .wok-gallery.wok-datagrid {
background: transparent;
margin-top: -12px;
}
#storage-root-container .volumes .wok-gallery.wok-datagrid > .wok-datagrid-header {
display: none;
}
#storage-root-container .volumes .wok-gallery.wok-datagrid > .wok-datagrid-body {
margin-left: -3px;
overflow-y: auto;
overflow-x: hidden;
max-height: 400px;
}
#storage-root-container .volumes .wok-gallery.wok-datagrid .wok-datagrid-body > .wok-datagrid-row {
position: relative;
cursor: pointer;
background: #fff !important;
border: 0 !important;
display: inline-block !important;
width: 415px !important;
margin: 12px 4px 0;
}
#storage-root-container .volumes .wok-gallery.wok-datagrid .wok-datagrid-body > .wok-datagrid-row, #storage-root-container .volumes .wok-gallery.wok-datagrid .wok-datagrid-body > .wok-datagrid-row * {
-webkit-user-select: none;
-moz-user-select: none;
user-select: none;
}
#storage-root-container .volumes .wok-gallery.wok-datagrid .wok-datagrid-body > .wok-datagrid-row.selected .volume-box-border {
border-color: #8cc63f;
border-color: #8cc63f;
}
#storage-root-container .volumes .wok-gallery.wok-datagrid .wok-datagrid-body > .wok-datagrid-row.selected .volume-box-inner {
border-color: #000;
}
#storage-root-container .volumes .wok-gallery .volume-box-outer {
border-radius: 3px;
overflow: hidden;
}
#storage-root-container .volumes .wok-gallery .volume-box-border {
display: block;
border-width: 3px;
border-style: solid;
border-color: transparent;
border-color: rgba(255, 255, 255, 0);
transition: border-color .1s ease-in-out;
}
#storage-root-container .volumes .wok-gallery .volume-box-inner {
padding: 0 16px;
width: 409px;
height: auto;
display: flex;
flex-flow: row wrap;
justify-content: space-around;
border-width: 1px;
border-style: solid;
border-color: #fff;
background: #fff;
transition: border-color .1s ease-in-out;
}
#storage-root-container .volumes .wok-gallery span.column-name,
#storage-root-container .volumes .wok-gallery span.column-used {
height: 52px;
line-height: 52px;
border-bottom: 1px solid #ccc;
}
#storage-root-container .volumes .wok-gallery span.column-name {
width: 282px;
order: 1;
}
#storage-root-container .volumes .wok-gallery span.column-used {
width: 93px;
order: 2;
}
#storage-root-container .volumes .wok-gallery span.column-used-by {
width: 20px;
height: 20px;
order: 3;
position: absolute;
right: 22px;
top: 20px;
}
#storage-root-container .volumes .wok-gallery span.column-used-by .fa {
display: block;
color: #424242;
}
#storage-root-container .volumes .wok-gallery span.column-used-by .format-text {
display: none !important;
}
#storage-root-container .volumes .wok-gallery span.column-name label.volume-name {
width: 100%;
height: 52px;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
display: block;
margin: 0;
padding-right: 6px;
}
#storage-root-container .volumes .wok-gallery span.column-allocated,
#storage-root-container .volumes .wok-gallery span.column-capacity,
#storage-root-container .volumes .wok-gallery span.column-format,
#storage-root-container .volumes .wok-gallery span.column-type {
order: 3;
width: auto;
margin: 5px 0px;
}
#storage-root-container .volumes .wok-gallery span.gallery-header {
font-weight: 600;
display: block;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
width: 90px;
}
#storage-root-container .volumes .wok-gallery span.column-progress {
display: none;
}
#storage-root-container .volumes .wok-gallery .tooltip-iner {
font-size: 11pt;
padding: 6px 12px;
}
#storage-root-container .volumes .wok-list span.gallery-header {
display: none;
}
#storage-root-container .volumes .wok-list .volume-inline-progress {
vertical-align: middle;
display: inline-block;
margin-right: 7px;
}
#storage-root-container .volumes .wok-list .volume-inline-progress > i.wok-loading-icon {
margin-right: 0;
}
#storage-root-container .volumes .wok-list .volume-progress, #storage-root-container .volumes .wok-list .volume-progress * {
display: none !important;
}
#storage-root-container .volumes .wok-list .volume-box-inner {
font-size: 0;
}
#storage-root-container .volumes .wok-list.wok-datagrid > .wok-datagrid-header > span.column-name {
padding-left: 41px;
}
#storage-root-container .volumes .wok-list.wok-datagrid > .wok-datagrid-body {
overflow-y: auto;
overflow-x: hidden;
max-height: 350px;
}
#storage-root-container .volumes .wok-list.wok-datagrid > .wok-datagrid-body > .wok-datagrid-row {
position: relative;
cursor: pointer;
}
#storage-root-container .volumes .wok-list.wok-datagrid > .wok-datagrid-body > .wok-datagrid-row .volume-box-border {
border-color: rgba(255, 255, 255, 0);
border-width: 0px;
border-style: solid;
}
#storage-root-container .volumes .wok-list.wok-datagrid > .wok-datagrid-body > .wok-datagrid-row .volume-box-inner {
border-color: rgba(255, 255, 255, 0);
border-width: 0px;
border-style: solid;
}
#storage-root-container .volumes .wok-list.wok-datagrid > .wok-datagrid-body > .wok-datagrid-row.selected {
background: #ddd !important;
}
#storage-root-container .volumes .wok-list.wok-datagrid > .wok-datagrid-body > .wok-datagrid-row > div > div > div > span {
font-family: Helvetica, Arial, "Lucida Grande", sans-serif;
line-height: 2.42857;
vertical-align: top;
font-size: 12.5pt;
font-weight: 400;
}
#storage-root-container .volumes .wok-list.wok-datagrid > .wok-datagrid-body > .wok-datagrid-row > div > div > div > span.column-name {
padding-left: 15px;
}
#storage-root-container .volumes .wok-list.wok-datagrid > .wok-datagrid-header > span,
#storage-root-container .volumes .wok-list.wok-datagrid > .wok-datagrid-body > .wok-datagrid-row > div > div > div > span {
display: inline-block;
vertical-align: middle;
}
#storage-root-container .volumes .wok-list.wok-datagrid > .wok-datagrid-header > span.column-format,
#storage-root-container .volumes .wok-list.wok-datagrid > .wok-datagrid-body > .wok-datagrid-row > div > div > div > span.column-format {
width: 57px;
}
@media (min-width: 992px) {
#storage-root-container .volumes .wok-list.wok-datagrid > .wok-datagrid-header > span.column-format,
#storage-root-container .volumes .wok-list.wok-datagrid > .wok-datagrid-body > .wok-datagrid-row > div > div > div > span.column-format {
width: 127px;
}
}
@media (min-width: 1200px) {
#storage-root-container .volumes .wok-list.wok-datagrid > .wok-datagrid-header > span.column-format,
#storage-root-container .volumes .wok-list.wok-datagrid > .wok-datagrid-body > .wok-datagrid-row > div > div > div > span.column-format {
left: 173px;
}
}
#storage-root-container .volumes .wok-list.wok-datagrid > .wok-datagrid-header > span.column-used,
#storage-root-container .volumes .wok-list.wok-datagrid > .wok-datagrid-header > span.column-type,
#storage-root-container .volumes .wok-list.wok-datagrid > .wok-datagrid-header > span.column-capacity,
#storage-root-container .volumes .wok-list.wok-datagrid > .wok-datagrid-header > span.column-allocated,
#storage-root-container .volumes .wok-list.wok-datagrid > .wok-datagrid-header > span.column-progress,
#storage-root-container .volumes .wok-list.wok-datagrid > .wok-datagrid-body > .wok-datagrid-row > div > div > div > span.column-used,
#storage-root-container .volumes .wok-list.wok-datagrid > .wok-datagrid-body > .wok-datagrid-row > div > div > div > span.column-type,
#storage-root-container .volumes .wok-list.wok-datagrid > .wok-datagrid-body > .wok-datagrid-row > div > div > div > span.column-capacity,
#storage-root-container .volumes .wok-list.wok-datagrid > .wok-datagrid-body > .wok-datagrid-row > div > div > div > span.column-allocated,
#storage-root-container .volumes .wok-list.wok-datagrid > .wok-datagrid-body > .wok-datagrid-row > div > div > div > span.column-progress {
width: 79px;
text-transform: capitalize;
}
@media (min-width: 992px) {
#storage-root-container .volumes .wok-list.wok-datagrid > .wok-datagrid-header > span.column-used,
#storage-root-container .volumes .wok-list.wok-datagrid > .wok-datagrid-header > span.column-type,
#storage-root-container .volumes .wok-list.wok-datagrid > .wok-datagrid-header > span.column-capacity,
#storage-root-container .volumes .wok-list.wok-datagrid > .wok-datagrid-header > span.column-allocated,
#storage-root-container .volumes .wok-list.wok-datagrid > .wok-datagrid-header > span.column-progress,
#storage-root-container .volumes .wok-list.wok-datagrid > .wok-datagrid-body > .wok-datagrid-row > div > div > div > span.column-used,
#storage-root-container .volumes .wok-list.wok-datagrid > .wok-datagrid-body > .wok-datagrid-row > div > div > div > span.column-type,
#storage-root-container .volumes .wok-list.wok-datagrid > .wok-datagrid-body > .wok-datagrid-row > div > div > div > span.column-capacity,
#storage-root-container .volumes .wok-list.wok-datagrid > .wok-datagrid-body > .wok-datagrid-row > div > div > div > span.column-allocated,
#storage-root-container .volumes .wok-list.wok-datagrid > .wok-datagrid-body > .wok-datagrid-row > div > div > div > span.column-progress {
width: 142px;
}
}
@media (min-width: 1200px) {
#storage-root-container .volumes .wok-list.wok-datagrid > .wok-datagrid-header > span.column-used,
#storage-root-container .volumes .wok-list.wok-datagrid > .wok-datagrid-header > span.column-type,
#storage-root-container .volumes .wok-list.wok-datagrid > .wok-datagrid-header > span.column-capacity,
#storage-root-container .volumes .wok-list.wok-datagrid > .wok-datagrid-header > span.column-allocated,
#storage-root-container .volumes .wok-list.wok-datagrid > .wok-datagrid-header > span.column-progress,
#storage-root-container .volumes .wok-list.wok-datagrid > .wok-datagrid-body > .wok-datagrid-row > div > div > div > span.column-used,
#storage-root-container .volumes .wok-list.wok-datagrid > .wok-datagrid-body > .wok-datagrid-row > div > div > div > span.column-type,
#storage-root-container .volumes .wok-list.wok-datagrid > .wok-datagrid-body > .wok-datagrid-row > div > div > div > span.column-capacity,
#storage-root-container .volumes .wok-list.wok-datagrid > .wok-datagrid-body > .wok-datagrid-row > div > div > div > span.column-allocated,
#storage-root-container .volumes .wok-list.wok-datagrid > .wok-datagrid-body > .wok-datagrid-row > div > div > div > span.column-progress {
left: 165px;
}
}
#storage-root-container .volumes .wok-list.wok-datagrid > .wok-datagrid-header > span.column-used-by,
#storage-root-container .volumes .wok-list.wok-datagrid > .wok-datagrid-body > .wok-datagrid-row > div > div > div > span.column-used-by {
width: 69px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
padding-right: 5px;
}
@media (min-width: 992px) {
#storage-root-container .volumes .wok-list.wok-datagrid > .wok-datagrid-header > span.column-used-by,
#storage-root-container .volumes .wok-list.wok-datagrid > .wok-datagrid-body > .wok-datagrid-row > div > div > div > span.column-used-by {
width: 85px;
}
}
@media (min-width: 1200px) {
#storage-root-container .volumes .wok-list.wok-datagrid > .wok-datagrid-header > span.column-used-by,
#storage-root-container .volumes .wok-list.wok-datagrid > .wok-datagrid-body > .wok-datagrid-row > div > div > div > span.column-used-by {
width: 155px;
}
}
#storage-root-container .volumes .wok-list.wok-datagrid > .wok-datagrid-header > span.column-used-by .fa,
#storage-root-container .volumes .wok-list.wok-datagrid > .wok-datagrid-body > .wok-datagrid-row > div > div > div > span.column-used-by .fa {
display: none !important;
}
#storage-root-container .volumes .wok-list.wok-datagrid > .wok-datagrid-header > span.column-name,
#storage-root-container .volumes .wok-list.wok-datagrid > .wok-datagrid-body > .wok-datagrid-row > div > div > div > span.column-name {
width: 202px;
}
@media (min-width: 992px) {
#storage-root-container .volumes .wok-list.wok-datagrid > .wok-datagrid-header > span.column-name,
#storage-root-container .volumes .wok-list.wok-datagrid > .wok-datagrid-body > .wok-datagrid-row > div > div > div > span.column-name {
width: 450px;
}
}
@media (min-width: 1200px) {
#storage-root-container .volumes .wok-list.wok-datagrid > .wok-datagrid-header > span.column-name,
#storage-root-container .volumes .wok-list.wok-datagrid > .wok-datagrid-body > .wok-datagrid-row > div > div > div > span.column-name {
width: 500px;
}
}
#storage-root-container .volumes .wok-list.wok-datagrid > .wok-datagrid-header > span.column-name label,
#storage-root-container .volumes .wok-list.wok-datagrid > .wok-datagrid-body > .wok-datagrid-row > div > div > div > span.column-name label {
padding: 0 5px 0 0;
margin-right: 0;
margin-bottom: 0;
font-size: inherit;
font-weight: inherit;
width: 100%;
display: block;
height: auto;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
#storage-root-container .volumes .wok-list.wok-datagrid > .wok-datagrid-header > span.column-progress,
#storage-root-container .volumes .wok-list.wok-datagrid > .wok-datagrid-body > .wok-datagrid-row > div > div > div > span.column-progress {
white-space: nowrap;
}
#storage-root-container .wok-datagrid > .wok-datagrid-body > .wok-datagrid-row[data-stat="inactive"] {
color: #999 !important;
}
#storage-root-container .wok-datagrid > .wok-datagrid-header > span.column-state,
#storage-root-container .wok-datagrid > .wok-datagrid-body > .wok-datagrid-row > span.column-state {
width: 2.0519%;
text-align: center;
}
#storage-root-container .wok-datagrid > .wok-datagrid-header > span.column-name,
#storage-root-container .wok-datagrid > .wok-datagrid-body > .wok-datagrid-row > span.column-name {
width: 126px;
text-overflow: ellipsis;
display: inline-block;
white-space: nowrap;
overflow: hidden !important;
}
#storage-root-container .wok-datagrid > .wok-datagrid-header > span.column-type,
#storage-root-container .wok-datagrid > .wok-datagrid-body > .wok-datagrid-row > span.column-type {
width: 101px;
text-overflow: ellipsis;
display: inline-block;
white-space: nowrap;
overflow: hidden !important;
}
#storage-root-container .wok-datagrid > .wok-datagrid-header > span.column-location,
#storage-root-container .wok-datagrid > .wok-datagrid-body > .wok-datagrid-row > span.column-location {
width: 171px;
text-overflow: ellipsis;
display: inline-block;
white-space: nowrap;
overflow: hidden !important;
}
#storage-root-container .wok-datagrid > .wok-datagrid-header > span.column-usage,
#storage-root-container .wok-datagrid > .wok-datagrid-body > .wok-datagrid-row > span.column-usage {
width: 152px;
text-overflow: ellipsis;
display: inline-block;
white-space: nowrap;
overflow: hidden !important;
}
#storage-root-container .wok-datagrid > .wok-datagrid-header > span.column-usage .usage-icon,
#storage-root-container .wok-datagrid > .wok-datagrid-body > .wok-datagrid-row > span.column-usage .usage-icon {
padding-left: 35px;
display: inline-block;
background-repeat: no-repeat;
background-position: 0 50%;
background-color: transparent;
}
#storage-root-container .wok-datagrid > .wok-datagrid-header > span.column-usage .usage-icon.icon-high,
#storage-root-container .wok-datagrid > .wok-datagrid-body > .wok-datagrid-row > span.column-usage .usage-icon.icon-high {
background-image: url("../../../images/theme-default/high.png");
}
#storage-root-container .wok-datagrid > .wok-datagrid-header > span.column-usage .usage-icon.icon-med,
#storage-root-container .wok-datagrid > .wok-datagrid-body > .wok-datagrid-row > span.column-usage .usage-icon.icon-med {
background-image: url("../../../images/theme-default/med.png");
}
#storage-root-container .wok-datagrid > .wok-datagrid-header > span.column-usage .usage-icon.icon-low,
#storage-root-container .wok-datagrid > .wok-datagrid-body > .wok-datagrid-row > span.column-usage .usage-icon.icon-low {
background-image: url("../../../images/theme-default/low.png");
}
#storage-root-container .wok-datagrid > .wok-datagrid-header > span.column-capacity,
#storage-root-container .wok-datagrid > .wok-datagrid-body > .wok-datagrid-row > span.column-capacity {
width: 129px;
text-overflow: ellipsis;
display: inline-block;
white-space: nowrap;
overflow: hidden !important;
}
#storage-root-container .wok-datagrid > .wok-datagrid-header > span.column-allocated,
#storage-root-container .wok-datagrid > .wok-datagrid-body > .wok-datagrid-row > span.column-allocated {
width: 134px;
text-overflow: ellipsis;
display: inline-block;
white-space: nowrap;
overflow: hidden !important;
}
#storage-root-container .wok-datagrid > .wok-datagrid-header > span.column-disks,
#storage-root-container .wok-datagrid > .wok-datagrid-body > .wok-datagrid-row > span.column-disks {
text-align: center;
width: 105px;
text-overflow: ellipsis;
display: inline-block;
white-space: nowrap;
overflow: hidden !important;
}
#storage-root-container .wok-datagrid > .wok-datagrid-header > span.column-action,
#storage-root-container .wok-datagrid > .wok-datagrid-body > .wok-datagrid-row > span.column-action {
width: 254px;
text-align: right;
}
#storage-root-container .wok-datagrid > .wok-datagrid-body > .wok-datagrid-row > span.column-state {
height: 53px;
vertical-align: middle;
}
#storage-root-container .wok-datagrid > .wok-datagrid-body > .wok-datagrid-row > span.column-disks {
height: 53px;
vertical-align: middle;
}
#storage-root-container .wok-datagrid > .wok-datagrid-body > .wok-datagrid-row > span.column-disks .arrow-down,
#storage-root-container .wok-datagrid > .wok-datagrid-body > .wok-datagrid-row > span.column-disks .arrow-up {
display: inline-block;
font: normal normal normal 14px/1 FontAwesome;
font-size: inherit;
text-rendering: auto;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
#storage-root-container .wok-datagrid > .wok-datagrid-body > .wok-datagrid-row > span.column-disks .arrow-down:before {
content: "\f078";
}
#storage-root-container .wok-datagrid > .wok-datagrid-body > .wok-datagrid-row > span.column-disks .arrow-up:before {
content: "\f077";
}
#storage-root-container #logicalPoolExtend .modal-body {
max-height: 438px;
}
#storage-root-container #logicalPoolExtend .modal-body p span {
vertical-align: middle !important;
}
#storage-root-container #logicalPoolExtend form,
.storage-modal form {
margin: 0 !important;
}
#storage-root-container #logicalPoolExtend .host-partition,
.storage-modal .host-partition {
overflow-y: auto;
overflow-x: hidden;
max-height: 430px;
}
#storage-root-container #logicalPoolExtend .host-partition label,
.storage-modal .host-partition label {
display: block;
}
#storage-root-container #logicalPoolExtend .host-partition label > div,
.storage-modal .host-partition label > div {
vertical-align: top;
display: inline-block;
}
#storage-root-container #logicalPoolExtend .host-partition label span.device-name,
#storage-root-container #logicalPoolExtend .host-partition label span.device-path,
.storage-modal .host-partition label span.device-name,
.storage-modal .host-partition label span.device-path {
display: block;
}
#storage-root-container #logicalPoolExtend .host-partition label span.device-name,
.storage-modal .host-partition label span.device-name {
font-weight: 600;
overflow: hidden;
text-overflow: ellipsis;
}
#storage-root-container #logicalPoolExtend .host-partition label span.device-path,
.storage-modal .host-partition label span.device-path {
font-weight: 400;
word-wrap: break-word;
}
#storage-root-container #logicalPoolExtend .host-partition label > div {
width: 388px;
}
#storage-root-container #logicalPoolExtend .host-partition label > div span.device-path {
width: 388px;
}
.storage-modal .filter-select.popable .popover,
.storage-modal .storage-target-input .popover,
.storage-modal .storage-add-input .popover {
max-width: 100% !important;
width: 100%;
top: 34px;
left: -2px;
border: 0 !important;
background: 0 !important;
box-shadow: none !important;
}
.storage-modal .filter-select.popable .popover ul,
.storage-modal .storage-target-input .popover ul,
.storage-modal .storage-add-input .popover ul {
z-index: 1000;
padding: 5px 0;
margin: 2px 2px 0;
list-style: none;
font-size: 14px;
text-align: left;
background-color: #fcfcfc;
border: 1px solid #ccc;
border: 1px solid #ccc;
border-radius: 3px;
-webkit-box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175);
-moz-box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175);
box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175);
background-clip: padding-box;
}
.storage-modal .filter-select.popable .popover ul li,
.storage-modal .storage-target-input .popover ul li,
.storage-modal .storage-add-input .popover ul li {
cursor: pointer;
display: block;
padding: 3px 20px;
clear: both;
font-weight: normal;
line-height: 1.42857;
color: #222;
white-space: nowrap;
}
.storage-modal .filter-select.popable .popover ul li:hover, .storage-modal .filter-select.popable .popover ul li:focus,
.storage-modal .storage-target-input .popover ul li:hover,
.storage-modal .storage-target-input .popover ul li:focus,
.storage-modal .storage-add-input .popover ul li:hover,
.storage-modal .storage-add-input .popover ul li:focus {
text-decoration: none;
color: #151515;
background-color: #f5f5f5;
}
.storage-modal #nfspathId[style],
.storage-modal #nfsserverId[style] {
width: 100% !important;
}
.storage-modal .iscsi-section .form-group > .col-md-12 > .col-md-10 + .col-md-2 {
padding-left: 5px;
}
.storage-modal .iscsi-section .form-group > .col-md-12 > .col-md-10 {
padding-right: 5px;
}
.storage-modal .authenticationfield > div > .col-md-6 + .col-md-6 {
padding-left: 5px;
}
.storage-modal .authenticationfield > div > .col-md-6 {
padding-right: 5px;
}
.storage-modal .host-partition label > div {
width: 688px;
}
.storage-modal .host-partition label > div span.device-path {
width: 688px;
}
================================================
FILE: ui/css/src/kimchi.scss
================================================
/*
* Project Kimchi
*
* Copyright IBM Corp, 2015-2016
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//
// Wok Variables
// ----------------------------------------------------------------------------
@import "../../../../../../../ui/css/src/modules/wok-variables";
//
// Imported functions
// ----------------------------------------------------------------------------
@import "../../../../../../../ui/css/src/modules/compact";
@import "../../../../../../../ui/css/src/vendor/compass-mixins/lib/compass";
@import "../../../../../../../ui/css/src/vendor/bootstrap-sass/bootstrap/mixins";
//
// Extended classes
// ----------------------------------------------------------------------------
@import "../../../../../../../ui/css/src/modules/utils";
@import "../../../../../../../ui/css/src/modules/animation";
//
// Kimchi variables and classes
// ----------------------------------------------------------------------------
$virtColor: #8cc63f;
$storages-low: #8BC53E !default;
$guestCharts: (
lightGray: #e6e7e8,
mediumGray: #bbbdbf,
darkGray: #929497
);
@import "modules/iso-list";
@import "modules/guests";
@import "modules/edit-guests";
@import "modules/templates";
@import "modules/network";
@import "modules/storage";
================================================
FILE: ui/css/src/modules/_edit-guests.scss
================================================
//
// Project Kimchi
//
// Copyright IBM Corp, 2015-2017
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
#guest-edit-window {
.tab-content {
overflow: hidden;
height: auto;
}
.tab-content .tab-pane {
position: relative;
}
#form-guest-edit-general {
#guest-max-memory-panel,
#guest-max-processor-panel {
display: none;
}
#guest-edit-memory-textbox,
#guest-edit-max-memory-textbox,
#guest-edit-cores-textbox,
#guest-edit-max-processor-textbox {
width: 590px;
}
#guest-edit-memory-textbox,
#guest-show-max-memory {
display: inline-block;
}
}
#form-guest-edit-storage {
.column-actions {
width: 26%;
}
}
#form-guest-edit-snapshot {
.column-actions {
width: 22%;
}
}
#form-guest-edit-pci {
.wok-mask {
top: 0 !important;
z-index: 2 !important;
}
.column-actions {
width: 4.47%;
}
}
#form-edit-processor {
#guest-processor label {
display: block;
}
#guest-max-processor-panel label {
display: block;
}
#guest-max-processor-panel .form-control,
#guest-processor .form-control {
display: inline-block;
width: 184px;
}
.manual {
margin-top: 5px;
margin-bottom: 10px;
}
.topology {
display: none;
margin: 0 24px;
}
.topology label {
display: block;
}
}
form {
margin: 15px 0 0;
.header{
.cell.column-network,
.cell.column-mac {
display: inline-block;
overflow-x: hidden;
overflow-y: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
},
.task,
.body {
.column-actions {
text-align: right;
}
.column-device {
width: 12.7%;
}
.column-path {
width: 60.25%;
}
.cell.column-network {
width: 184px;
> span {
width: 100%;
display: inline-block;
text-overflow: ellipsis;
overflow: hidden;
}
}
.cell.column-type {
width: 184px;
}
.cell.column-mode {
width: 164px;
}
.cell.column-mac {
width: 174px;
}
.cell.column-ip {
width: 150px;
display: inline-block;
text-overflow: ellipsis;
white-space: nowrap;
}
.cell.column-sel {
width: 1.77%;
}
.cell.column-snapshot-name {
width: 58%;
}
.cell.column-snapshot-created {
width: 16.5%;
}
.cell.column-pci-status {
width: 3.7%;
.fa {
color: $virtColor;
font-size: 24px;
}
}
.cell.column-pci-name {
width: 21%;
}
.cell.column-product {
width: 45%;
}
.cell.column-vendor {
width: 24.1%;
}
}
.header {
background: $table-bg;
display: block;
border-bottom: 1px solid $table-border-color;
overflow: hidden;
clear: both;
> span {
padding: $table-cell-padding;
display: inline-block;
font-family: $font-family-light;
font-weight: 400;
font-size: 12.5pt;
vertical-align: bottom;
border-bottom: none;
border-top: 0;
line-height: $line-height-base;
&.column-actions {
height: 36px;
}
}
}
.body {
overflow-y: auto;
overflow-x: hidden;
height: 471px;
}
.body,
.task {
.item {
border-top: 1px solid $table-border-color;
height: 53px;
&:first-child {
border-top: 0;
}
> span {
padding: $table-cell-padding;
display: inline-block;
vertical-align: middle;
input[type="text"] {
height: 40px;
}
input[readonly],
input[readonly]:hover,
input[readonly]:focus,
input[readonly]:active {
background-color: transparent !important;
border-color: transparent !important;
box-shadow: none !important;
border-radius: 0 !important;
text-overflow: ellipsis;
padding-right: 0 !important;
padding-left: 0 !important;
width: 100%;
}
}
}
}
}
}
#guest-edit-window form .body .item:nth-child(even),
#guest-edit-window form .task .item:nth-child(even) {
background-color: $table-bg-accent;
}
#guest-edit-window form .body .item:nth-child(odd),
#guest-edit-window form .task .item:nth-child(odd) {
background-color: $table-bg;
}
#guest-edit-window form .header .cell.column-network .bootstrap-select:not([class*=col-]):not([class*=form-control]):not(.input-group-btn),
#guest-edit-window form .task .cell.column-network .bootstrap-select:not([class*=col-]):not([class*=form-control]):not(.input-group-btn),
#guest-edit-window form .body .cell.column-network .bootstrap-select:not([class*=col-]):not([class*=form-control]):not(.input-group-btn) {
width: 180px;
}
#guest-edit-window form .header .cell.column-mode .bootstrap-select:not([class*=col-]):not([class*=form-control]):not(.input-group-btn),
#guest-edit-window form .task .cell.column-mode .bootstrap-select:not([class*=col-]):not([class*=form-control]):not(.input-group-btn),
#guest-edit-window form .body .cell.column-mode .bootstrap-select:not([class*=col-]):not([class*=form-control]):not(.input-group-btn) {
width: 160px;
}
#guest-edit-window form .header .cell.column-type .bootstrap-select:not([class*=col-]):not([class*=form-control]):not(.input-group-btn),
#guest-edit-window form .task .cell.column-type .bootstrap-select:not([class*=col-]):not([class*=form-control]):not(.input-group-btn),
#guest-edit-window form .body .cell.column-type .bootstrap-select:not([class*=col-]):not([class*=form-control]):not(.input-group-btn) {
width: 180px;
}
.guest-edit-snapshot .hide,
.guest-edit-interface .hide {
display: none !important;
}
.guest-edit-pci {
.filter {
height: 40px;
overflow: visible;
clear: both;
}
.pull-right .bootstrap-select:not([class*=col-]):not([class*=form-control]):not(.input-group-btn) {
width: 133px;
}
.filter input[type="text"].form-control {
width: 460px;
height: 40px;
float: right;
border-top-left-radius: 0;
border-bottom-left-radius: 0;
}
.filter .bootstrap-select.btn-group .btn .caret {
border-left: 0;
}
.filter button.btn.dropdown-toggle.form-control.selectpicker.btn-default {
border-top-right-radius: 0 !important;
border-bottom-right-radius: 0 !important;
background: $table-bg-accent;
border-right: 0;
}
.body {
overflow-y: auto;
overflow-x: hidden;
height: 442px !important;
}
.body .item.disabled input[type="text"].form-control {
color: $gray-light;
}
.body .item.disabled span.column-pci-status i {
display: none;
}
}
.guest-edit-permission {
.pam {
height: 540px;
.column {
display: inline-block;
vertical-align: top;
}
.v-center {
min-height: 532px;
display: flex;
justify-content: center;
flex-flow: column wrap;
}
.center-block {
display: block;
margin-left: auto;
margin-right: auto;
}
.center-block + .center-block {
margin-top: 5px;
}
.title {
font-size: 13pt;
}
.body {
margin-top: 4px;
border-radius: 3px;
border: 1px solid $table-border-color;
height: 460px !important;
}
.body .head {
.item {
display: block;
padding: $table-cell-padding;
margin-bottom: 5px;
font-family: $font-family-light;
font-weight: 400;
font-size: 12.5pt;
vertical-align: bottom;
line-height: $line-height-base;
height: auto !important;
background: $table-bg;
border-top: 0;
border-bottom: 1px solid $table-border-color;
cursor: default;
}
}
.body > .column-user .item,
.body > .column-group .item {
height: auto !important;
margin-bottom: 0;
margin-left: 5px;
}
.body > .column-group .item {
margin-right: 5px;
}
.column-user label,
.column-group label {
cursor: pointer;
margin-bottom: 0;
margin-left: 5px;
width: 160px;
height: 24px;
line-height: 22px;
overflow: hidden;
text-overflow: ellipsis;
vertical-align: middle;
}
.body > .column .item {
background-color: $btn-default-bg !important;
border: 1px solid $table-border-color !important;
margin-bottom: 3px;
display: block;
padding: .2em .6em .3em;
font-weight: 700;
line-height: 1;
text-align: left;
white-space: nowrap;
vertical-align: middle;
border-radius: .25em;
overflow: hidden;
}
.body > .column .item:hover {
color: $btn-default-color !important;
background-color: #e6e6e6 !important;
border-color: #adadad !important;
label {
color: $btn-default-color !important;
}
}
.body > .column .item.item-picked {
color: $btn-primary-color !important;
background-color: $btn-primary-bg !important;
border-color: #1b1b1c !important;
outline: 5px auto -webkit-focus-ring-color;
outline-offset: -2px;
label {
color: $btn-primary-color !important;
}
}
}
.hide {
display: none;
}
}
#form-guest-edit-permission .ldap .body .item {
margin: 8px 0;
}
#form-guest-edit-permission .ldap .cell {
width: 250px;
}
#form-guest-edit-permission .ldap .action-area {
float: right;
line-height: 24px;
}
#form-guest-edit-permission .ldap .header button {
margin-bottom: 1px;
}
#form-guest-edit-permission .ldap .checked {
border-color: red;
border-style: solid;
border-width: 1px;
}
#form-guest-edit-permission .ldap .checked.hide {
display: none;
}
#guest-storage-add-window {}
#form-guest-storage-add .form-section .field {
overflow: visible;
}
ul {
cursor: default;
}
.boot-order {
display: block;
width: 85%;
font-size: 14px;
line-height: 1.42857;
color: #444;
overflow: hidden;
background-color: #fff;
background-image: none;
border: 1px solid #ccc;
border-radius: 3px;
-webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
-webkit-transition: border-color ease-in-out 0.15s, box-shadow ease-in-out 0.15s;
-o-transition: border-color ease-in-out 0.15s, box-shadow ease-in-out 0.15s;
transition: border-color ease-in-out 0.15s, box-shadow ease-in-out 0.15s;
}
.boot-order:focus,
.boot-order.focus {
border-color: #66afe9;
outline: 0;
-webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(102, 175, 233, 0.6);
box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(102, 175, 233, 0.6);
}
.boot-order > li {
cursor: move; /* fallback if grab cursor is unsupported */
cursor: grab;
cursor: -moz-grab;
cursor: -webkit-grab;
border-left: 0;
border-right: 0;
}
.boot-order > li:first-child {
border-top: 0;
}
.boot-order > li:last-child {
border-bottom: 0;
}
.boot-order > li.ui-sortable-helper {
cursor: grabbing;
cursor: -moz-grabbing;
cursor: -webkit-grabbing;
border: 1px solid #ccc !important;
}
.boot-order li i {
text-align: right;
}
================================================
FILE: ui/css/src/modules/_guests.scss
================================================
//
// Project Kimchi
//
// Copyright IBM Corp, 2015-2016
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
/* Create Guest Modal */
.guests-modal {
.modal-dialog {
width: 1100px;
}
.page-list {
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
overflow: hidden;
}
.page {
position: absolute;
left: 0;
width: 100%;
height: 100%;
overflow: auto;
padding: 10px 30px;
}
.template-status {
position: absolute;
right: 15px;
bottom: 15px;
font-size: 32px;
}
}
#wok-confirm-modal .modal-body strong,
.modal-dialog .modal-body strong {
border-bottom: 1px dotted;
}
#guest-add-window {
.modal-body {
margin: 0;
padding: 0;
}
.modal-footer {
margin-top: 0;
}
.modal-footer .btn + .btn {
margin-left: 0;
}
.modal-footer .btn {
margin-right: 5px;
}
.modal-dialog {
width: 900px;
}
.guest-modal-container {
padding: 10px 30px;
position: relative;
}
.guest-pager {
background: $table-border-color;
overflow: hidden;
position: relative;
height: 530px;
}
&.modal-content p {
margin: 0 0 10px 0;
}
&.modal-content h5 {
font-size: 13pt;
font-weight: 400;
margin-top: 0;
}
&.modal-content label {
font-size: 16px;
font-weight: 400;
font-family: $font-family-sans-serif;
}
form#form-vm-add {
margin: 0;
}
input#guest-vm-name,
p.help-block {
width: 592px;
}
}
#guest-content-container {
.wok-guest-list {
display: block;
width: 100%;
padding: 0;
list-style-type: none;
.wok-guest-list-body > ul {
list-style: none;
padding: 0;
> li:nth-child(even) {
background-color: #fcfcfc;
}
> li:nth-child(odd) {
background-color: #fff;
}
> li:first-child {
border-top: 0;
}
}
.wok-guest-list-header {
border-top: 0 none;
height: 36px;
> span {
height: 36px;
padding: 6px 2px;
display: inline-block;
vertical-align: middle;
font-family: $font-family-sans-serif;
font-weight: 300;
font-size: 12.5pt;
line-height: 1.42857;
border-bottom: none;
border-top: 0;
overflow: hidden;
> span {
width: 100%;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
display: block;
}
}
}
.wok-guest-list-item {
border-top: 1px solid $table-border-color;
> span {
padding: 6px 2px;
display: inline-block;
vertical-align: middle;
font-family: $font-family-sans-serif;
font-size: 12.5pt;
line-height: 2.42857;
font-weight: 400;
}
.nodata,
.screenshot {
display: none;
}
.column-name.distro-icon {
background: none;
}
.progress {
display: inline-block;
width: 60%;
position: relative;
vertical-align: top;
margin-top: 15px;
border-radius: 0;
-webkit-box-shadow: none;
box-shadow: none;
}
.progress-bar {
position: absolute;
top: 0;
left: 0;
-webkit-box-shadow: none;
box-shadow: none;
&.dark-grey {
background-color: map-get($guestCharts, darkGray);
}
&.medium-grey {
background-color: map-get($guestCharts, mediumGray);
}
&.light-grey {
background-color: map-get($guestCharts, lightGray);
}
}
.column-type {
padding-left: 40px;
}
.column-actions .btn {
margin-top: 6px;
}
div.percentage-label {
display: inline-block;
width: 25%;
margin-top: 6px;
}
div.measure-label {
display: inline-block;
width: 35%;
margin-top: 6px;
}
.item-hidden {
display: none;
}
.btn .guest-state {
display: none;
}
}
}
.wok-guest-gallery {
list-style: none;
padding: 0 0 0 5px;
> li.wok-guest-list-header {
display: none;
}
> li > ul {
list-style: none;
padding: 0;
}
.wok-guest-list-item {
padding: 0;
width: 290px;
height: 435px;
display: inline-block;
border: 0;
background: $body-bg;
margin-right: 20px;
margin-bottom: 20px;
position: relative;
vertical-align: top;
&.inactive {
.progress,
.item-hidden,
[class^="column-"] {
display: none;
}
.nodata {
display: block;
padding-top: 115px;
padding-bottom: 115px;
text-align: center;
}
span.column-action,
span.column-name {
display: block !important;
}
.btn {
background: #4d4c4e !important;
}
}
> span {
display: inline-block;
width: 100%;
font-family: $font-family-sans-serif;
font-size: 12.5pt;
line-height: $line-height-base;
font-weight: 400;
}
.progress {
display: block;
float: right;
width: 125px;
height: 18px;
position: relative;
vertical-align: top;
margin-top: 0;
margin-bottom: 0;
border-radius: 0;
-webkit-box-shadow: none;
box-shadow: none;
}
.progress-bar {
position: absolute;
top: 0;
left: 0;
-webkit-box-shadow: none;
box-shadow: none;
&.dark-grey {
background-color: map-get($guestCharts, darkGray);
}
&.medium-grey {
background-color: map-get($guestCharts, mediumGray);
}
&.light-grey {
background-color: map-get($guestCharts, lightGray);
}
}
.item-hidden {
clear: both;
display: block;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
position: relative;
top: -10px;
}
.column-action.pull-right {
position: absolute;
}
.ul-body {
display: inline-block;
padding: 0;
margin: 0;
list-style: none;
}
.column-type,
.nodata,
.column-vnc,
.column-state {
display: none;
}
.column-name {
line-height: 2.5 !important;
font-size: 15.3pt !important;
font-weight: 500 !important;
text-overflow: ellipsis !important;
overflow: hidden !important;
padding-right: 35px !important;
padding-left: 20px;
margin-right: 20px;
display: block;
width: 290px;
white-space: nowrap;
cursor: default;
}
.column-processors,
.column-memory,
.column-storage,
.column-network {
margin-top: 14px;
display: block;
height: 38px;
padding-left: 20px;
padding-right: 18px;
}
.column-processors {
margin-top: 18px !important;
}
.percentage-label,
.measure-label {
float: left;
display: block;
width: 68px;
font-size: 21px;
font-weight: 600;
top: -7px;
position: relative;
}
.font-bold {
font-weight: bold !important;
}
.pull-right {
float: none !important;
}
.dropdown-menu {
width: 100%;
}
.screenshot {
width: 100%;
height: 148px;
background-size: cover;
background-repeat: no-repeat;
}
.menu-flat {
width: 290px;
}
.btn {
width: 100%;
text-align: left;
padding-left: 21px;
border-radius: 0;
background: rgba(0, 0, 0, .6) !important;
> span.guest-state {
.fa {
margin-right: 10px;
}
}
> span.guest-state.running {
span.running {
display: block;
}
span.shutoff,
span.starting,
span.crashed,
span.nostate,
span.paused,
span.pmsuspended,
span.resetting {
display: none;
}
}
> span.guest-state.shutoff {
span.shutoff {
display: block;
}
span.running,
span.starting,
span.crashed,
span.nostate,
span.paused,
span.pmsuspended,
span.resetting {
display: none;
}
}
> span.guest-state.starting {
span.starting {
display: block;
}
span.running,
span.shutoff,
span.crashed,
span.nostate,
span.paused,
span.pmsuspended,
span.resetting {
display: none;
}
}
> span.guest-state.crashed {
span.crashed {
display: block;
}
span.running,
span.shutoff,
span.starting,
span.nostate,
span.paused,
span.pmsuspended,
span.resetting {
display: none;
}
}
> span.guest-state.nostate {
span.nostate {
display: block;
}
span.running,
span.shutoff,
span.starting,
span.crashed,
span.paused,
span.pmsuspended,
span.resetting {
display: none;
}
}
> span.guest-state.paused {
span.paused {
display: block;
}
span.running,
span.shutoff,
span.starting,
span.crashed,
span.nostate,
span.pmsuspended,
span.resetting {
display: none;
}
}
> span.guest-state.pmsuspended {
span.pmsuspended {
display: block;
}
span.running,
span.shutoff,
span.starting,
span.crashed,
span.nostate,
span.paused,
span.resetting {
display: none;
}
}
> span.guest-state.resetting {
span.resetting {
display: block;
}
span.running,
span.shutoff,
span.starting,
span.crashed,
span.nostate,
span.paused,
span.pmsuspended {
display: none;
}
}
}
.guest-actions {
display: none;
}
.guest-state {
display: block;
}
}
}
.wok-guest-list .wok-guest-list-body .wok-guest-list-item,
.wok-guest-gallery .wok-guest-list-body .wok-guest-list-item {
> span.column-processors {
> div > div.progress-bar.cpu-progress-bar {
background-color: #d9182d;
}
}
> span.column-memory {
> div > div.progress-bar.memory-progress-bar {
background-color: #008abf;
}
}
> span.column-storage {
> div > div.progress-bar.storage-progress-bar {
background-color: $state-warning-border;
}
}
> span.column-network {
> div > div.progress-bar.network-progress-bar {
background-color: #7f1c7d;
}
}
}
.wok-guest-list .wok-guest-list-body .wok-guest-list-item > span.column-state {
> span.guest-state.running {
span.running {
display: block;
}
.fa {
color: $fa-green;
}
}
> span.guest-state.pmsuspended {
span.pmsuspended {
display: block;
}
.fa {
color: $gray-light;
}
}
> span.guest-state.nostate {
span.nostate {
display: block;
}
.fa {
color: $gray-light;
}
}
> span.guest-state.crashed {
span.crashed {
display: block;
}
.fa {
color: $gray-light;
}
}
> span.guest-state.shutdown,
> span.guest-state.blocked,
> span.guest-state.shutoff {
span.shutoff,
span.blocked,
span.shutdown {
display: block;
}
.fa {
color: $gray-light;
}
}
> span.guest-state.starting {
span.starting {
display: block;
}
.fa {
color: $gray-light;
}
}
> span.guest-state.paused {
span.paused {
display: block;
}
.fa {
color: $gray-light;
}
}
> span.guest-state.resetting {
span.resetting {
display: block;
}
.fa {
color: $fa-green;
}
}
}
.wok-guest-list .wok-guest-list-header,
.wok-guest-list .wok-guest-list-body .wok-guest-list-item {
> span.column-state {
width: 40px;
text-align: center;
> span.guest-state {
font-size: 22px;
position: relative;
span.text-status {
display: none;
}
}
> span.guest-state span {
display: none;
}
}
> span.column-name {
width: 13.7%;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
@media (min-width: $screen-lg + 130) {
width: 9.7%;
}
@media (min-width: $screen-xlg) {
width: 12%;
}
}
> span.column-type {
width: 11.74%;
background-position: 0 50%;
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
@media (min-width: $screen-lg + 130) {
width: 10.74%;
}
}
> span.column-vnc {
display: none;
> a {
font-weight: normal;
color: $vnc-blue !important;
}
.fa-spin {
display: none
}
.fa-spin.active {
display: inline-block;
margin-right: 8px;
font-size: 22px;
color: $vnc-blue !important;
}
@media (min-width: $screen-lg + 130) {
width: 10%;
display: inline-block;
}
}
> span.column-processors,
> span.column-memory,
> span.column-storage,
> span.column-network {
width: 13%;
}
> span.column-action {
width: 165px;
}
> span.item-hidden {
display: none !important;
}
.btn .guest-pending {
margin-left: -38px;
margin-right: -45px;
}
}
.wok-guest-list .distro-icon.inactive {
-webkit-filter: grayscale(100%) contrast(0.8) brightness(110%);
-moz-filter: grayscale(100%) contrast(0.8) brightness(110%);
filter: grayscale(100%) contrast(0.8) brightness(110%);
}
.wok-guest-list .wok-guest-list-body.inactive {
color: $disabled-color !important;
}
.distro-icon {
background-color: transparent;
background-size: 32px 32px;
background-repeat: no-repeat;
background-position: 100% 50%;
&.icon-centos {
background-image: url('../images/icon-centos.png');
}
&.icon-debian {
background-image: url('../images/icon-debian.png');
}
&.icon-fedora {
background-image: url('../images/icon-fedora.png');
}
&.icon-opensuse {
background-image: url('../images/icon-opensuse.png');
}
&.icon-sles {
background-image: url('../images/icon-sles.png');
}
&.icon-ubuntu {
background-image: url('../images/icon-ubuntu.png');
}
&.icon-gentoo {
background-image: url('../images/icon-gentoo.png');
}
&.icon-unknown {
background-image: url('../images/icon-vm.png');
}
}
}
body.wok-gallery {
background: $input-bg-disabled;
}
================================================
FILE: ui/css/src/modules/_iso-list.scss
================================================
//
// Project Kimchi
//
// Copyright IBM Corp, 2015-2016
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
/* Template & Guests Modal Windows */
#template-add-window.modal-content,
#guest-add-window.modal-content {
label.box-iso-outer {
font-family: $font-family-sans-serif;
font-size: 14px !important;
font-weight: 400;
border-radius: 3px;
overflow: hidden;
display: block;
-webkit-user-select: none;
user-select: none;
}
label.box-iso-outer span.box-iso-border {
display: block;
border: 3px solid transparent;
transition: all .1s ease-in-out;
}
label.box-iso-outer .iso-radio-hidden:checked + span.box-iso-border,
label.box-iso-outer .iso-checkbox-hidden:checked + span.box-iso-border {
border-color: $virtColor;
}
label.box-iso-outer .iso-radio-hidden:checked + span.box-iso-border > .box-iso-inner,
label.box-iso-outer .iso-checkbox-hidden:checked + span.box-iso-border > .box-iso-inner {
border-color: $gray-base;
}
label.box-iso-outer span.box-iso-inner {
display: block;
border: 1px solid transparent;
background: $body-bg;
transition: all .1s ease-in-out;
}
label.box-iso-outer span.box-iso-inner .tooltip-inner {
font-size: 10pt;
padding: 6px 8px;
}
label.box-iso-outer span.box-iso-inner .tooltip-inner {
max-width: 300px;
}
label.box-iso-outer span.box-iso-inner .tooltip[style] {
left: 7px !important;
right: 7px !important;
}
label.box-iso-outer span.box-iso-inner .tooltip-arrow[style] {
left: 216px !important;
}
li[data-invalid="invalid"] label.box-iso-outer {
color: $gray-light !important;
}
li[data-invalid="invalid"] label.box-iso-outer span.box-iso-inner {
background: rgba($body-bg, 0.4);
}
ul.list-template,
ul.list-iso {
display: block;
overflow-x: hidden;
overflow-y: auto;
max-height: 462px;
list-style: none;
margin: 0 -5px 10px -5px;
padding: 0;
}
label.box-iso-outer span.box-iso-inner dl {
margin-bottom: 16px;
}
label.box-iso-outer span.box-iso-inner dt,
label.box-iso-outer span.box-iso-inner dd {
padding: 0 12px 0 20px;
}
label.box-iso-outer span.box-iso-inner dt {
padding-top: 5px;
text-transform: capitalize;
}
label.box-iso-outer span.box-iso-inner dd {
padding-bottom: 5px;
}
ul#templateTile input[type="radio"].iso-radio-hidden,
ul#list-local-iso input[type="checkbox"].iso-checkbox-hidden,
ul#list-remote-iso input[type="checkbox"].iso-checkbox-hidden {
display: none;
}
label.box-iso-outer {
cursor: pointer;
}
ul#list-local-iso li.col-md-3,
ul#list-remote-iso li.col-md-3 {
width: 239px;
margin: 10px 5px 0;
}
h3.iso-title {
font-size: 22px;
font-weight: 300;
line-height: 22px;
margin: 0;
padding: 13px 40px 13px 20px;
background-color: transparent;
background-position: right 10px center;
background-repeat: no-repeat;
background-size: auto 27px;
background-origin: padding-box;
max-width: 100%;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
&.centos {
background-image: url('../images/icon-centos.png');
}
&.debian {
background-image: url('../images/icon-debian.png');
}
&.fedora {
background-image: url('../images/icon-fedora.png');
}
&.opensuse {
background-image: url('../images/icon-opensuse.png');
}
&.suse {
background-image: url('../images/icon-sles.png');
}
&.ubuntu {
background-image: url('../images/icon-ubuntu.png');
}
&.gentoo {
background-image: url('../images/icon-gentoo.png');
}
&.unknown {
background-image: url('../images/icon-vm.png');
}
}
}
================================================
FILE: ui/css/src/modules/_network.scss
================================================
//
// Project Kimchi
//
// Copyright IBM Corp, 2015-2017
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
.network-config input.invalid-field[type="text"] {
border-color: #FF4444;
}
.network-config input.invalid-field[type="text"][disabled] {
border-color: #666666;
}
#add-network-window {
#vlan-enabled {
padding-left: 26px;
label, input[type="text"] {
display: block;
}
}
}
#networkConfig .alert-dismissable .close, .alert-dismissible .close{
right: -2px !important;
}
#network-root-container {
.wok-datagrid-body {
span > .fa {
font-size: 22px;
width: 22px;
position: relative;
}
.loading .fa-spinner {
display: inline-block;
}
.up .fa-power-off {
color: $fa-green;
}
.down .fa-power-off {
display: none;
}
}
.wok-datagrid > .wok-datagrid-header,
.wok-datagrid > .wok-datagrid-body > .wok-datagrid-row {
> span.column-state {
width: 2.92207%;
text-align: center;
}
> span.column-name {
width: 19.2207%;
}
> span.column-type {
width: 11.3896%;
}
> span.column-interface {
width: 15.3896%;
padding-right: 40px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
> span.column-space {
width: 25%;
}
> span.column-action {
width: 25.909%;
text-align: right;
}
}
.wok-datagrid > .wok-datagrid-body > .wok-datagrid-row > span {
&.column-state {
height: 53px;
vertical-align: middle;
}
}
}
#add-network-window {
#networkConfig {
#alert-modal-container .alert {
padding: 8px 34px 8px 16px;
}
}
}
================================================
FILE: ui/css/src/modules/_storage.scss
================================================
//
// Project Kimchi
//
// Copyright IBM Corp, 2015-2017
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
#storage-root-container {
.wok-datagrid-body {
span > .fa {
font-size: 22px;
width: 20px;
height: 20px;
position: relative;
}
.handle {
-webkit-user-select: none;
-moz-user-select: none;
user-select: none;
position: relative;
}
.active {
.handle {
cursor: pointer;
}
.fa-power-off {
color: $fa-green;
}
}
.inactive {
.handle {
cursor: default;
}
.fa-power-off {
display: none;
}
.usage-icon.icon-high {
background-image: url('../../#{$wok-icon-path}/high_disabled.png') !important;
}
.usage-icon.icon-med {
background-image: url('../../#{$wok-icon-path}/med_disabled.png') !important;
}
.usage-icon.icon-low {
background-image: url('../../#{$wok-icon-path}/low_disabled.png') !important;
}
}
}
.volumes {
width: 100%;
background: $navbar-default-toggle-hover-bg;
display: none;
.tooltip > .tooltip-inner {
width: 150px;
}
input[type=checkbox][disabled].wok-checkbox + label:before {
content: '';
}
.toggle-gallery {
left: 202px;
@media (min-width: $screen-lg) {
left: 282px;
}
}
> .footer {
z-index: 100;
}
.volumeslist {
padding: 22px;
min-height: 188px;
max-height: 505px;
overflow: hidden;
}
.volumeslist .wok-list {
min-height: inherit;
}
.volumeslist .row {
font-size: 0;
margin-bottom: 22px;
}
.volumeslist .filter {
width: 344px;
height: 38px;
margin-top: 1px;
@media (min-width: $screen-md) {
width: 514px;
}
}
.pool-action {
display: inline-block;
margin-right: 20px;
}
.volume-icon {
display: inline-block;
vertical-align: middle;
width: 27px;
height: 27px;
line-height: 27px;
background-repeat: no-repeat;
background-position: 50%;
background-color: transparent;
}
.volume-icon.icon-high {
background-image: url('../../#{$wok-icon-path}/high.png');
}
.volume-icon.icon-med {
background-image: url('../../#{$wok-icon-path}/med.png');
}
.volume-icon.icon-low {
background-image: url('../../#{$wok-icon-path}/low.png');
}
.volume-progress {
position: absolute;
margin: 0;
width: 407px;
top: 4px;
left: 4px;
.progress-bar-outer {
background: $table-bg-hover;
height: 6px;
overflow: hidden;
width: 100%;
}
.progress-bar-inner {
background: $storages-low;
height: 100%;
width: 100%;
}
}
.volume-data {
margin: 0;
padding: 0;
list-style: none;
> li {
display: inline-block;
width: 89px;
span {
display: block;
font-size: 12pt;
}
span.value {
font-weight: 600;
}
span.key {
font-weight: 300;
}
}
}
.pool-empty{
width: 100%;
cursor: default !important;
> span {
width: 100%;
text-align: center;
line-height: 136px;
vertical-align: middle !important;
}
}
.wok-gallery {
&.wok-datagrid {
background: transparent;
margin-top: -12px;
}
&.wok-datagrid > .wok-datagrid-header {
display: none;
}
&.wok-datagrid > .wok-datagrid-body {
margin-left: -3px;
overflow-y: auto;
overflow-x: hidden;
max-height: 400px;
}
&.wok-datagrid .wok-datagrid-body > .wok-datagrid-row {
position: relative;
cursor: pointer;
background: $body-bg !important;
border: 0 !important;
display: inline-block !important;
width: 415px !important;
margin: 12px 4px 0;
&, * {
-webkit-user-select: none;
-moz-user-select: none;
user-select: none;
}
}
&.wok-datagrid .wok-datagrid-body > .wok-datagrid-row.selected .volume-box-border {
border-color: $virtColor;
border-color: rgba($virtColor,1);
}
&.wok-datagrid .wok-datagrid-body > .wok-datagrid-row.selected .volume-box-inner {
border-color: $gray-base;
}
.volume-box-outer {
border-radius: 3px;
overflow: hidden;
}
.volume-box-border {
display: block;
border-width: 3px;
border-style: solid;
border-color: transparent;
border-color: rgba(255,255,255,0);
transition: border-color .1s ease-in-out
}
.volume-box-inner {
padding: 0 16px;
width: 409px;
height: auto;
display: flex;
flex-flow: row wrap;
justify-content: space-around;
border-width: 1px;
border-style: solid;
border-color: #fff;
background: #fff;
transition: border-color .1s ease-in-out;
}
span.column-name,
span.column-used {
height: 52px;
line-height: 52px;
border-bottom: 1px solid $input-border;
}
span.column-name {
width: 282px;
order: 1;
}
span.column-used {
width: 93px;
order: 2;
}
span.column-used-by {
width: 20px;
height: 20px;
order: 3;
position: absolute;
right: 22px;
top: 20px;
.fa {
display: block;
color: #424242;
}
.format-text {
display: none !important;
}
}
span.column-name label.volume-name {
width: 100%;
height: 52px;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
display: block;
margin: 0;
padding-right: 6px;
}
span.column-allocated,
span.column-capacity,
span.column-format,
span.column-type {
order: 3;
width: auto;
margin: 5px 0px;
}
span.gallery-header {
font-weight: 600;
display: block;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
width: 90px;
}
span.column-progress {
display: none;
}
.tooltip-iner {
font-size: 11pt;
padding: 6px 12px;
}
}
.wok-list {
span.gallery-header {
display: none;
}
.volume-inline-progress {
vertical-align: middle;
display: inline-block;
margin-right: 7px;
}
.volume-inline-progress > i.wok-loading-icon {
margin-right: 0;
}
.volume-progress, .volume-progress * {
display: none !important;
}
.volume-box-inner {
font-size: 0;
}
&.wok-datagrid > .wok-datagrid-header {
> span.column-name {
padding-left: 41px;
}
}
&.wok-datagrid > .wok-datagrid-body {
overflow-y: auto;
overflow-x: hidden;
max-height: 350px;
}
&.wok-datagrid > .wok-datagrid-body > .wok-datagrid-row {
position: relative;
cursor: pointer;
.volume-box-border {
border-color: rgba(255,255,255,0);
border-width: 0px;
border-style: solid;
}
.volume-box-inner {
border-color: rgba(255,255,255,0);
border-width: 0px;
border-style: solid;
}
}
&.wok-datagrid > .wok-datagrid-body > .wok-datagrid-row.selected {
background: $table-bg-hover !important;
}
&.wok-datagrid > .wok-datagrid-body > .wok-datagrid-row > div > div > div {
> span {
font-family: $font-family-sans-serif;
line-height: (1 + $line-height-base);
vertical-align: top;
font-size: 12.5pt;
font-weight: 400;
}
> span.column-name {
padding-left: 15px;
}
}
&.wok-datagrid > .wok-datagrid-header,
&.wok-datagrid > .wok-datagrid-body > .wok-datagrid-row > div > div > div {
>span {
display: inline-block;
vertical-align: middle;
}
> span.column-format {
width: 57px;
@media (min-width: $screen-md) {
width: 127px;
}
@media (min-width: $screen-lg) {
left: 173px;
}
}
> span.column-used,
> span.column-type,
> span.column-capacity,
> span.column-allocated,
> span.column-progress {
width: 79px;
text-transform: capitalize;
@media (min-width: $screen-md) {
width: 142px;
}
@media (min-width: $screen-lg) {
left: 165px;
}
}
> span.column-used-by {
width: 69px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
padding-right: 5px;
@media (min-width: $screen-md) {
width: 85px;
}
@media (min-width: $screen-lg) {
width: 155px;
}
.fa {
display: none !important;
}
}
> span.column-name {
width: 202px;
@media (min-width: $screen-md) {
width: 450px;
}
@media (min-width: $screen-lg) {
width: 500px;
}
label {
padding: 0 5px 0 0;
margin-right: 0;
margin-bottom: 0;
font-size: inherit;
font-weight: inherit;
width: 100%;
display: block;
height: auto;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
}
> span.column-progress {
white-space: nowrap;
}
}
}
}
.wok-datagrid > .wok-datagrid-body > .wok-datagrid-row[data-stat="inactive"] {
color: $gray-light !important;
}
.wok-datagrid > .wok-datagrid-header,
.wok-datagrid > .wok-datagrid-body > .wok-datagrid-row {
> span.column-state {
width: 2.0519%;
text-align: center;
}
> span.column-name {
width: 126px;
text-overflow: ellipsis;
display: inline-block;
white-space: nowrap;
overflow: hidden !important;
}
> span.column-type {
width: 101px;
text-overflow: ellipsis;
display: inline-block;
white-space: nowrap;
overflow: hidden !important;
}
> span.column-location {
width: 171px;
text-overflow: ellipsis;
display: inline-block;
white-space: nowrap;
overflow: hidden !important;
}
> span.column-usage {
width: 152px;
text-overflow: ellipsis;
display: inline-block;
white-space: nowrap;
overflow: hidden !important;
.usage-icon {
padding-left: 35px;
display: inline-block;
background-repeat: no-repeat;
background-position: 0 50%;
background-color: transparent;
&.icon-high {
background-image: url('../../#{$wok-icon-path}/high.png');
}
&.icon-med {
background-image: url('../../#{$wok-icon-path}/med.png');
}
&.icon-low {
background-image: url('../../#{$wok-icon-path}/low.png');
}
}
}
> span.column-capacity {
width: 129px;
text-overflow: ellipsis;
display: inline-block;
white-space: nowrap;
overflow: hidden !important;
}
> span.column-allocated {
width: 134px;
text-overflow: ellipsis;
display: inline-block;
white-space: nowrap;
overflow: hidden !important;
}
> span.column-disks {
text-align: center;
width: 105px;
text-overflow: ellipsis;
display: inline-block;
white-space: nowrap;
overflow: hidden !important;
}
> span.column-action {
width: 254px;
text-align: right;
}
}
.wok-datagrid > .wok-datagrid-body > .wok-datagrid-row > span {
&.column-state {
height: 53px;
vertical-align: middle;
}
&.column-disks {
height: 53px;
vertical-align: middle;
.arrow-down,
.arrow-up {
display: inline-block;
font: normal normal normal 14px/1 FontAwesome;
font-size: inherit;
text-rendering: auto;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.arrow-down:before {
content: "\f078";
}
.arrow-up:before {
content: "\f077";
}
}
}
}
#storage-root-container #logicalPoolExtend {
.modal-body {
max-height: 438px;
p span {
vertical-align: middle !important;
}
}
}
#storage-root-container #logicalPoolExtend,
.storage-modal {
form {
margin: 0 !important;
}
.host-partition {
overflow-y: auto;
overflow-x: hidden;
max-height: 430px;
label {
display: block;
> div {
vertical-align: top;
display: inline-block;
}
span.device-name,
span.device-path {
display: block;
}
span.device-name {
font-weight: 600;
overflow: hidden;
text-overflow: ellipsis;
}
span.device-path {
font-weight: 400;
word-wrap: break-word;
}
}
}
}
#storage-root-container #logicalPoolExtend {
.host-partition label > div {
width: 388px;
span.device-path {
width: 388px;
}
}
}
.storage-modal {
// Wok Popable
.filter-select.popable,
.storage-target-input,
.storage-add-input {
.popover {
max-width: 100% !important;
width: 100%;
top: 34px;
left: -2px;
border: 0 !important;
background: 0 !important;
box-shadow: none !important;
ul {
z-index: $zindex-dropdown;
padding: 5px 0;
margin: 2px 2px 0;
list-style: none;
font-size: $font-size-base;
text-align: left;
background-color: $dropdown-bg;
border: 1px solid $dropdown-fallback-border;
border: 1px solid $dropdown-border;
border-radius: $border-radius-base;
-webkit-box-shadow: compact(0 6px 12px rgba(0, 0, 0, 0.175));
-moz-box-shadow: compact(0 6px 12px rgba(0, 0, 0, 0.175));
box-shadow: compact(0 6px 12px rgba(0, 0, 0, 0.175));
background-clip: padding-box;
li {
cursor: pointer;
display: block;
padding: 3px 20px;
clear: both;
font-weight: normal;
line-height: $line-height-base;
color: $dropdown-link-color;
white-space: nowrap;
&:hover,
&:focus {
text-decoration: none;
color: $dropdown-link-hover-color;
background-color: $dropdown-link-hover-bg;
}
}
}
}
}
#nfspathId[style],
#nfsserverId[style] {
// overriding style definition
width: 100% !important;
}
.iscsi-section .form-group > .col-md-12 > .col-md-10 + .col-md-2 {
padding-left: 5px;
}
.iscsi-section .form-group > .col-md-12 > .col-md-10 {
padding-right: 5px;
}
.authenticationfield > div > .col-md-6 + .col-md-6 {
padding-left: 5px;
}
.authenticationfield > div > .col-md-6 {
padding-right: 5px;
}
.host-partition label > div {
width: 688px;
span.device-path {
width: 688px;
}
}
}
================================================
FILE: ui/css/src/modules/_templates.scss
================================================
//
// Project Kimchi
//
// Copyright IBM Corp, 2015-2016
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
/* Add Template Modal Window */
$kimchi-icon-path: '../images';
.templates-modal {
.modal-dialog {
width: 1100px;
}
.page-list {
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
overflow: hidden;
}
.page {
position: absolute;
left: 100%;
width: 100%;
height: 100%;
overflow: auto;
padding: 10px 30px;
}
}
#template-edit-window {
.wok-mask {
top: 0 !important;
z-index: 3;
}
.tab-content .tab-pane {
position: relative;
}
form {
margin: 15px 0 0;
}
label.check-all {
margin: 0 !important;
padding: 0 !important;
width: 100px;
display: inline-block;
vertical-align: middle;
}
.hide {
display: none;
}
.form-template-inline-wrapper {
display: inline-block;
vertical-align: top;
}
.template-edit-wrapper-label {
vertical-align: top;
min-width: 172px;
height: 35px;
line-height: 35px;
margin: 7px 0 8px;
}
.template-edit-wrapper-controls {
vertical-align: top;
width: 480px;
height: 35px;
line-height: 35px;
margin: 7px 0 8px;
}
.template-tab-header {
background: $table-bg;
display: block;
border-bottom: 1px solid $table-border-color;
> span {
padding: $table-cell-padding;
display: inline-block;
font-family: $font-family-light;
font-weight: 400;
font-size: 12.5pt;
vertical-align: baseline;
border-bottom: none;
border-top: 0;
line-height: 42px;
height: 42px;
}
}
.template-tab-body {
.item {
border-top: 1px solid $table-border-color;
height: 53px;
&:first-child {
border-top: 0;
}
&:nth-child(even) {
background-color: $table-bg-accent;
}
&:nth-child(odd) {
background-color: $table-bg;
}
> span {
padding: $table-cell-padding;
display: inline-block;
vertical-align: middle;
input[type="text"].form-control {
height: 40px;
}
}
}
}
#template-edit-memory-textbox {
width: 308px !important;
display: inline;
}
#guest-show-max-processor {
display: inline-block;
}
#guest-processor label {
display: block;
}
#guest-max-processor-panel label {
display: block;
}
#guest-max-processor-panel .form-control,
#guest-processor .form-control {
display: inline-block;
width: 184px;
}
.manual {
margin-top: 5px;
margin-bottom: 10px;
}
.topology {
display: none;
margin: 0 24px;
}
.topology label {
display: block;
}
.bootstrap-select .btrn .caret {
height: selectpicker height - 2px;
}
.template-storage-cell.storage-pool {
width: 180px !important;
}
.template-storage-cell.storage {
width: 180px !important;
}
.template-storage-cell.storage-path {
width: 180px !important;
}
.template-storage-cell.source {
width: 180px !important;
}
.template-storage-cell.type {
width: 110px;
}
.template-storage-cell.disk {
width: 133px;
}
.template-storage-cell.format {
width: 162px;
}
.template-interface-cell.network {
width: 220px;
}
.template-interface-cell.type {
width: 250px;
}
}
#template-add-window {
.modal-body {
margin: 0;
padding: 0;
}
.modal-footer {
margin-top: 0;
}
.modal-footer .btn + .btn {
margin-left: 0;
}
.modal-footer .btn {
margin-right: 5px;
}
.template-modal-container {
padding: 10px 30px;
position: relative;
}
.template-pager {
background: $table-border-color;
width: 1082px;
height: 689px;
position: relative;
overflow: hidden;
}
.template-pager-container {
position: absolute;
height: 664px;
width: 2164px;
left: 0;
transition: left .2s ease-in-out;
}
&.modal-content p {
margin: 0;
}
&.modal-content h5 {
font-size: 13pt;
font-weight: 400;
margin-top: 0;
}
&.modal-content label {
font-size: 16px;
font-weight: 400;
font-family: $font-family-sans-serif;
}
&.modal-content label.check-all {
display: inline-block;
vertical-align: middle;
padding-top: 8px;
}
&.modal-content button#iso-more,
&.modal-content button#iso-more-loading {
clear: both;
}
&.modal-content div#iso-remote-box {
left: 1082px;
}
&.modal-content div#iso-local-box {
left: 0;
}
.check-all {
margin-right: 0 !important;
padding-left: 0 !important;
}
.filter {
float: right;
height: 40px;
overflow: visible;
clear: both;
margin-bottom: 0;
display: inline-block;
vertical-align: middle;
}
.pull-right .bootstrap-select:not([class*=col-]):not([class*=form-control]):not(.input-group-btn) {
width: 133px;
}
.filter input[type="text"].form-control {
width: 460px;
height: 40px;
float: right;
border-top-left-radius: 0;
border-bottom-left-radius: 0;
}
.filter .bootstrap-select.btn-group .btn .caret {
border-left: 0;
}
.filter button.btn.dropdown-toggle.form-control.selectpicker.btn-default {
border-top-right-radius: 0 !important;
border-bottom-right-radius: 0 !important;
background: $table-bg-accent;
border-right: 0;
}
span.iso-image-indicator {
position: absolute;
bottom: 10px;
right: 10px;
font-size: 32px;
.fa {
display: inline-block;
vertical-align: middle;
}
i.fa.fa-file-iso,
i.fa.fa-file-img {
display: inline-block;
width: 27px;
height: 25px;
margin-right: 3px;
}
i.fa.fa-file-iso {
background: url('#{$kimchi-icon-path}/file-o-iso.svg') no-repeat 50% 50%;
background-size: contain;
}
i.fa.fa-file-img {
background: url('#{$kimchi-icon-path}/file-o-img.svg') no-repeat 50% 50%;
background-size: contain;
}
}
span.iso-image-alert {
position: absolute;
bottom: 15px;
right: 70px;
font-size: 20px;
}
.tooltip-arrow {
display: none;
}
#loading-isos {
top: 0 !important;
z-index: 4 !important;
}
}
/* VM List View classes*/
#templatestatusselect{
width: 240px !important;
}
#templates-root-container {
.grid-control input[type="text"] {
height: 38px;
display: inline-block;
vertical-align: top;
}
.bootstrap-select:not([class*=col-]):not([class*=form-control]):not(.input-group-btn) {
width: 162px;
margin-right: 10px;
}
.bootstrap-select.btn-group .dropdown-menu {
margin: 0px;
> li > a {
border-top: 1px solid $table-bg;
border-bottom: 1px solid $table-border-color;
height: 38px;
padding: 4px 12px;
font-family: $font-family-light;
font-size: 13pt;
}
> li:last-child > a {
border-bottom: 0;
}
}
.control.open > .dropdown-menu {
display: block;
display: block;
width: 188px;
margin-left: -26px;
border-radius: 0;
}
.control.open .caret {
background: #3a393b;
}
.control.open .caret:before {
content: '\f077';
}
.control.open > a {
outline: 0;
}
.sort-button {
height: 38px;
padding: 4px 12px;
.caret {
height: 36px;
}
.caret:before {
top: 6px;
}
}
.wok-vm-list {
display: block;
width: 100%;
list-style-type: none;
margin: 0;
padding-left: 0;
background: $table-bg;
.wok-vm-header {
border-bottom: 1px solid $table-first-row-border-color;
> span {
padding: $table-cell-padding;
display: inline-block;
vertical-align: bottom;
height: 36px;
font-family: $font-family-light;
font-weight: 300;
font-size: 12.5pt;
line-height: $line-height-base;
border-bottom: none;
border-top: 0;
background-color: $table-bg;
width: 200px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
}
.wok-vm-body {
clear: both;
border-top: 1px solid $table-border-color;
&:first-child {
border-top: 0;
}
> span {
padding: $table-cell-padding;
display: inline-block;
vertical-align: top;
font-family: $font-family-sans-serif;
font-size: 12.5pt;
line-height: (1 + $line-height-base);
font-weight: 400;
width: 200px;
}
.column-type {
padding-left: 40px !important;
}
}
.ul-body {
display: block;
width: 100%;
clear: both;
padding: 0;
margin: 0;
list-style: none;
> li:nth-child(even) {
background-color: $table-bg-accent;
}
> li:nth-child(odd) {
background-color: $table-bg;
}
}
.column-name {
width: 17.4900%;
font-weight: bold;
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
}
.column-type {
width: 14.2435%;
font-weight: bold;
}
.column-version {
width: 12.2435%;
font-weight: bold;
}
.column-processors {
width: 10.8413%;
}
.column-memory {
width: 9.6900%;
}
.column-status {
width: 1.6900%;
}
.column-action {
width: 232px;
}
.item-hidden {
display: none !important;
}
.distro-icon {
background-color: transparent;
background-size: 27px 27px;
background-repeat: no-repeat;
background-position: 8px 50%;
&.icon-centos {
background-image: url('../images/icon-centos.png');
}
&.icon-debian {
background-image: url('../images/icon-debian.png');
}
&.icon-fedora {
background-image: url('../images/icon-fedora.png');
}
&.icon-opensuse {
background-image: url('../images/icon-opensuse.png');
}
&.icon-sles {
background-image: url('../images/icon-sles.png');
}
&.icon-ubuntu {
background-image: url('../images/icon-ubuntu.png');
}
&.icon-gentoo {
background-image: url('../images/icon-gentoo.png');
}
&.icon-unknown {
background-image: url('../images/icon-vm.png');
}
}
}
.wok-vm-gallery {
display: block;
width: 100%;
list-style-type: none;
margin: 0;
padding-left: 5px;
.wok-vm-header {
display: none;
}
.wok-vm-body {
position: relative;
;
padding: 0 20px 0 20px;
width: 240px;
display: inline-block;
border: 0;
background: $body-bg;
margin-right: 20px;
margin-bottom: 20px;
> span {
display: inline-block;
width: 100%;
font-family: $font-family-sans-serif;
font-size: 12.5pt;
line-height: $line-height-base;
font-weight: 400;
}
}
.ul-body {
display: inline-block;
padding: 0;
margin: 0;
list-style: none;
}
.column-name {
line-height: 2.5 !important;
font-size: 15.3pt !important;
font-weight: 500 !important;
text-overflow: ellipsis !important;
overflow: hidden !important;
padding-right: 35px !important;
white-space: nowrap;
cursor: default;
}
span.template-status {
position: absolute;
bottom: 10px;
right: 10px;
width: 32px;
height: 32px;
}
.invalid-icon {
position: absolute;
font-size: 32px;
}
.item-hidden {
&.column-type,
&.column-version,
&.column-processors {
padding-bottom: 11px;
}
}
.item-hidden {
&.column-memory {
padding-bottom: 38px;
}
}
.font-bold {
font-weight: bold !important;
}
.pull-right {
float: none !important;
padding-bottom: 22px;
}
.dropdown-menu {
width: 100%;
}
.menu-flat {
width: 240px;
margin-left: -20px;
}
.btn {
width: 100%;
text-align: left;
padding-left: 42px;
border-radius: 0;
}
.name-distro-icon {
background-color: transparent;
background-size: 32px 32px;
background-repeat: no-repeat;
background-position: 100% 50%;
&.icon-centos {
background-image: url('../images/icon-centos.png');
}
&.icon-debian {
background-image: url('../images/icon-debian.png');
}
&.icon-fedora {
background-image: url('../images/icon-fedora.png');
}
&.icon-opensuse {
background-image: url('../images/icon-opensuse.png');
}
&.icon-sles {
background-image: url('../images/icon-sles.png');
}
&.icon-ubuntu {
background-image: url('../images/icon-ubuntu.png');
}
&.icon-gentoo {
background-image: url('../images/icon-gentoo.png');
}
&.icon-unknown {
background-image: url('../images/icon-vm.png');
}
}
}
span.template-status {
color: #999;
}
.tooltip-inner {
font-size: 10pt;
padding: 6px 8px;
}
.wok-vm-list .tooltip-inner {
max-width: 300px;
}
.wok-vm-list .tooltip[style] {
left: 79px !important;
}
.wok-vm-list .tooltip-arrow[style] {
left: 10px !important;
}
.wok-vm-gallery .tooltip-inner {
max-width: 320px;
}
.wok-vm-gallery .tooltip[style] {
left: 7px !important;
right: 7px !important;
}
.wok-vm-gallery .tooltip-arrow[style] {
left: 207px !important;
}
}
================================================
FILE: ui/images/Makefile.am
================================================
#
# Kimchi
#
# Copyright IBM Corp, 2013-2016
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
imagedir = $(datadir)/wok/plugins/kimchi/ui/images
dist_image_DATA = *.png *.svg
================================================
FILE: ui/js/Makefile.am
================================================
#
# Kimchi
#
# Copyright IBM Corp, 2013-2016
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
EXTRA_DIST = src
jsdir = $(datadir)/wok/plugins/kimchi/ui/js
dist_js_DATA = kimchi.min.js $(filter-out kimchi.min.js, $(wildcard *.js))
kimchi.min.js: src/*.js
cat $(sort $^) > $@
echo "//# sourceURL=kimchi.min.js" >> $@
CLEANFILES = kimchi.min.js
================================================
FILE: ui/js/src/kimchi.api.js
================================================
/*
* Project Kimchi
*
* Copyright IBM Corp, 2013-2017
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
var kimchi = {
widget: {},
trackingTasks: [],
/**
* Get Kimchi details
*/
getConfig : function(suc, err, done) {
done = typeof done !== 'undefined' ? done: function(){};
wok.requestJSON({
url : "plugins/kimchi/config",
type : "GET",
contentType : "application/json",
dataType : "json",
success: suc,
error: err,
complete: done
});
},
/**
*
* Get host capabilities
* suc: callback if succeed err: callback if failed
*/
getCapabilities : function(suc, err, done) {
done = typeof done !== 'undefined' ? done: function(){};
wok.requestJSON({
url : "plugins/kimchi/config/capabilities",
type : "GET",
contentType : "application/json",
dataType : "json",
success: suc,
error: err,
complete: done
});
},
/**
* Get the i18 strings.
*/
getI18n: function(suc, err, url, sync) {
wok.requestJSON({
url : url ? url : 'plugins/kimchi/i18n.json',
type : 'GET',
resend: true,
dataType : 'json',
async : !sync,
success : suc,
error: err
});
},
/**
*
* Create a new Virtual Machine. Usage: kimchi.createVM({ name: 'MyUbuntu',
* template: '/templates/ubuntu_base' }, creationSuc, creationErr);
*
* settings: name *(optional)*: The name of the VM. Used to identify the VM
* in this API. If omitted, a name will be chosen based on the template
* used. template: The URI of a Template to use when building the VM
* storagepool *(optional)*: Assign a specific Storage Pool to the new VM
* suc: callback if succeed err: callback if failed
*/
createVM : function(settings, suc, err) {
wok.requestJSON({
url : "plugins/kimchi/vms",
type : "POST",
contentType : "application/json",
data : JSON.stringify(settings),
dataType : "json"
}).done(suc).fail(err);
},
/**
*
* Create a new Template. settings name: The name of the Template. Used to
* identify the Template in this API suc: callback if succeed err: callback
* if failed
*/
createTemplate : function(settings, suc, err) {
wok.requestJSON({
url : "plugins/kimchi/templates",
type : "POST",
contentType : "application/json",
data : JSON.stringify(settings),
dataType : "json",
success: suc,
error: err
});
},
deleteTemplate : function(tem, suc, err) {
wok.requestJSON({
url : 'plugins/kimchi/templates/' + encodeURIComponent(tem),
type : 'DELETE',
contentType : 'application/json',
dataType : 'json',
success : suc,
error : err
});
},
cloneTemplate : function(tem, suc, err) {
wok.requestJSON({
url : 'plugins/kimchi/templates/' + encodeURIComponent(tem) + "/clone",
type : 'POST',
contentType : 'application/json',
dataType : 'json',
success : suc,
error : err
});
},
listTemplates : function(suc, err) {
wok.requestJSON({
url : 'plugins/kimchi/templates',
type : 'GET',
contentType : 'application/json',
dataType : 'json',
success : suc,
error : err
});
},
/**
* Retrieve the information of a template by the given name.
*/
retrieveTemplate : function(templateName, suc, err) {
wok.requestJSON({
url : 'plugins/kimchi/templates/' + encodeURIComponent(templateName),
type : 'GET',
contentType : 'application/json',
dataType : 'json'
}).done(suc);
},
/**
* Update a template with new information. TODO: Update me when the RESTful
* API is available. Now work it around by remove the template and then
* recreate it with new information.
*/
updateTemplate : function(name, settings, suc, err) {
$.ajax({
url : 'plugins/kimchi/templates/' + encodeURIComponent(name),
type : 'PUT',
contentType : 'application/json',
data : JSON.stringify(settings),
dataType : 'json'
}).done(suc).fail(err);
},
/**
* Create a new Storage Pool. settings name: The name of the Storage Pool
* path: The path of the defined Storage Pool type: The type of the defined
* Storage Pool capacity: The total space which can be used to store volumes
* The unit is MBytes suc: callback if succeed err: callback if failed
*/
createStoragePool : function(settings, suc, err) {
wok.requestJSON({
url : 'plugins/kimchi/storagepools',
type : 'POST',
contentType : 'application/json',
data : JSON.stringify(settings),
dataType : 'json'
}).done(suc).fail(err);
},
updateStoragePool : function(name, content, suc, err) {
$.ajax({
url : "plugins/kimchi/storagepools/" + encodeURIComponent(name),
type : 'PUT',
contentType : 'application/json',
dataType : 'json',
data : JSON.stringify(content)
}).done(suc).fail(err ? err : function(data) {
wok.message.error(data.responseJSON.reason);
});
},
startVM : function(vm, suc, err) {
wok.requestJSON({
url : 'plugins/kimchi/vms/' + encodeURIComponent(vm) + '/start',
type : 'POST',
contentType : 'application/json',
dataType : 'json',
success : suc,
error : err
});
},
poweroffVM : function(vm, suc, err) {
wok.requestJSON({
url : 'plugins/kimchi/vms/' + encodeURIComponent(vm) + '/poweroff',
type : 'POST',
contentType : 'application/json',
dataType : 'json',
success : suc,
error : err
});
},
shutdownVM : function(vm, suc, err) {
wok.requestJSON({
url : 'plugins/kimchi/vms/' + encodeURIComponent(vm) + '/shutdown',
type : 'POST',
contentType : 'application/json',
dataType : 'json',
success : suc,
error : err
});
},
resetVM : function(vm, suc, err) {
wok.requestJSON({
url : 'plugins/kimchi/vms/' + encodeURIComponent(vm) + '/reset',
type : 'POST',
contentType : 'application/json',
dataType : 'json',
success : suc,
error : err
});
},
suspendVM : function(vm, suc, err) {
wok.requestJSON({
url : 'plugins/kimchi/vms/' + encodeURIComponent(vm) + '/suspend',
type : 'POST',
contentType : 'application/json',
dataType : 'json',
success : suc,
error : err
});
},
resumeVM : function(vm, suc, err) {
wok.requestJSON({
url : 'plugins/kimchi/vms/' + encodeURIComponent(vm) + '/resume',
type : 'POST',
contentType : 'application/json',
dataType : 'json',
success : suc,
error : err
});
},
/**
* Retrieve the information of a given VM by its name.
*
* @param vm VM name
* @param suc callback for success
* @param err callback for error
*/
retrieveVM : function(vm, suc, err) {
$.ajax({
url : 'plugins/kimchi/vms/' + encodeURIComponent(vm),
type : 'GET',
contentType : 'application/json',
dataType : 'json',
success: suc,
error: err
});
},
/**
* Update a VM with new information.
*/
updateVM : function(name, settings, suc, err) {
$.ajax({
url : "plugins/kimchi/vms/" + encodeURIComponent(name),
type : 'PUT',
contentType : 'application/json',
data : JSON.stringify(settings),
dataType : 'json',
success: suc,
error: err
});
},
deleteVM : function(vm, suc, err) {
wok.requestJSON({
url : 'plugins/kimchi/vms/' + encodeURIComponent(vm),
type : 'DELETE',
contentType : 'application/json',
dataType : 'json',
success : suc,
error : err
});
},
serialToVM : function(vm) {
wok.requestJSON({
url : 'config/',
type : 'GET',
dataType : 'json'
}).done(function(data, textStatus, xhr) {
proxy_port = data['proxy_port'];
server_root = data['server_root'];
wok.requestJSON({
url : "plugins/kimchi/vms/" + encodeURIComponent(vm) + "/serial",
type : "POST",
dataType : "json"
}).done(function() {
url = 'https://' + location.hostname + ':' + proxy_port;
url += server_root;
url += "/plugins/kimchi/serial/html/serial.html";
url += "?port=" + proxy_port;
url += "&path=" + server_root + "websockify";
url += "?token=" + wok.urlSafeB64Encode(vm+'-console').replace(/=*$/g, "");
url += '&encrypt=1';
window.open(url);
}).fail(function(data) {
wok.message.error(data.responseJSON.reason);
});
}).fail(function(data) {
wok.message.error(data.responseJSON.reason);
});
},
vncToVM : function(vm) {
proxy_port = location.port || (location.protocol === 'https:' ? '443' : '80');
server_root = wok.config['server_root'];
wok.requestJSON({
url : "plugins/kimchi/vms/" + encodeURIComponent(vm) + "/connect",
type : "POST",
dataType : "json"
}).done(function() {
url = 'https://' + location.hostname + ':' + proxy_port;
url += server_root;
url += "/plugins/kimchi/novnc/vnc_auto.html";
url += "?port=" + proxy_port;
url += "&path=" + server_root + "websockify";
/*
* From python documentation base64.urlsafe_b64encode(s)
* substitutes - instead of + and _ instead of / in the
* standard Base64 alphabet, BUT the result can still
* contain = which is not safe in a URL query component.
* So remove it when needed as base64 can work well without it.
* */
url += "?token=" + wok.urlSafeB64Encode(vm).replace(/=*$/g, "");
url += '&encrypt=1';
window.open(url);
});
},
spiceToVM : function(vm) {
proxy_port = location.port || (location.protocol === 'https:' ? '443' : '80');
server_root = wok.config['server_root'];
wok.requestJSON({
url : "plugins/kimchi/vms/" + encodeURIComponent(vm) + "/connect",
type : "POST",
dataType : "json"
}).done(function(data, textStatus, xhr) {
url = 'https://' + location.hostname + ':' + proxy_port;
url += server_root;
if(kimchi.config['with_spice_web_client'])
{
/*
* Slightly different api for spice-web-client
*/
url += "/plugins/kimchi/spice-web-client/index.html";
url += "?port=" + proxy_port + server_root;
url += "&host=" + location.hostname;
url += "&vmInfoToken=" + wok.urlSafeB64Encode(vm).replace(/=*$/g, "");
url += '&protocol=wss';
}
else
{
// Using spice-html5 by default
url += "/plugins/kimchi/spice_auto.html";
/*
* When using server_root we need pass the value with port
* argument to be used correctly by spice_auto.html scripts
*/
url += "?port=" + proxy_port + server_root;
url += "&listen=" + location.hostname;
/*
* From python documentation base64.urlsafe_b64encode(s)
* substitutes - instead of + and _ instead of / in the
* standard Base64 alphabet, BUT the result can still
* contain = which is not safe in a URL query component.
* So remove it when needed as base64 can work well without it.
* */
url += "&token=" + wok.urlSafeB64Encode(vm).replace(/=*$/g, "");
url += '&encrypt=1';
}
window.open(url);
});
},
listVMs : function(suc, err) {
wok.requestJSON({
url : 'plugins/kimchi/vms',
type : 'GET',
contentType : 'application/json',
headers: {'Wok-Robot': 'wok-robot'},
dataType : 'json',
resend: true,
success : suc,
error : err
});
},
listTemplates : function(suc, err) {
wok.requestJSON({
url : 'plugins/kimchi/templates',
type : 'GET',
contentType : 'application/json',
dataType : 'json',
resend: true,
success : suc,
error : err
});
},
listStoragePools : function(suc, err) {
wok.requestJSON({
url : 'plugins/kimchi/storagepools',
type : 'GET',
contentType : 'application/json',
dataType : 'json',
resend: true,
success : suc,
error : err
});
},
listStorageVolumes : function(poolName, suc, err, sync) {
$.ajax({
url : 'plugins/kimchi/storagepools/' + encodeURIComponent(poolName) + '/storagevolumes',
type : 'GET',
contentType : 'application/json',
dataType : 'json',
async : !sync,
success : suc,
error : err
});
},
listIsos : function(suc, err) {
wok.requestJSON({
url : 'plugins/kimchi/storagepools/kimchi_isos/storagevolumes',
type : 'GET',
contentType : 'application/json',
dataType : 'json',
success : suc,
error : err
});
},
listDistros : function(suc, err) {
wok.requestJSON({
url : 'plugins/kimchi/config/distros',
type : 'GET',
contentType : 'application/json',
dataType : 'json',
success : suc,
error : err
});
},
stepListDeepScanIsos : function(suc, err) {
var deepScanHandler = {
stop : false
};
var isoPool = 'iso' + new Date().getTime();
kimchi.createStoragePool({
name : isoPool,
type : 'kimchi-iso',
path : '/'
}, function(result) {
var taskId = result.task_id;
function monitorTask() {
if (deepScanHandler.stop) {
return;
}
kimchi.getTask(taskId, function(result) {
var status = result.status;
if (status === "finished") {
if (deepScanHandler.stop) {
return;
}
kimchi.listStorageVolumes(isoPool, function(isos) {
if (deepScanHandler.stop) {
return;
}
suc(isos, true);
}, err, false);
} else if (status === "running") {
if (deepScanHandler.stop) {
return;
}
kimchi.listStorageVolumes(isoPool, function(isos) {
if (deepScanHandler.stop) {
return;
}
suc(isos, false);
setTimeout(monitorTask, 2000);
}, err, false);
} else if (status === "failed") {
if (deepScanHandler.stop) {
return;
}
err(result.message);
}
}, err);
}
setTimeout(monitorTask, 2000);
}, err);
return deepScanHandler;
},
getTask : function(taskId, suc, err) {
wok.requestJSON({
url : 'plugins/kimchi/tasks/' + encodeURIComponent(taskId),
type : 'GET',
contentType : 'application/json',
dataType : 'json',
success : suc,
error : err
});
},
getTasksByFilter : function(filter, suc, err, sync) {
wok.requestJSON({
url : 'plugins/kimchi/tasks?' + filter,
type : 'GET',
contentType : 'application/json',
dataType : 'json',
async : !sync,
success : suc,
error : err
});
},
trackTask : function(taskID, suc, err, progress) {
var onTaskResponse = function(result) {
var taskStatus = result['status'];
switch(taskStatus) {
case 'running':
$('html').addClass('in-progress');
progress && progress(result);
setTimeout(function() {
kimchi.trackTask(taskID, suc, err, progress);
}, 2000);
break;
case 'finished':
$('html').removeClass('in-progress');
suc && suc(result);
break;
case 'failed':
$('html').removeClass('in-progress');
err && err(result);
break;
default:
$('html').removeClass('in-progress');
break;
}
};
kimchi.getTask(taskID, onTaskResponse, err);
if(kimchi.trackingTasks.indexOf(taskID) < 0) {
kimchi.trackingTasks.push(taskID);
}
},
deleteStoragePool : function(poolName, suc, err) {
$.ajax({
url : 'plugins/kimchi/storagepools/' + encodeURIComponent(poolName),
type : 'DELETE',
contentType : 'application/json',
dataType : 'json',
success : suc,
error : err
});
},
changePoolState : function(poolName, state, suc, err) {
if (state === 'activate' || state === 'deactivate') {
$.ajax({
url : 'plugins/kimchi/storagepools/' + encodeURIComponent(poolName) + '/' + state,
type : 'POST',
contentType : 'application/json',
dataType : 'json',
success : suc,
error : err
});
}
},
listNetworks : function(suc, err) {
wok.requestJSON({
url : 'plugins/kimchi/networks',
type : 'GET',
contentType : 'application/json',
dataType : 'json',
resend : true,
success : suc,
error : err ? err : function(data) {
wok.message.error(data.responseJSON.reason);
}
});
},
listmacvtapNetworks: function(suc, err) {
wok.requestJSON({
url: 'plugins/kimchi/interfaces?type=^nic|bonding|vlan$',
type: 'GET',
contentType: 'application/json',
dataType: 'json',
resend: true,
success: suc,
error: err ? err : function(data) {
wok.message.error(data.responseJSON.reason);
}
});
},
listovsNetworks: function(suc, err) {
wok.requestJSON({
url: 'plugins/kimchi/ovsbridges',
type: 'GET',
contentType: 'application/json',
dataType: 'json',
resend: true,
success: suc,
error: err ? err : function(data) {
wok.message.error(data.responseJSON.reason);
}
});
},
toggleNetwork : function(name, on, suc, err) {
var action = on ? "activate" : "deactivate";
wok.requestJSON({
url : 'plugins/kimchi/networks/' + encodeURIComponent(name) + '/' + action,
type : 'POST',
contentType : 'application/json',
dataType : 'json',
success : suc,
error : err ? err : function(data) {
wok.message.error(data.responseJSON.reason);
}
});
},
createNetwork : function(network, suc, err) {
wok.requestJSON({
url : 'plugins/kimchi/networks',
type : 'POST',
contentType : 'application/json',
dataType : 'json',
data : JSON.stringify(network),
success : suc,
error : err ? err : function(data) {
wok.message.error(data.responseJSON.reason);
}
});
},
getInterfaces : function(suc, err) {
wok.requestJSON({
url : 'plugins/kimchi/interfaces?_inuse=false',
type : 'GET',
contentType : 'application/json',
dataType : 'json',
resend : true,
success : suc,
error : err ? err : function(data) {
wok.message.error(data.responseJSON.reason);
}
});
},
getInterface : function(iface, suc, err, sync) {
wok.requestJSON({
url : 'plugins/kimchi/interfaces/' + encodeURIComponent(iface),
type : 'GET',
contentType : 'application/json',
async : !sync,
dataType : 'json',
success : suc,
error : err
});
},
getVEPAInterfaces : function(suc, err) {
wok.requestJSON({
url : 'plugins/kimchi/interfaces?_inuse=false&module=^(?!mlx5_core|mlx5-core).*$',
type : 'GET',
contentType : 'application/json',
dataType : 'json',
resend : true,
success : suc,
error : err ? err : function(data) {
wok.message.error(data.responseJSON.reason);
}
});
},
retrieveNetwork : function(name, suc, err) {
wok.requestJSON({
url : 'plugins/kimchi/networks/' + encodeURIComponent(name),
type : 'GET',
contentType : 'application/json',
dataType : 'json',
success: suc,
error: err
});
},
deleteNetwork : function(name, suc, err) {
wok.requestJSON({
url : 'plugins/kimchi/networks/' + encodeURIComponent(name),
type : 'DELETE',
contentType : 'application/json',
dataType : 'json',
success : suc,
error : err ? err : function(data) {
wok.message.error(data.responseJSON.reason);
}
});
},
updateNetwork : function(name, settings, suc, err) {
wok.requestJSON({
url : "plugins/kimchi/networks/" + encodeURIComponent(name),
type : 'PUT',
contentType : 'application/json',
data : JSON.stringify(settings),
dataType : 'json',
success: suc,
error: err
});
},
listHostPartitions : function(suc, err) {
wok.requestJSON({
url : 'plugins/kimchi/host/partitions',
type : 'GET',
contentType : 'application/json',
dataType : 'json',
success : suc,
error : err
});
},
getStorageServers: function(type, suc, err) {
var url = 'plugins/kimchi/storageservers?_target_type=' + type;
wok.requestJSON({
url : url,
type : 'GET',
contentType : 'application/json',
dataType : 'json',
success : suc,
error : err ? err : function(data) {
wok.message.error(data.responseJSON.reason);
}
});
},
getStorageTargets: function(server,type, suc, err) {
var url = 'plugins/kimchi/storageservers/' + server + '/storagetargets?_target_type=' + type;
wok.requestJSON({
url : url,
type : 'GET',
contentType : 'application/json',
timeout: 2000,
dataType : 'json',
success : suc,
error : err
});
},
getStoragePool: function(poolName, suc, err) {
var url = 'plugins/kimchi/storagepools/' + encodeURIComponent(poolName);
wok.requestJSON({
url : url,
type : 'GET',
contentType : 'application/json',
timeout: 2000,
dataType : 'json',
success : suc,
error : err
});
},
getStoragePoolVolume: function(poolName, volumeName, suc, err) {
var url = 'plugins/kimchi/storagepools/' + encodeURIComponent(poolName) + '/storagevolumes/' + encodeURIComponent(volumeName);
wok.requestJSON({
url : url,
type : 'GET',
contentType : 'application/json',
timeout: 2000,
dataType : 'json',
success : suc,
error : err
});
},
cloneStoragePoolVolume: function(poolName, volumeName, data, suc, err) {
var url = 'plugins/kimchi/storagepools/' + encodeURIComponent(poolName) + '/storagevolumes/' + encodeURIComponent(volumeName) + '/clone';
wok.requestJSON({
url : url,
type : 'POST',
data : JSON.stringify(data),
contentType : 'application/json',
dataType : 'json',
success : suc,
error : err
});
},
resizeStoragePoolVolume: function(poolName, volumeName, data, suc, err) {
var url = 'plugins/kimchi/storagepools/' + encodeURIComponent(poolName) + '/storagevolumes/' + encodeURIComponent(volumeName) + '/resize';
wok.requestJSON({
url : url,
type : 'POST',
data : JSON.stringify(data),
contentType : 'application/json',
dataType : 'json',
success : suc,
error : err
});
},
wipeStoragePoolVolume: function(poolName, volumeName, suc, err) {
var url = 'plugins/kimchi/storagepools/' + encodeURIComponent(poolName) + '/storagevolumes/' + encodeURIComponent(volumeName) + '/wipe';
wok.requestJSON({
url : url,
type : 'POST',
contentType : 'application/json',
dataType : 'json',
success : suc,
error : err
});
},
deleteStoragePoolVolume: function(poolName, volumeName, suc, err) {
var url = 'plugins/kimchi/storagepools/' + encodeURIComponent(poolName) + '/storagevolumes/' + encodeURIComponent(volumeName);
wok.requestJSON({
url : url,
type : 'DELETE',
contentType : 'application/json',
dataType : 'json',
success : suc,
error : err
});
},
getHostVgs: function(suc, err) {
var url = 'plugins/kimchi/host/vgs/';
wok.requestJSON({
url : url,
type : 'GET',
contentType : 'application/json',
timeout: 2000,
dataType : 'json',
success : suc,
error : err
});
},
addVMStorage : function(settings, suc, err) {
var vm = encodeURIComponent(settings['vm']);
delete settings['vm'];
wok.requestJSON({
url : 'plugins/kimchi/vms/' + vm + '/storages',
type : 'POST',
contentType : 'application/json',
data : JSON.stringify(settings),
dataType : 'json',
success : suc,
error : err
});
},
retrieveVMStorage : function(settings, suc, err) {
var vm = encodeURIComponent(settings['vm']);
var dev = encodeURIComponent(settings['dev']);
wok.requestJSON({
url : "plugins/kimchi/vms/" + vm + '/storages/' + dev,
type : 'GET',
contentType : 'application/json',
dataType : 'json',
success: suc,
error: err
});
},
replaceVMStorage : function(settings, suc, err) {
var vm = encodeURIComponent(settings['vm']);
var dev = encodeURIComponent(settings['dev']);
wok.requestJSON({
url : 'plugins/kimchi/vms/' + vm + '/storages/' + dev,
type : 'PUT',
contentType : 'application/json',
data : JSON.stringify({
path: settings['path']
}),
dataType : 'json',
success : suc,
error : err
});
},
deleteVMStorage : function(settings, suc, err) {
var vm = settings['vm'];
var dev = settings['dev'];
wok.requestJSON({
url : 'plugins/kimchi/vms/' + encodeURIComponent(vm) +
'/storages/' + encodeURIComponent(dev),
type : 'DELETE',
contentType : 'application/json',
dataType : 'json',
success : suc,
error : err
});
},
listVMStorages : function(params, suc, err) {
var vm = encodeURIComponent(params['vm']);
var type = params['storageType'];
var url = 'plugins/kimchi/vms/' + vm + '/storages';
if(type) {
url += '?type=' + type;
}
wok.requestJSON({
url : url,
type : 'GET',
contentType : 'application/json',
dataType : 'json',
success : suc,
error : err
});
},
getHostFCDevices: function(suc, err) {
var url = 'plugins/kimchi/host/devices?_cap=fc_host';
wok.requestJSON({
url : url,
type : 'GET',
contentType : 'application/json',
dataType : 'json',
success : suc,
error : err ? err : function(data) {
wok.message.error(data.responseJSON.reason);
}
});
},
getGuestInterfaces: function(name, suc, err) {
var url = 'plugins/kimchi/vms/' + encodeURIComponent(name) + '/ifaces';
wok.requestJSON({
url : url,
type : 'GET',
contentType : 'application/json',
dataType : 'json',
success : suc,
error : err || function(data) {
wok.message.error(data.responseJSON.reason,'#alert-modal-container');
}
});
},
createGuestInterface : function(name, interface, suc, err) {
wok.requestJSON({
url : 'plugins/kimchi/vms/' + encodeURIComponent(name) + '/ifaces',
type : 'POST',
contentType : 'application/json',
dataType : 'json',
data : JSON.stringify(interface),
success : suc,
error : err || function(data) {
wok.message.error(data.responseJSON.reason,'#alert-modal-container');
}
});
},
deleteGuestInterface : function(vm, mac, suc, err) {
wok.requestJSON({
url : 'plugins/kimchi/vms/' + encodeURIComponent(vm) + '/ifaces/' + encodeURIComponent(mac),
type : 'DELETE',
contentType : 'application/json',
dataType : 'json',
success : suc,
error : err ? err : function(data) {
wok.message.error(data.responseJSON.reason,'#alert-modal-container');
}
});
},
updateGuestInterface : function(vm, mac, interface, suc, err) {
$.ajax({
url : 'plugins/kimchi/vms/' + encodeURIComponent(vm) + '/ifaces/' + encodeURIComponent(mac),
type : 'PUT',
contentType : 'application/json',
data : JSON.stringify(interface),
dataType : 'json',
success: suc,
error: err ? err : function(data) {
wok.message.error(data.responseJSON.reason,'#alert-modal-container');
}
});
},
getUserById : function(data, suc, err) {
wok.requestJSON({
url : 'plugins/kimchi/users?_user_id=' + data.user_id,
type : 'GET',
contentType : 'application/json',
dataType : 'json',
resend : true,
async : false,
success : suc && suc(data),
error : err ? err : function(data) {
wok.message.error(data.responseJSON.reason,'#alert-modal-container');
}
});
},
getUsers : function(suc, err) {
wok.requestJSON({
url : 'plugins/kimchi/users',
type : 'GET',
contentType : 'application/json',
dataType : 'json',
resend : true,
success : suc,
error : err ? err : function(data) {
wok.message.error(data.responseJSON.reason,'#alert-modal-container');
}
});
},
getGroups : function(suc, err) {
wok.requestJSON({
url : 'plugins/kimchi/groups',
type : 'GET',
contentType : 'application/json',
dataType : 'json',
resend : true,
success : suc,
error : err ? err : function(data) {
wok.message.error(data.responseJSON.reason,'#alert-modal-container');
}
});
},
getHostPCIDevices : function(suc, err) {
wok.requestJSON({
url : 'plugins/kimchi/host/devices?_passthrough=true&_cap=pci',
type : 'GET',
contentType : 'application/json',
dataType : 'json',
resend : true,
success : suc,
error : err ? err : function(data) {
wok.message.error(data.responseJSON.reason,'#alert-modal-container');
}
});
},
getAvailableHostPCIDevices : function(suc, err) {
wok.requestJSON({
url : 'plugins/kimchi/host/devices?_passthrough=true&_cap=pci&_available_only=true',
type : 'GET',
contentType : 'application/json',
dataType : 'json',
resend : true,
success : suc,
error : err ? err : function(data) {
wok.message.error(data.responseJSON.reason,'#alert-modal-container');
}
});
},
getPCIDeviceCompanions : function(pcidev, suc, err) {
wok.requestJSON({
url : 'plugins/kimchi/host/devices?_passthrough_affected_by=' + pcidev,
type : 'GET',
contentType : 'application/json',
dataType : 'json',
resend : true,
success : suc,
error : err ? err : function(data) {
wok.message.error(data.responseJSON.reason,'#alert-modal-container');
}
});
},
getISCSITargets : function(server, port, suc, err) {
server = encodeURIComponent(server);
port = port ? '&_server_port='+encodeURIComponent(port) : '';
wok.requestJSON({
url : 'plugins/kimchi/storageservers/' + server + '/storagetargets?_target_type=iscsi' + port,
type : 'GET',
contentType : 'application/json',
dataType : 'json',
resend : true,
success : suc,
error : err ? err : function(data) {
wok.message.error(data.responseJSON.reason,'#alert-modal-container');
}
});
},
getVMPCIDevices : function(id, suc, err) {
wok.requestJSON({
url : 'plugins/kimchi/vms/' + encodeURIComponent(id) + '/hostdevs',
type : 'GET',
contentType : 'application/json',
dataType : 'json',
resend : true,
success : suc,
error : err ? err : function(data) {
wok.message.error(data.responseJSON.reason,'#alert-modal-container');
}
});
},
addVMPCIDevice : function(vm, device, suc, err) {
wok.requestJSON({
url : 'plugins/kimchi/vms/'+ encodeURIComponent(vm) +'/hostdevs',
type : 'POST',
contentType : 'application/json',
dataType : 'json',
data : JSON.stringify(device),
success : suc,
error : err ? err : function(data) {
wok.message.error(data.responseJSON.reason,'#alert-modal-container');
}
});
},
removeVMPCIDevice : function(vm, device, suc, err) {
wok.requestJSON({
url : 'plugins/kimchi/vms/'+ encodeURIComponent(vm) +'/hostdevs/' + encodeURIComponent(device),
type : 'DELETE',
contentType : 'application/json',
dataType : 'json',
success : suc,
error : err ? err : function(data) {
wok.message.error(data.responseJSON.reason,'#alert-modal-container');
}
});
},
/**
* Create a new volume with capacity
*/
createVolumeWithCapacity: function(poolName, settings, suc, err) {
wok.requestJSON({
url : 'plugins/kimchi/storagepools/' + encodeURIComponent(poolName) + '/storagevolumes',
type : 'POST',
contentType : "application/json",
data : JSON.stringify(settings),
dataType : "json",
success : suc,
error : err
});
},
/**
* Upload volume content
*/
uploadVolumeToSP: function(poolName, volumeName, settings, suc, err) {
var url = 'plugins/kimchi/storagepools/' + encodeURIComponent(poolName) + '/storagevolumes/' + encodeURIComponent(volumeName);
var fd = settings['formData'];
wok.requestJSON({
url : url,
type : 'PUT',
data : fd,
processData : false,
contentType : false,
dataType: 'json',
success : suc,
error : err
});
},
/**
* Add a volume to a given storage pool by URL.
*/
downloadVolumeToSP: function(settings, suc, err) {
var sp = encodeURIComponent(settings['sp']);
delete settings['sp'];
wok.requestJSON({
url : 'plugins/kimchi/storagepools/' + sp + '/storagevolumes',
type : 'POST',
data : JSON.stringify(settings),
contentType : 'application/json',
dataType : 'json',
success : suc,
error : err
});
},
cloneGuest: function(vm, suc, err) {
wok.requestJSON({
url : 'plugins/kimchi/vms/' + encodeURIComponent(vm) + "/clone",
type : 'POST',
contentType : 'application/json',
dataType : 'json',
success : suc,
error : err ? err : function(data) {
wok.message.error(data.responseJSON.reason);
}
});
},
migrateGuest: function(vm, data, suc, err) {
wok.requestJSON({
url : 'plugins/kimchi/vms/' + encodeURIComponent(vm) + "/migrate",
type : 'POST',
contentType : 'application/json',
dataType : 'json',
data : JSON.stringify(data),
success : suc,
error : err ? err : function(data) {
wok.message.error(data.responseJSON.reason);
}
});
},
listSnapshots : function(vm, suc, err) {
wok.requestJSON({
url : 'plugins/kimchi/vms/' + encodeURIComponent(vm) + '/snapshots',
type : 'GET',
contentType : 'application/json',
dataType : 'json',
resend : true,
success : suc,
error : err ? err : function(data) {
wok.message.error(data.responseJSON.reason, '#alert-modal-container');
}
});
},
getCurrentSnapshot : function(vm, suc, err, sync) {
wok.requestJSON({
url : 'plugins/kimchi/vms/' + encodeURIComponent(vm) + '/snapshots/current',
type : 'GET',
contentType : 'application/json',
dataType : 'json',
async : !sync,
resend : true,
success : suc,
error : err ? err : function(data) {
wok.message.error(data.responseJSON.reason, '#alert-modal-container');
}
});
},
revertSnapshot : function(vm, snapshot, suc, err) {
wok.requestJSON({
url : 'plugins/kimchi/vms/' + encodeURIComponent(vm) + '/snapshots/' + encodeURIComponent(snapshot) + '/revert',
type : 'POST',
contentType : 'application/json',
dataType : 'json',
success : suc,
error : err ? err : function(data) {
wok.message.error(data.responseJSON.reason, '#alert-modal-container');
}
});
},
createSnapshot : function(vm, suc, err) {
wok.requestJSON({
url : 'plugins/kimchi/vms/' + encodeURIComponent(vm) + '/snapshots',
type : 'POST',
contentType : 'application/json',
dataType : 'json',
success : suc,
error : err ? err : function(data) {
wok.message.error(data.responseJSON.reason, '#alert-modal-container');
}
});
},
deleteSnapshot : function(vm, snapshot, suc, err) {
wok.requestJSON({
url : 'plugins/kimchi/vms/' + encodeURIComponent(vm) + '/snapshots/' + encodeURIComponent(snapshot),
type : 'DELETE',
contentType : 'application/json',
dataType : 'json',
success : suc,
error : err ? err : function(data) {
wok.message.error(data.responseJSON.reason, '#alert-modal-container');
}
});
},
getCPUInfo : function(suc, err) {
wok.requestJSON({
url : 'plugins/kimchi/host/cpuinfo',
type : 'GET',
contentType : 'application/json',
dataType : 'json',
resend : true,
success : suc,
error : err ? err : function(data) {
wok.message.error(data.responseJSON.reason);
}
});
}
};
/**
* Get the host information.
*/
kimchi.serverConfig = function(suc, err) {
wok.requestJSON({
url: 'plugins/kimchi/host',
type: 'GET',
resend: true,
contentType: 'application/json',
dataType: 'json',
success: suc,
error: err
});
}
================================================
FILE: ui/js/src/kimchi.guest_add_main.js
================================================
/*
* Project Kimchi
*
* Copyright IBM Corp, 2013-2016
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
kimchi.guest_add_main = function() {
var showTemplates = function() {
wok.topic('templateCreated').unsubscribe(showTemplates);
kimchi.listTemplates(function(result) {
if (result && result.length) {
$('#prompt-create-template').addClass('hidden');
$('#prompt-choose-template').removeClass('hidden');
$('#guest-add-window .guest-pager').animate({
height: "530px"
});
var html = '';
var tmpl = $('#tmpl-template').html();
$.each(result, function(index, value) {
value.invalid_indicator = "invalid";
if ($.isEmptyObject(value.invalid)) {
value.invalid_indicator = "valid";
}
html += wok.substitute(tmpl, value);
});
$('#templateTile').html(html);
$('.iso-radio-hidden[data-invalid="invalid"]').attr("disabled", true);
$('.template-status[data-invalid="valid"]').hide();
$('[data-toggle="tooltip"]').tooltip();
return;
}
$('#btn-create-template').on('click', function(event) {
wok.topic('templateCreated').subscribe(showTemplates);
wok.window.open('plugins/kimchi/template-add.html','extendCreateTemplate');
event.preventDefault();
});
$('#prompt-choose-template').addClass('hidden');
$('#prompt-create-template').removeClass('hidden');
$('#guest-add-window .guest-pager').animate({
height: "90px"
});
}, function(err) {
wok.message.error(err.responseJSON.reason);
});
};
function validateForm() {
if (!$('input[name=template]:checked', '#templateTile').val()) {
return false;
}
return true;
}
$('#form-vm-add').change(function() {
if (validateForm()) {
$('#vm-doAdd').attr('disabled', false);
}
});
var addGuest = function(event) {
$('#vm-doAdd').attr('disabled', true);
$('#vm-doAdd').attr('style', 'display:none');
$('#vm-doAdding').attr('style', 'display');
var formData = $('#form-vm-add').serializeObject();
kimchi.createVM(formData, function() {
kimchi.listVmsAuto();
wok.window.close();
}, function(jqXHR, textStatus, errorThrown) {
$('#vm-doAdd').attr('style', 'display');
$('#vm-doAdding').attr('style', 'display:none');
var reason = jqXHR &&
jqXHR['responseJSON'] &&
jqXHR['responseJSON']['reason'];
wok.message.error(reason);
});
return false;
};
$('#form-vm-add').on('submit', addGuest);
$('#vm-doAdd').on('click', addGuest);
showTemplates();
};
================================================
FILE: ui/js/src/kimchi.guest_edit_main.js
================================================
/*
* Project Kimchi
*
* Copyright IBM Corp, 2013-2017
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
kimchi.guest_edit_main = function() {
var authType;
var formTargetId;
var guestEditForm = $('#form-guest-edit-general');
var saveButton = $('#guest-edit-button-save');
var s390xArch = 's390x';
var macvtapNetworks = "";
var ovsNetworks = "";
var networkOptions = "";
clearTimeout(kimchi.vmTimeout);
var bootOrderOptions = [];
$('#guest-edit-window a[data-toggle="tab"]').on('show.bs.tab', function(tab) {
tab.target; // newly activated tab
tab.relatedTarget; // previous active tab
var display_list = ['form-guest-edit-general', 'form-guest-edit-permission'];
$(saveButton).prop('disabled', true);
formTargetId = $(tab.target).data('id');
var deactivated = $('form#' + formTargetId);
if (display_list.indexOf($(deactivated).attr('id')) >= 0) {
$(saveButton).prop('disabled', false);
}
});
var submitForm = function(event) {
var submit_map = {
0: generalSubmit,
3: permissionSubmit,
6: processorSubmit
};
var currentTab = $('#guest-edit-window li.active a[data-toggle="tab"]').data('id');
var toSubmit = parseInt($('#'+currentTab).index());
var submitFun = submit_map[toSubmit];
submitFun && submitFun(event);
event.preventDefault();
};
$(guestEditForm).on('submit', submitForm);
$(saveButton).on('click', submitForm);
$('#guest-edit-window a[data-toggle="tab"]').on('shown.bs.tab', function(e) {
var target = $(this).attr('href');
$(target).css('left', '-' + $(window).width() + 'px');
var left = $(target).offset().left;
$(target).css({
left: left
}).animate({
"left": "0px"
}, "10");
});
$('#guest-edit-window a[data-toggle="tab"]:first').tab('show');
var refreshCDROMs = function() {
kimchi.listVMStorages({
vm: kimchi.selectedGuest
}, function(storages) {
var container = $('#form-guest-edit-storage .body');
$(container).empty();
$.each(storages, function(index, storage) {
storage['vm'] = kimchi.selectedGuest;
rowHTML = $('#' + storage['type'] + '-row-tmpl').html();
var templated = wok.substitute(rowHTML, storage);
container.append(templated);
});
if (kimchi.thisVMState === 'running') {
$('.detach[data-type="cdrom"]', container).remove();
}
});
};
var initStorageListeners = function() {
var container = $('#form-guest-edit-storage .body');
var toggleCDROM = function(rowNode, toEdit) {
$('button.replace,button.detach', rowNode)[(toEdit ? 'add' : 'remove') + 'Class']('hidden');
$('button.save,button.cancel', rowNode)[(toEdit ? 'remove' : 'add') + 'Class']('hidden');
var pathBox = $('.path input', rowNode)
.prop('readonly', !toEdit);
toEdit && pathBox.select();
pathBox.val(pathBox.attr('value'));
};
var replaceCDROM = function(event) {
event.preventDefault();
kimchi.selectedGuestStorage = $(this).data('dev');
$('.item', container).each(function(i, n) {
toggleCDROM(n);
});
var rowNode = $('#cdrom-' + kimchi.selectedGuestStorage);
toggleCDROM(rowNode, true);
};
$(container).on('click', 'button.replace', replaceCDROM);
$(container).on('click', 'button.detach', function(e) {
e.preventDefault();
var settings = {
title: i18n['KCHAPI6004M'],
content: i18n['KCHVMCD6001M'],
confirm: i18n['KCHAPI6002M'],
cancel: i18n['KCHAPI6003M']
};
if ($(this).data('type') === "disk") {
settings['content'] = i18n['KCHVMCD6009M'];
}
var dev = $(this).data('dev');
wok.confirm(settings, function() {
kimchi.deleteVMStorage({
vm: kimchi.selectedGuest,
dev: dev
}, function() {
wok.topic('kimchi/vmCDROMDetached').publish();
});
});
});
$(container).on('click', 'button.save', function(event) {
event.preventDefault();
var path = $('#cdrom-path-' + kimchi.selectedGuestStorage).val();
var settings = {
vm: kimchi.selectedGuest,
dev: kimchi.selectedGuestStorage,
path: path
};
kimchi.replaceVMStorage(settings, function(result) {
wok.topic('kimchi/vmCDROMReplaced').publish({
result: result
});
}, function(result) {
var errText = result['reason'] ||
result['responseJSON']['reason'];
wok.message.error(errText, '#alert-modal-container');
});
});
$(container).on('click', 'button.cancel', function(event) {
event.preventDefault();
var rowNode = $('#cdrom-' + kimchi.selectedGuestStorage);
toggleCDROM(rowNode);
});
};
var setupInterface = function() {
$(".add", "#form-guest-edit-interface").on('click', function(evt) {
evt.preventDefault();
addItem({
id: -1,
mac: "",
ips: "",
network: "",
type: "network",
viewMode: "hide",
editMode: ""
});
});
var toggleEdit = function(item, on, itemId) {
if(kimchi.hostarch === s390xArch){
$("#label-mac-" + itemId, item).toggleClass("hide", on);
$("#edit-mac-" + itemId, item).toggleClass("hide", !on);
$("#label-network-" + itemId, item).toggleClass("hide", false);
$("#label-type-" + itemId, item).toggleClass("hide", false);
$("#label-mode-" + itemId, item).toggleClass("hide", false);
$("select", item).toggleClass("hide", true);
$(".bootstrap-select", item).toggleClass("hide", true);
$(".action-area", item).toggleClass("hide");
}else {
$("#label-mac-" + itemId, item).toggleClass("hide", on);
$("#edit-mac-" + itemId, item).toggleClass("hide", !on);
$("#label-network-" + itemId, item).toggleClass("hide", false);
$("select", item).toggleClass("hide", true);
$(".bootstrap-select", item).toggleClass("hide", true);
$(".action-area", item).toggleClass("hide");
}
};
var addItem = function(data) {
var oriID = data.id;
if (data.id === -1) {
data.id = $('#form-guest-edit-interface > .body').children().length;
}
if (data.ips === "" || data.ips === null || data.ips === undefined || data.ips.length === 0) {
data.ips = i18n["KCHNET6001M"];
} else {
data.ips = data.ips;
}
if (kimchi.hostarch === s390xArch) {
data.mode = (data.mode) ? data.mode : 'None';
var itemNode = $.parseHTML(wok.substitute($('#interface-s390x-tmpl').html(), data));
$(".body", "#form-guest-edit-interface").append(itemNode);
$("select", "span.column-type", itemNode).empty().append(typeOptions);
$("select", "span.column-mode", itemNode).empty().append(modeOptions);
$("select", "span.column-network", itemNode).empty().append(macvtapNetworks);
$("select", "span.column-type", itemNode).val(data.type);
$("select", "span.column-network", itemNode).val(data.source);
$("select", "span.column-mode", itemNode).val(data.mode);
} else {
var itemNode = $.parseHTML(wok.substitute($('#interface-tmpl').html(), data));
$(".body", "#form-guest-edit-interface").append(itemNode);
$("select", "span.column-network", itemNode).append(networkOptions);
}
$("select", itemNode).selectpicker({
dropupAuto: false
});
$('.edit', itemNode).attr('disabled', kimchi.thisVMState === "running");
$(".edit", itemNode).on('click', function(evt) {
evt.preventDefault();
toggleEdit($(this).closest('div'), true, data.id);
});
$(".delete", itemNode).on('click', function(evt) {
evt.preventDefault();
var item = $(this).parent().parent();
kimchi.deleteGuestInterface(kimchi.selectedGuest, item.prop("id"), function() {
item.remove();
});
});
$(".save", itemNode).on('click', function(evt) {
evt.preventDefault();
var item = $(this).parent().parent();
if (kimchi.hostarch === s390xArch) {
if (item.prop("id") === "") { //adding new interface
switch ($("span.column-type select", item).val()) {
case 'macvtap':
var interface = {
source: $("span.column-network select", item).val(),
type: $("span.column-type select", item).val(),
mac: $(":text", item).val(),
ips: $(".ipText", item).val(),
mode: $("span.column-mode select", item).val()
};
break;
case 'ovs':
var interface = {
source: $("span.column-network select", item).val(),
type: $("span.column-type select", item).val(),
mac: $(":text", item).val(),
ips: $(".ipText", item).val()
};
break;
case 'network':
var interface = {
network: $("span.column-network select", item).val(),
type: "network",
mac: $(":text", item).val(),
ips: $(".ipText", item).val()
};
break;
}
} else { //updating existing interface
switch ($("#label-type-" + data.id, item).text()) {
case 'macvtap':
var interface = {
source: $("#label-network-" + data.id, item).text(),
type: $("#label-type-" + data.id, item).text(),
mac: $(":text", item).val(),
ips: $(".ipText", item).val(),
mode: $("#label-mode-" + data.id, item).text()
};
break;
case 'ovs':
var interface = {
source: $("#label-network-" + data.id, item).text(),
type: $("#label-type-" + data.id, item).text(),
mac: $(":text", item).val(),
ips: $(".ipText", item).val()
};
break;
case 'network':
var interface = {
network: $("#label-network-" + data.id, item).text(),
type: "network",
mac: $(":text", item).val(),
ips: $(".ipText", item).val()
};
break;
}
}
} else { //in s86 arch
var interface = {
network: $("select", item).val(),
type: "network",
mac: $(":text", item).val(),
ips: $(".ipText", item).val()
};
}
var postUpdate = function(mac) {
$("#label-network-" + data.id, item).text(interface.network);
$("#label-mac-" + data.id, item).text(mac);
$("#edit-mac-" + data.id, item).val(mac);
toggleEdit(item, false, data.id);
};
var posts390xUpdate = function(result) {
switch(result.type){
case 'macvtap' :
$("#label-type-" + data.id, item).text(result.type);
$("#label-network-" + data.id, item).text(result.source);
$("#label-mode-" + data.id, item).text(result.mode);
break;
case 'ovs' :
$("#label-type-" + data.id, item).text(result.type);
$("#label-network-" + data.id, item).text(result.source);
$("#label-mode-" + data.id, item).text(i18n['KCHVMED6018M']);
break;
case 'network' :
$("#label-type-" + data.id, item).text(result.type);
$("#label-network-" + data.id, item).text(result.network);
$("#label-mode-" + data.id, item).text(i18n['KCHVMED6018M']);
break;
}
$("#label-mac-" + data.id, item).text(result.mac);
$("#edit-mac-" + data.id, item).val(result.mac);
toggleEdit(item, false, data.id);
};
if (item.prop("id") === "") {
kimchi.createGuestInterface(kimchi.selectedGuest, interface, function(data) {
item.prop("id", data.mac);
if(kimchi.hostarch == s390xArch){
posts390xUpdate(data);
}else{
postUpdate(data.mac);
}
});
} else {
if (item.prop('id') === interface.mac) {
toggleEdit(item, false, data.id);
} else {
kimchi.updateGuestInterface(kimchi.selectedGuest, item.prop('id'),
interface,
function(data) {
item.prop("id", data.mac);
postUpdate(data.mac);
});
}
}
});
$(".cancel", itemNode).on('click', function(evt) {
evt.preventDefault();
var item = $(this).parent().parent();
$("label", item).text() === "" ? item.remove() : toggleEdit(item, false, data.id);
});
if (kimchi.hostarch === s390xArch) {
$("#interface-s390x-type-" + data.id).on('change', function() {
var itemNode = $(this).closest('div.item');
switch ($(this).val()) {
case 'macvtap':
$('#label-mode-' + data.id).addClass('hide');
$('span.column-mode .bootstrap-select', itemNode).toggleClass("hide", false);
$("span.column-network select", itemNode).empty().append(macvtapNetworks);
$("span.column-network select", itemNode).selectpicker('refresh');
break;
case 'ovs':
$('#label-mode-' + data.id).html(i18n['KCHVMED6018M']);
$('#label-mode-' + data.id).removeClass('hide');
$('span.column-mode .bootstrap-select', itemNode).toggleClass("hide", true);
$("span.column-network select", itemNode).empty().append(ovsNetworks);
$("span.column-network select", itemNode).selectpicker('refresh');
break;
case 'network':
$('#label-mode-' + data.id).html(i18n['KCHVMED6018M']);
$('#label-mode-' + data.id).removeClass('hide');
$('span.column-mode .bootstrap-select', itemNode).toggleClass("hide", true);
$("span.column-network select", itemNode).empty().append(networkOptions);
$("span.column-network select", itemNode).selectpicker('refresh');
break;
}
});
if (oriID === -1) {
$("#interface-s390x-type-" + data.id).trigger('change');
}
}
};
kimchi.listNetworks(function(data) {
for (var i = 0; i < data.length; i++) {
var isSlected = i === 0 ? " selected" : "";
networkOptions += "";
}
if (kimchi.hostarch === s390xArch) {
kimchi.listmacvtapNetworks(function(data) {
for (var i = 0; i < data.length; i++) {
var isSlected = i === 0 ? ' selected="selected"' : "";
macvtapNetworks += "";
}
kimchi.listovsNetworks(function(data) {
for (var i = 0; i < data.length; i++) {
var isSlected = i === 0 ? " selected" : "";
ovsNetworks += "";
}
kimchi.getGuestInterfaces(kimchi.selectedGuest, function(data) {
for (var i = 0; i < data.length; i++) {
data[i].viewMode = "";
data[i].editMode = "hide";
data[i].id = i;
addItem(data[i]);
}
});
});
});
} else {
kimchi.getGuestInterfaces(kimchi.selectedGuest, function(data) {
for (var i = 0; i < data.length; i++) {
data[i].viewMode = "";
data[i].editMode = "hide";
data[i].id = i;
addItem(data[i]);
}
});
}
});
if (kimchi.hostarch === s390xArch) {
$('#form-guest-edit-interface > div.header').hide();
$('#form-guest-edit-interface > div.s390x').show();
var typeOptionsdata = [{
label: i18n['KCHVMED6013M'],
value: 'macvtap'
}, {
label: i18n['KCHVMED6014M'],
value: 'ovs'
}, {
label: i18n['KCHVMED6015M'],
value: 'network'
}];
var typeOptions = '';
for (var i = 0; i < typeOptionsdata.length; i++) {
var isSlected = i === 0 ? ' selected="selected"' : "";
typeOptions += '';
}
var modeOptionsdata = [{
label: i18n['KCHVMED6016M'],
value: 'bridge'
}, {
label: i18n['KCHVMED6017M'],
value: 'vepa'
}];
var modeOptions = '';
for (var i = 0; i < modeOptionsdata.length; i++) {
var isSlected = i === 0 ? " selected" : "";
modeOptions += '';
}
} else {
$('#form-guest-edit-interface > div.header').show();
$('#form-guest-edit-interface > div.s390x').hide();
}
};
var setupPermission = function() {
//set up for LDAP
$(".add", "#form-guest-edit-permission").on('click', function(evt) {
evt.preventDefault();
addItem({
user: "",
freeze: false,
viewMode: "hide",
editMode: "",
checked: true
});
});
var addItem = function(data) {
var itemNode = $.parseHTML(wok.substitute($('#ldap-user-tmpl').html(), data));
$(".body", "#form-guest-edit-permission .ldap").append(itemNode);
$(".delete", itemNode).on('click', function(evt) {
evt.preventDefault();
var item = $(this).parent().parent();
item.remove();
});
$("input").focusout(function() {
var item = $(this).parent().parent();
var user = $(this).val();
item.prop("id", user);
$("label", item).text(user);
});
$("input").focusin(function() {
$(this).removeClass("checked");
});
if (data.checked === true) {
$(".checked", itemNode).addClass("hide");
}
};
var toggleEdit = function(item, on) {
$(".cell span", item).toggleClass("hide", on);
$("input", item).toggleClass("hide", !on);
$(".action-area", item).toggleClass("hide");
};
//set up for PAM
var userNodes = {},
groupNodes = {};
authType = wok.config['auth'];
if (authType === 'pam') {
$("#form-guest-edit-permission .ldap").hide();
kimchi.retrieveVM(kimchi.selectedGuest, function(vm) {
kimchi.getUsers(function(users) {
kimchi.getGroups(function(groups) {
var subArray = function(a1, a2) { //a1-a2
for (var i = 0; i < a2.length; i++) {
for (var j = 0; j < a1.length; j++) {
if (a2[i] === a1[j]) {
a1.splice(j, 1);
break;
}
}
}
};
subArray(users, vm.users);
subArray(groups, vm.groups);
init(users, groups, vm.users, vm.groups);
});
});
});
} else if (authType === 'ldap') {
$("#form-guest-edit-permission .pam").hide();
kimchi.retrieveVM(kimchi.selectedGuest, function(vm) {
for (var i = 0; i < vm.users.length; i++) {
addItem({
user: vm.users[i],
viewMode: "",
freeze: true,
editMode: "hide",
checked: true
});
}
});
}
var sortNodes = function(container, isUser) {
nodes = container.children();
var keys = [];
nodes.each(function() {
keys.push($("label", this).text());
});
keys.sort();
container.empty();
for (var i = 0; i < keys.length; i++) {
var itemNode = isUser ? userNodes[keys[i]] : groupNodes[keys[i]];
$(itemNode).click(function() {
$(this).toggleClass("item-picked");
});
container.append(itemNode);
}
};
var init = function(availUsers, availGroups, selUsers, selGroups) {
var initNode = function(key, isUserNode) {
var nodeGroups = isUserNode ? userNodes : groupNodes;
nodeGroups[key] = $.parseHTML(wok.substitute($('#permission-item-pam').html(), {
val: key,
class: isUserNode ? "fa-user" : "fa-users"
}));
};
for (var i = 0; i < availUsers.length; i++) {
initNode(availUsers[i], true);
$("#permission-avail-users").append(userNodes[availUsers[i]]);
}
sortNodes($("#permission-avail-users"), true);
for (var i = 0; i < selUsers.length; i++) {
initNode(selUsers[i], true);
$("#permission-sel-users").append(userNodes[selUsers[i]]);
}
sortNodes($("#permission-sel-users"), true);
for (var i = 0; i < availGroups.length; i++) {
initNode(availGroups[i], false);
$("#permission-avail-groups").append(groupNodes[availGroups[i]]);
}
sortNodes($("#permission-avail-groups"), false);
for (var i = 0; i < selGroups.length; i++) {
initNode(selGroups[i], false);
$("#permission-sel-groups").append(groupNodes[selGroups[i]]);
}
sortNodes($("#permission-sel-groups"), false);
};
var filterNodes = function(key, container) {
container.children().each(function() {
$(this).css("display", $("label", this).text().indexOf(key) === -1 ? "none" : "");
});
};
$("#permission-avail-searchBox").on("keyup", function() {
var key = $(this).val();
filterNodes(key, $("#permission-avail-users"));
filterNodes(key, $("#permission-avail-groups"));
});
$("#permission-sel-searchBox").on("keyup", function() {
var key = $(this).val();
filterNodes(key, $("#permission-sel-users"));
filterNodes(key, $("#permission-sel-groups"));
});
$('#permissionGo').on('click', function(evt) {
evt.preventDefault();
$("#permission-avail-users").children(".item-picked").appendTo("#permission-sel-users").removeClass("item-picked");
sortNodes($("#permission-sel-users"), true);
$("#permission-avail-groups").children(".item-picked").appendTo("#permission-sel-groups").removeClass("item-picked");
sortNodes($("#permission-sel-groups"), false);
$("#permission-sel-searchBox").val("");
filterNodes("", $("#permission-sel-users"));
filterNodes("", $("#permission-sel-groups"));
});
$('#permissionBack').on('click', function(evt) {
evt.preventDefault();
$("#permission-sel-users").children(".item-picked").appendTo("#permission-avail-users").removeClass("item-picked");
sortNodes($("#permission-avail-users"), true);
$("#permission-sel-groups").children(".item-picked").appendTo("#permission-avail-groups").removeClass("item-picked");
sortNodes($("#permission-avail-groups"), false);
$("#permission-avail-searchBox").val("");
filterNodes("", $("#permission-avail-users"));
filterNodes("", $("#permission-avail-groups"));
});
};
var filterPCINodes = function(group, text) {
text = text.trim().split(" ");
var rows = $('.body', '#form-guest-edit-pci').find('div');
if (text === "") {
rows.show();
return;
}
rows.hide();
rows.filter(function(index, value) {
var $span = $(this);
var $itemGroup = $('button i', this);
for (var i = 0; i < text.length; ++i) {
if ($span.is(":containsNC('" + text[i] + "')")) {
if (group === 'all') {
return true;
} else if (group === 'toAdd' && $itemGroup.hasClass('fa-power-off')) {
return true;
} else if (group === 'added' && $itemGroup.hasClass('fa-ban')) {
return true;
}
}
}
return false;
}).show();
};
var _generatePciDeviceHtml = function(devices, pciType) {
var pciEnabled = kimchi.capabilities.kernel_vfio;
var deviceHTml = devices.map(function(device, index) {
device.iconClass = (pciType === 'hostPCIs' ? 'fa-power-off' : (pciType === 'vmPCIs' ? 'fa-ban' : 'fa-power-off'));
device.status = (pciType === 'vmPCIs' ? 'enabled' : 'disabled');
device.product = (device.product !== null ? device.product.description : '');
device.vendor = (device.vendor !== null ? device.vendor.description : '');
deviceHtml = $.parseHTML(wok.substitute($('#pci-tmpl').html(), {
status: device.status,
name: device.name,
product: device.product,
vendor: device.vendor
}));
pciEnabled || $('button', deviceHtml).remove();
$('button > i', deviceHtml).addClass(device.iconClass);
if (kimchi.thisVMState === "running" && device.vga3d) {
$('button', deviceHtml).prop("disabled", true);
}
device = deviceHtml[0].outerHTML;
$('.body', '#form-guest-edit-pci').append(device);
});
};
var getOngoingAttachingDevices = function(task) {
kimchi.trackTask(task.id, function(result) {
kimchi.getAvailableHostPCIDevices(function(arrPCIDevices) {
kimchi.getVMPCIDevices(kimchi.selectedGuest, function(vmPCIs) {
for (var k = 0; k < vmPCIs.length; k++) {
$('#' + vmPCIs[k].name + '.item').removeClass('disabled').addClass('enabled');
$('#' + vmPCIs[k].name + ' .action-area button i').removeClass('fa-power-off').addClass('fa-ban');
}
});
});
$('#form-guest-edit-pci > .wok-mask').fadeOut(300, function() {});
wok.message.success(i18n['KCHVMED6010M'], '#alert-modal-container');
filterPCINodes($('select', '#form-guest-edit-pci').val(), $('input#guest-edit-pci-filter', '#form-guest-edit-pci').val());
}, function(result) {
if (result['message']) {
var errText = result['message'];
} else {
var errText = result['responseJSON']['reason'];
}
$('#form-guest-edit-pci > .wok-mask').fadeOut(300, function() {});
filterPCINodes($('select', '#form-guest-edit-pci').val(), $('input#guest-edit-pci-filter', '#form-guest-edit-pci').val());
result && wok.message.error(errText, '#alert-modal-container');
}, function(result) {
$('#form-guest-edit-pci > .wok-mask').show();
});
};
var getOngoingDetachingDevices = function(task) {
kimchi.trackTask(task.id, function(result) {
kimchi.getAvailableHostPCIDevices(function(arrPCIDevices) {
kimchi.getVMPCIDevices(kimchi.selectedGuest, function(vmPCIs) {
for (var k = 0; k < arrPCIDevices.length; k++) {
$('#' + arrPCIDevices[k].name + '.item').removeClass('enabled').addClass('disabled');
$('#' + arrPCIDevices[k].name + ' .action-area button i').removeClass('fa-ban').addClass('fa-power-off');
}
for (var k = 0; k < vmPCIs.length; k++) {
$('#' + arrPCIDevices[k].name + '.item').removeClass('disabled').addClass('enabled');
$('#' + arrPCIDevices[k].name + ' .action-area button i').removeClass('fa-power-off').addClass('fa-ban');
}
});
});
$('#form-guest-edit-pci > .wok-mask').fadeOut(300, function() {});
wok.message.success(i18n['KCHVMED6011M'], '#alert-modal-container');
//id is for the object that is being added back to the available PCI devices
filterPCINodes($('select', '#form-guest-edit-pci').val(), $('input#guest-edit-pci-filter', '#form-guest-edit-pci').val());
}, function(result) {
if (result['message']) {
var errText = result['message'];
} else {
var errText = result['responseJSON']['reason'];
}
$('#form-guest-edit-pci > .wok-mask').fadeOut(300, function() {});
filterPCINodes($('select', '#form-guest-edit-pci').val(), $('input#guest-edit-pci-filter', '#form-guest-edit-pci').val());
result && wok.message.error(errText, '#alert-modal-container');
}, function(result) {
$('#form-guest-edit-pci > .wok-mask').show();
});
};
var pciDeviceButtonHandler = function() {
$('.btn.btn-link', '#form-guest-edit-pci').on('click', function(event) {
event.preventDefault();
if (event.originalEvent.detail > 1)
return;
var obj = $(this);
var objIcon = obj.find('i');
var id = obj.parent().parent().attr('id');
if (objIcon.hasClass('fa-ban')) {
kimchi.removeVMPCIDevice(kimchi.selectedGuest, id, function(task) {
getOngoingDetachingDevices(task);
}, function(err) {
wok.message.error(err.responseJSON.reason, '#alert-modal-container');
});
} else {
$('html').addClass('in-progress');
$('#form-guest-edit-pci > .wok-mask').show();
var haveCompanions = false;
var pciTitle = i18n['KCHVMED6007M'] + '\n';
kimchi.getPCIDeviceCompanions(id, function(infoData) {
for (var p = 0; p < infoData.length; p++) {
if (infoData[p].device_type === 'net') {
haveCompanions = true;
pciTitle += ' ' + infoData[p].name + '\n';
pciTitle += ' ' + i18n['KCHVMED6001M'] + ' ' + infoData[p].interface;
pciTitle += ', ' + i18n['KCHVMED6002M'] + ' ' + infoData[p].address;
pciTitle += ', ' + i18n['KCHVMED6003M'] + ' ' + infoData[p].link_type + '\n';
} else if (infoData[p].device_type === 'storage') {
haveCompanions = true;
pciTitle += ' ' + infoData[p].name + '\n';
pciTitle += ' ' + i18n['KCHVMED6004M'] + ' ' + infoData[p].block;
pciTitle += ', ' + i18n['KCHVMED6005M'] + ' ' + infoData[p].drive_type;
pciTitle += ', ' + i18n['KCHVMED6006M'] + ' ' + infoData[p].model + '\n';
}
}
});
$('#form-guest-edit-pci > .wok-mask').fadeOut(300, function() {});
$('html').removeClass('in-progress');
var settings = {
title: i18n['KCHVMED6012M'],
content: pciTitle,
confirm: i18n['KCHAPI6002M'],
cancel: i18n['KCHAPI6003M']
};
if (haveCompanions) {
wok.confirm(settings, function() {
kimchi.addVMPCIDevice(kimchi.selectedGuest, {
name: id
}, function(task) {
getOngoingAttachingDevices(task);
}, function(err) {
wok.message.error(err.responseJSON.reason, '#alert-modal-container');
});
});
} else {
kimchi.addVMPCIDevice(kimchi.selectedGuest, {
name: id
}, function(task) {
getOngoingAttachingDevices(task);
}, function(err) {
wok.message.error(err.responseJSON.reason, '#alert-modal-container');
});
}
}
});
};
var setupPCIDevice = function() {
kimchi.getAvailableHostPCIDevices(function(hostPCIs) {
kimchi.getVMPCIDevices(kimchi.selectedGuest, function(vmPCIs) {
_generatePciDeviceHtml(hostPCIs, 'hostPCIs');
_generatePciDeviceHtml(vmPCIs, 'vmPCIs');
pciDeviceButtonHandler();
$('#form-guest-edit-pci > .wok-mask').fadeOut(300, function() {});
});
});
$('select', '#form-guest-edit-pci').change(function() {
filterPCINodes($(this).val(), $('input#guest-edit-pci-filter', '#form-guest-edit-pci').val());
});
$('select', '#form-guest-edit-pci').selectpicker();
$('input#guest-edit-pci-filter', '#form-guest-edit-pci').on('keyup', function() {
filterPCINodes($('select', '#form-guest-edit-pci').val(), $(this).val());
});
};
var setupSnapshot = function() {
var currentSnapshot;
var setCurrentSnapshot = function(aSnapshot) {
if (!aSnapshot) {
kimchi.getCurrentSnapshot(kimchi.selectedGuest, function(snapshot) {
if (snapshot && snapshot.name) {
aSnapshot = snapshot.name;
}
}, null, true);
}
if (aSnapshot) {
if (currentSnapshot) {
$(".fa.fa-check", "#" + currentSnapshot).addClass("hide");
}
$(".fa.fa-check", "#" + aSnapshot).removeClass("hide");
currentSnapshot = aSnapshot;
}
};
var addItem = function(data, container) {
var itemNode = $.parseHTML(wok.substitute($('#snapshot-tmpl').html(), data));
$("." + container, "#form-guest-edit-snapshot").append(itemNode);
$(".delete", itemNode).on('click', function(evt) {
evt.preventDefault();
var item = $(this).parent().parent();
$("button", "#form-guest-edit-snapshot").prop("disabled", true);
kimchi.deleteSnapshot(kimchi.selectedGuest, item.prop("id"), function() {
item.remove();
setCurrentSnapshot();
$("button", "#form-guest-edit-snapshot").prop("disabled", false);
}, function(data) {
wok.message.error(data.responseJSON.reason, '#alert-modal-container');
$("button", "#form-guest-edit-snapshot").prop("disabled", false);
});
});
$(".revert", itemNode).on('click', function(evt) {
evt.preventDefault();
var item = $(this).parent().parent();
$(".fa.fa-check", item).addClass("hide");
$(".wok-loading", item).removeClass("hide");
$("button", "#form-guest-edit-snapshot").prop("disabled", true);
kimchi.revertSnapshot(kimchi.selectedGuest, item.prop("id"), function() {
$(".wok-loading", item).addClass("hide");
$("button", "#form-guest-edit-snapshot").prop("disabled", false);
setCurrentSnapshot(item.prop("id"));
kimchi.listVmsAuto();
wok.window.close();
}, function(data) {
wok.message.error(data.responseJSON.reason, '#alert-modal-container');
$(".wok-loading-icon", item).addClass("hide");
$("button", "#form-guest-edit-snapshot").prop("disabled", false);
});
});
};
var addOngoingItem = function(task) {
var uri = task.target_uri;
addItem({
name: uri.substring(uri.lastIndexOf('/') + 1, uri.length),
created: "",
listMode: "hide",
createMode: ""
}, 'task');
if (kimchi.trackingTasks.indexOf(task.id) === -1) {
kimchi.trackTask(task.id, function(task) {
listGeneratingSnapshots();
$("button", "#form-guest-edit-snapshot").prop("disabled", false);
}, function(err) {
wok.message.error(err.message, '#alert-modal-container');
listGeneratingSnapshots();
$("button", "#form-guest-edit-snapshot").prop("disabled", false);
});
}
};
var listGeneratingSnapshots = function() {
kimchi.getTasksByFilter('status=running&target_uri=' + encodeURIComponent('^/plugins/kimchi/snapshots/*'), function(tasks) {
$(".task", "#form-guest-edit-snapshot").empty();
for (var i = 0; i < tasks.length; i++) {
addOngoingItem(tasks[i]);
}
if (tasks.length === 0) {
listSnapshots();
}
});
};
var listSnapshots = function() {
kimchi.listSnapshots(kimchi.selectedGuest, function(data) {
$(".body", "#form-guest-edit-snapshot").empty();
for (var i = 0; i < data.length; i++) {
data[i].created = new Date(data[i].created * 1000).toLocaleString();
data[i].createMode = "hide";
data[i].listMode = "";
addItem(data[i], 'body');
}
setCurrentSnapshot();
});
};
listGeneratingSnapshots();
$(".add", "#form-guest-edit-snapshot").on('click', function(evt) {
evt.preventDefault();
kimchi.createSnapshot(kimchi.selectedGuest, function(task) {
$("button", "#form-guest-edit-snapshot").prop("disabled", true);
addOngoingItem(task);
});
});
};
var setupBootOrder = function(guest) {
var guestBootOrder = guest['bootorder'];
var dev = ["cdrom", "hd", "network"];
var excludedDev = dev.filter(function(e){return this.indexOf(e)<0;},guestBootOrder);
$('#myList').empty();
$.each(guestBootOrder, function(index, value) {
item = $.parseHTML("
" + value + "
");
$('#myList').append(item);
$('#myList .' + value + ' .addBootOrderElem').prop('disabled', true);
$('#myList .' + value + ' .deleteBootOrderElem').prop('disabled', false);
});
if (excludedDev) {
$.each(excludedDev, function(index, value) {
item = $.parseHTML("
" + value + "
");
$('#myList').append(item);
$('#myList .' + value + ' .deleteBootOrderElem').prop('disabled', true);
});
}
if (guestBootOrder.length == 1) {
$('#myList .deleteBootOrderElem').prop('disabled', true);
}
$('.boot-order').sortable({
items: 'li',
cursor: 'move',
opacity: 0.6,
containment: "parent",
start: function(event, ui) {
$(this).addClass('focus');
},
stop: function(event, ui) {
$(this).removeClass('focus');
},
change: function(event, ui) {
// callback once started changing order
},
update: function(event, ui) {
// callback once finished order
$(saveButton).prop('disabled', false);
bootOrderOptions = [];
$("#myList li").each(function() {
bootOrderOptions.push($(this).attr("data-value").toLowerCase())
});
bootOrderOptions.forEach(function(entry) {
console.log(entry);
});
var data = {
bootorder: bootOrderOptions
};
}
});
$(".deleteBootOrderElem").on('click', function(evt) {
evt.preventDefault();
var item = $(this).parent().parent().attr("data-value").toLowerCase();
var index = guestBootOrder.indexOf(item);
$('.' + item + ' i.fa.fa-check').replaceWith('');
$('#myList .' + item + ' .deleteBootOrderElem').prop('disabled', true);
$('#myList .' + item + ' .addBootOrderElem').prop('disabled', false);
if (index !== -1) {
guestBootOrder.splice(index, 1);
}
if (guestBootOrder.length == 1) {
$('#myList .deleteBootOrderElem').prop('disabled', true);
}
var data = {
bootorder: guestBootOrder
};
});
$(".addBootOrderElem").on('click', function(evt) {
evt.preventDefault();
var item = $(this).parent().parent().attr("data-value").toLowerCase();
var index = guestBootOrder.indexOf(item);
$('.' + item).prepend(" ");
$('#myList .' + item + ' .addBootOrderElem').prop('disabled', true);
$('#myList .' + item + ' .deleteBootOrderElem').prop('disabled', false);
guestBootOrder.push(item);
if (guestBootOrder.length > 1) {
$('#myList .deleteBootOrderElem').prop('disabled', false);
}
var data = {
bootorder: guestBootOrder
};
});
};
var initContent = function(guest) {
guest['icon'] = guest['icon'] || 'plugins/kimchi/images/icon-vm.png';
$('#form-guest-edit-general').fillWithObject(guest);
$('#guest-edit-memory-textbox').val(parseInt(guest.memory.current));
$('#guest-edit-max-memory-textbox').val(parseInt(guest.memory.maxmemory));
$("#enableGuestAutostart").prop('checked', parseInt(guest.autostart));
kimchi.thisVMState = guest['state'];
refreshCDROMs();
$('#guest-edit-attach-cdrom-button').on('click', function(event) {
event.preventDefault();
wok.window.open('plugins/kimchi/guest-storage-add.html', 'extendCreateStorage');
});
if ((kimchi.thisVMState === "running") || (kimchi.thisVMState === "paused")) {
if (kimchi.capabilities.mem_hotplug_support) {
$("#form-guest-edit-general input").not("#guest-edit-memory-textbox").not("#enableGuestAutostart").prop("disabled", true);
} else {
$("#form-guest-edit-general input").not("#enableGuestAutostart").prop("disabled", true);
}
}
if (! kimchi.capabilities.mem_hotplug_support) {
$("#guest-edit-max-memory-textbox").prop("disabled", true);
$("#guest-edit-memory-hotplug-unsupported").removeClass('hidden');
}
$('#guest-show-max-memory').on('click', function(e) {
e.preventDefault;
$('#guest-max-memory-panel').slideToggle();
var text = $('#guest-show-max-memory span.text').text();
$('#guest-show-max-memory span.text').text(text == i18n['KCHVMED6008M'] ? i18n['KCHVMED6009M'] : i18n['KCHVMED6008M']);
$('#guest-show-max-memory i.fa').toggleClass('fa-plus-circle fa-minus-circle');
});
if ((kimchi.thisVMState !== "running") && (kimchi.thisVMState !== "paused")) {
$("#guest-edit-memory-textbox").bind('keyup blur', function(e) {
$('#guest-edit-max-memory-textbox').val($(this).val());
});
}
if(kimchi.hostarch === s390xArch){
var consoleData = guest.console ? guest.console : '';
$('#guest-edit-console').val(consoleData);
if (kimchi.thisVMState === "shutoff") {
$('#guest-edit-console').prop('disabled', false);
}else{
$('#guest-edit-console').prop('disabled', true);
}
$('#guest-console-panel').show();
$('#guest-edit-console').selectpicker();
}
var onAttached = function(params) {
refreshCDROMs();
};
var onReplaced = function(params) {
refreshCDROMs();
};
var onDetached = function(params) {
refreshCDROMs();
};
initStorageListeners();
setupInterface();
setupPermission();
setupPCIDevice();
setupSnapshot();
setupBootOrder(guest);
kimchi.init_processor_tab(guest.cpu_info, $(saveButton));
if ((kimchi.thisVMState === "running") || (kimchi.thisVMState === "paused")) {
$('#guest-edit-max-processor-textbox').attr("disabled", true);
$('#sockets').attr("disabled", true);
$('#cores').attr("disabled", true);
$('#threads').attr("disabled", true);
$("#topology-checkbox").hide();
$("#settings-readonly-help").removeClass('hidden');
}
wok.topic('kimchi/vmCDROMAttached').subscribe(onAttached);
wok.topic('kimchi/vmCDROMReplaced').subscribe(onReplaced);
wok.topic('kimchi/vmCDROMDetached').subscribe(onDetached);
kimchi.clearGuestEdit = function() {
wok.topic('kimchi/vmCDROMAttached').unsubscribe(onAttached);
wok.topic('kimchi/vmCDROMReplaced').unsubscribe(onReplaced);
wok.topic('kimchi/vmCDROMDetached').unsubscribe(onDetached);
};
};
kimchi.retrieveVM(kimchi.selectedGuest, initContent);
var generalSubmit = function(event) {
kimchi.retrieveVM(kimchi.selectedGuest, function(org) {
$(saveButton).prop('disabled', true);
var data = $('#form-guest-edit-general').serializeObject();
data['autostart'] = $("#enableGuestAutostart").prop('checked');
data['memory'] = {current: Number(data['memory-ui']), maxmemory: Number(data['max-memory'])};
var changedFields = {};
for (var key in data) {
valueFromUI = data[key];
if (valueFromUI instanceof Object) {
// Compare if Objects of original and data are identical
// Handle special case when key is memory and guest is running as valueFromUI will return a null for max mem
// since it is disabled;
if (kimchi.thisVMState === 'running' || kimchi.thisVMState === 'paused') {
if (key === 'memory') {
// Replace valueFromUI of max mem with one from original as otherwise the value is undefined
data['memory']['maxmemory'] = org.memory.maxmemory;
}
}
// NOTE: Be aware of using this comparison as the order of the properties matter
if (JSON.stringify(valueFromUI) !== JSON.stringify(org[key])) {
changedFields[key] = valueFromUI;
}
} else {
if (org[key] !== undefined) {
if (data[key] != org[key]) {
changedFields[key] = valueFromUI;
}
}
}
}
var origMem = Number(org.memory.current);
var origMaxMem = Number(org.memory.maxmemory);
var currentMem = data['memory-ui'];
var currentMaxMem = data['max-memory'];
if ('memory' in changedFields) {
if (currentMaxMem !== undefined) {
currentMaxMem = Number(currentMaxMem);
if (currentMaxMem === origMaxMem) {
delete changedFields.memory.maxmemory;
}
} else {
delete changedFields.memory.maxmemory;
}
if (currentMem !== undefined) {
currentMem = Number(currentMem);
if (kimchi.thisVMState === 'running' || kimchi.thisVMState === 'paused') {
// Compare to original max mem since current max mem is undefined in UI due to being disabled
if (currentMem > origMaxMem) {
wok.message.error(i18n['KCHVM0002E'], '#alert-modal-container');
$(saveButton).prop('disabled', false);
return;
}
}
if (currentMem === origMem) {
delete changedFields.memory.current;
}
} else {
delete changedFields.memory.current;
}
}
checkedValue = [];
$("#myList i.fa.fa-check").each(function() {
checkedValue.push($(this).parent().attr("data-value").toLowerCase());
});
changedFields.bootorder = checkedValue;
kimchi.updateVM(kimchi.selectedGuest, changedFields, function() {
kimchi.listVmsAuto();
wok.window.close();
}, function(err) {
wok.message.error(err.responseJSON.reason, '#alert-modal-container');
$(saveButton).prop('disabled', false);
});
});
};
var permissionSubmit = function(event) {
var content = {
users: [],
groups: []
};
authType = wok.config['auth'];
if (authType === 'pam') {
$("#permission-sel-users").children().each(function() {
content.users.push($("label", this).text());
});
$("#permission-sel-groups").children().each(function() {
content.groups.push($("label", this).text());
});
kimchi.updateVM(kimchi.selectedGuest, content, function() {
wok.window.close();
});
} else if (authType === 'ldap') {
$(saveButton).prop('disabled', true);
var errors = 0;
$(".body", "#form-guest-edit-permission .ldap").children().each(function() {
var elem = $(this);
content.users.push(elem.attr("id"));
if (!$('input', elem).hasClass('hide')) {
var user = {
'user_id': $(this).attr("id")
};
kimchi.getUserById(user, null, function(data) {
errors += 1;
$("input", elem).addClass("checked");
});
}
});
if (errors === 0) {
kimchi.updateVM(kimchi.selectedGuest, content, function() {
wok.window.close();
});
} else {
$(saveButton).prop('disabled', false);
}
}
};
var processorSubmit = function(event) {
kimchi.retrieveVM(kimchi.selectedGuest, function(org) {
$(saveButton).prop('disabled', true);
var data = {};
var cpu = parseInt($('#vcpus').val());
var maxCpu = parseInt($('#guest-edit-max-processor-textbox').val());
var maxCpuFinal = cpu;
if (maxCpu >= cpu) {
maxCpuFinal = maxCpu;
}
if (kimchi.thisVMState === 'running' || kimchi.thisVMState === 'paused') {
data['cpu_info'] = {vcpus: cpu};
} else {
if ($("input:checkbox", "#form-edit-processor").prop("checked")) {
data['cpu_info'] = {
vcpus: cpu,
maxvcpus: maxCpuFinal,
topology: {
sockets: parseInt($("#sockets").val()),
cores: parseInt($("#cores").val()),
threads: parseInt($("#threads").val())
}
};
} else {
data['cpu_info'] = {
vcpus: cpu,
maxvcpus: maxCpuFinal,
topology: {}
};
}
}
kimchi.updateVM(kimchi.selectedGuest, data, function() {
kimchi.listVmsAuto();
wok.window.close();
}, function(err) {
wok.message.error(err.responseJSON.reason, '#alert-modal-container');
$(saveButton).prop('disabled', false);
});
});
};
if(kimchi.hostarch === s390xArch){
$('#guest-edit-window ul li a[data-id="form-guest-edit-pci"],a[data-id="form-guest-edit-snapshot"]').parent().hide();
}
};
================================================
FILE: ui/js/src/kimchi.guest_livemigration.js
================================================
/*
* Project Kimchi
*
* Copyright IBM Corp, 2016-2017
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
kimchi.guest_livemigration_main = function() {
kimchi.setupLiveMigrationFormEvent();
kimchi.initLiveMigrationDialog();
};
kimchi.getOngoingMigration = function(guestName, toDelete) {
var guests = [];
kimchi.getTasksByFilter('status=running&target_uri='+ encodeURIComponent('^/plugins/kimchi/vms/' + guestName + '/migrate'), function(tasks) {
for (var i = 0; i < tasks.length; i++) {
var guestUri = tasks[i].target_uri;
var guestName = guestUri.split('/')[4];
guests[guestName] = tasks[i];
if (kimchi.trackingTasks.indexOf(tasks[i].id) >= 0) {
continue;
}
kimchi.trackTask(tasks[i].id, function(guests) {
if (toDelete) {
kimchi.deleteVM(guestName, function(result) {
return;
});
}
kimchi.listVmsAuto();
}, function(guests) {
wok.message.error(''+guestName+': '+guests.message,'#alert-container', true, 'failed-migration-'+guests.id);
return;
}, function(guests) {
return;
});
}
}, null, true);
return guests;
};
kimchi.initLiveMigrationDialog = function(okCallback) {
$("#migrateFormOk").on("click", function() {
$("#migrateFormOk").prop("disabled", true);
$("#remote_host").prop("readonly", "readonly");
$("#user").prop("readonly", "readonly");
$("#password").prop("readonly", "readonly");
$("#deleteVM").prop("readonly", "readonly");
wok.window.close();
kimchi.initLiveMigrationProccess();
});
};
kimchi.initLiveMigrationProccess = function() {
var obj = kimchi.getLiveMigrationInputValues();
var toDelete = obj[kimchi.selectedGuest].toDelete;
kimchi.migrateGuest(kimchi.selectedGuest, obj[kimchi.selectedGuest].values, function() {
kimchi.listVmsAuto();
kimchi.getOngoingMigration(kimchi.selectedGuest, toDelete);
}, function(err) {
wok.message.error(err.responseJSON.reason);
});
}
kimchi.getLiveMigrationInputValues = function() {
var host = $("#remote_host").val();
var username = $("#user").val();
var password = $("#password").val();
var toDelete = $("#deleteVM").prop('checked');
var enable_rdma = $("#enableRDMA").prop('checked');
var data = {};
data[kimchi.selectedGuest] = {
values: {
remote_host: host,
enable_rdma: enable_rdma
},
toDelete: toDelete
};
if (username && password) {
data[kimchi.selectedGuest].values.user = username;
data[kimchi.selectedGuest].values.password = password;
}
return data;
};
kimchi.setupLiveMigrationFormEvent = function() {
$("#migrateFormOk").prop("disabled", true);
$("#remote_host").on("keyup", function(event) {
if (!this.value) {
$(this).parent().addClass('has-error');
} else {
$(this).parent().removeClass('has-error');
}
kimchi.updateLiveMigrationButton();
});
$("#user").on("keyup", function(event) {
if (this.value && !$("#password").val()) {
$("#user").parent().removeClass('has-warning');
$("#password").parent().addClass('has-warning');
} else {
$("#user").parent().removeClass('has-warning');
$("#password").parent().removeClass('has-warning');
}
kimchi.updateLiveMigrationButton();
});
$("#password").on("keyup", function(event) {
if (this.value && !$("#user").val()) {
$("#user").parent().addClass('has-warning');
} else {
$("#user").parent().removeClass('has-warning');
$("#password").parent().removeClass('has-warning');
kimchi.updateLiveMigrationButton();
}
});
};
kimchi.updateLiveMigrationButton = function() {
if ($("#remote_host").val()) {
if ($("input[type='text']").parent().hasClass("has-error") || $("input[type='text']").parent().hasClass("has-warning")) {
$("#migrateFormOk").prop("disabled", true);
} else {
$("#migrateFormOk").prop("disabled", false);
}
};
};
================================================
FILE: ui/js/src/kimchi.guest_main.js
================================================
/*
* Project Kimchi
*
* Copyright IBM Corp, 2013-2017
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// init Guest Filter List global variable
var guestFilterList;
var listFiltered;
//init s390x Architecture
var s390xArch = 's390x';
kimchi.sampleGuestObject = {
"name": "",
"uuid": "",
"state": "shutoff",
"persistent": true,
"icon": null,
"cpus": 0,
"memory": 0,
"stats": {
"net_throughput": 0,
"io_throughput_peak": 100,
"cpu_utilization": 0,
"mem_utilization": 0,
"io_throughput": 0,
"net_throughput_peak": 100
},
"screenshot": null,
"graphics": {
"passwd": null,
"passwdValidTo": null,
"type": "vnc",
"port": null,
"listen": "127.0.0.1"
},
"users": [],
"groups": [],
"access": "full"
};
kimchi.vmstart = function(event) {
var button = event.target;
if (!$(button).hasClass('loading')) {
$(button).addClass('loading');
var vm = $(button).closest('li[name=guest]');
var vm_id = $(vm).attr("id");
// setting up css class when starting
$(vm).find('.guest-state').removeClass('shutoff');
$(vm).find('.guest-state').addClass('starting');
$(vm).find('.progress').css("display", "none");
$(vm).find('.percentage - label').html('--');
$(vm).find('.measure-label').html('--');
$(vm).addClass('inactive');
$(vm).find('.distro-icon').addClass('inactive');
$(vm).find('.vnc-link').css("display", "none");
$(vm).find('.column-vnc').html('--');
kimchi.startVM(vm_id, function(result) {
$(button).removeClass('loading');
kimchi.listVmsAuto();
}, function(err) {
$(button).removeClass('loading');
wok.message.error(err.responseJSON.reason);
});
} else {
event.preventDefault();
event.stopPropagation();
return;
}
};
kimchi.vmsuspend = function(event) {
var button = event.target;
if (!$(button).hasClass('pause-gray')) {
$(button).addClass('pause-gray');
var vm = $(button).closest('li[name=guest]');
var vm_id = $(vm).attr("id");
kimchi.suspendVM(vm_id, function(result) {
$(button).removeClass('pause-gray');
kimchi.listVmsAuto();
}, function(err) {
$(button).removeClass('pause-gray');
wok.message.error(err.responseJSON.reason);
});
} else {
event.preventDefault();
event.stopPropagation();
return;
}
};
kimchi.vmresume = function(event) {
var button = event.target;
if (!$(button).hasClass('resume-gray')) {
$(button).addClass('resume-gray');
var vm = $(button).closest('li[name=guest]');
var vm_id = vm.attr("id");
kimchi.resumeVM(vm_id, function(result) {
$(button).removeClass('resume-gray');
kimchi.listVmsAuto();
}, function(err) {
$(button).removeClass('resume-gray');
wok.message.error(err.responseJSON.reason);
});
} else {
event.preventDefault();
event.stopPropagation();
return;
}
};
kimchi.vmpoweroff = function(event) {
var button = event.target;
if (!$(button).hasClass('loading')) {
$(button).addClass('loading');
var vm = $(button).closest('li[name=guest]');
var vm_id = vm.attr("id");
var vmObject = vm.data();
var vm_persistent = vmObject.persistent == true;
var content_msg_1 = i18n['KCHVM6003M'].replace('%1', ''+vm_id+'');
var content_msg_2 = i18n['KCHVM6009M'].replace('%1', ''+vm_id+'');
var content_msg = vm_persistent ? content_msg_1 : content_msg_2;
var settings = {
title: i18n['KCHVM6002M'],
content: content_msg,
confirm: i18n['KCHAPI6002M'],
cancel: i18n['KCHAPI6003M']
};
wok.confirm(settings, function() {
kimchi.poweroffVM(vm_id, function(result) {
$(button).removeClass('loading');
kimchi.listVmsAuto();
}, function(err) {
wok.message.error(err.responseJSON.reason);
});
}, function() {});
} else {
event.preventDefault();
event.stopPropagation();
}
};
kimchi.vmshutdown = function(event) {
var button = event.target;
var vm = $(button).closest('li[name=guest]');
var vm_id = vm.attr("id");
var confirmMessage = i18n['KCHVM6007M'].replace('%1', ''+vm_id+'');
var settings = {
title: i18n['KCHVM6006M'],
content: confirmMessage,
confirm: i18n['KCHAPI6002M'],
cancel: i18n['KCHAPI6003M']
};
wok.confirm(settings, function() {
kimchi.shutdownVM(vm_id, function(result) {
kimchi.listVmsAuto();
}, function(err) {
wok.message.error(err.responseJSON.reason);
});
}, function() {});
};
kimchi.vmreset = function(event) {
var button = event.target;
if (!$(button).hasClass('loading')) {
$(button).addClass('loading');
var vm = $(button).closest('li[name=guest]');
var vm_id = $(vm).attr("id");
var confirmMessage = i18n['KCHVM6005M'].replace('%1', ''+vm_id+'');
var settings = {
title: i18n['KCHVM6004M'],
content: confirmMessage,
confirm: i18n['KCHAPI6002M'],
cancel: i18n['KCHAPI6003M']
};
wok.confirm(settings, function() {
// setting up css class when resetting
$(vm).find('.guest-state').removeClass('running');
$(vm).find('.guest-state').addClass('resetting');
$(vm).find('.fa-spin').addClass('active');
kimchi.resetVM(vm_id, function(result) {
$(button).removeClass('loading');
kimchi.listVmsAuto();
}, function(err) {
$(button).removeClass('loading');
wok.message.error(err.responseJSON.reason);
});
}, function() {});
} else {
event.preventDefault();
event.stopPropagation();
return;
}
};
kimchi.vmdelete = function(event) {
var button = event.target;
var vm = $(button).closest('li[name=guest]');
var vm_id = $(vm).attr("id");
var confirmMessage = i18n['KCHVM6001M'].replace('%1', ''+vm_id+'');
var settings = {
title: i18n['KCHVM6008M'],
content: confirmMessage,
confirm: i18n['KCHAPI6002M'],
cancel: i18n['KCHAPI6003M']
};
wok.confirm(settings, function() {
kimchi.deleteVM(vm_id, function(result) {
kimchi.listVmsAuto();
}, function(err) {
wok.message.error(err.responseJSON.reason);
});
}, function() {});
};
kimchi.vmedit = function(event) {
var button = event.target;
var vm = $(button).closest('li[name=guest]');
var vm_id = $(vm).attr("id");
kimchi.selectedGuest = vm_id;
wok.window.open({
url: 'plugins/kimchi/guest-edit.html',
close: function() {
kimchi.clearGuestEdit();
}
});
};
kimchi.vmmigrate = function(event) {
var button = event.target;
var vm = $(button).closest('li[name=guest]');
var vm_id = $(vm).attr("id");
kimchi.selectedGuest = vm_id;
wok.window.open('plugins/kimchi/guest-migration.html');
};
kimchi.vmclone = function(event) {
var button = event.target;
var vm = $(button).closest('li[name=guest]');
var vm_id = $(vm).attr("id");
kimchi.selectedGuest = vm_id;
wok.window.open('plugins/kimchi/guest-clone.html');
};
kimchi.openVmSerialConsole = function(event) {
var button = event.target;
var vm = $(button).closest('li[name=guest]');
kimchi.serialToVM($(vm).attr('id'));
};
kimchi.openVmConsole = function(event) {
var button = event.target;
var vm = $(button).closest('li[name=guest]');
var vmObject = $(vm).data();
if (vmObject.graphics['type'] == 'vnc') {
kimchi.vncToVM($(vm).attr('id'));
} else if (vmObject.graphics['type'] == 'spice') {
kimchi.spiceToVM($(vm).attr('id'));
}
};
kimchi.getVmsCurrentConsoleImgs = function() {
var res = new Object();
$('#guestList').children().each(function() {
res[$(this).attr('id')] = $(this).find('img.imgactive').attr('src');
})
return res;
};
kimchi.getOpenMenuVmId = function() {
var result;
var openMenu = $('#guestList div[name="actionmenu"] .dropdown-menu:visible');
if (openMenu) {
var li_element = openMenu.closest('li');
result = li_element.attr('id');
}
return result;
};
kimchi.initGuestFilter = function() {
// Create the list with the css classes that could be filtered at
// the first click at the Filter Input Field
$('#search_input').one('keyup', function(event) {
var options = {
valueNames: ['title', 'distro-icon', 'processors-percentage', 'memory-percentage', 'storage-percentage', 'network-percentage']
};
guestFilterList = new List('guest-content-container', options);
});
};
kimchi.resetGuestFilter = function() {
if (guestFilterList) {
$('#search_input').val();
listFiltered = false;
}
};
kimchi.initClone = function() {
var numTimesToClone = $('#numberClone').val();
for (var i = 0; i < numTimesToClone; i++) {
kimchi.cloneGuest(kimchi.selectedGuest, function(data) {
kimchi.listVmsAuto();
});
}
wok.window.close();
};
kimchi.guestSetRequestHeader = function(xhr) {
xhr.setRequestHeader('Accept', 'text/html');
};
kimchi.toggleGuestsGallery = function() {
$(".wok-guest-list, .wok-guest-gallery").toggleClass("wok-guest-list wok-guest-gallery");
$(".wok-list, .wok-gallery").toggleClass("wok-list wok-gallery");
var text = $('#guest-gallery-table-button span.text').text();
$('#guest-gallery-table-button span.text').text(text == i18n['KCHTMPL6005M'] ? i18n['KCHTMPL6004M'] : i18n['KCHTMPL6005M']);
var buttonText = $('#guest-gallery-table-button span.text').text();
if (buttonText.indexOf("Gallery") !== -1) {
// Currently in list view
kimchi.setGuestView("guestView", "list");
} else {
// Currently in gallery
kimchi.setGuestView("guestView", "gallery");
}
};
kimchi.setGuestView = function(name, value) {
window.localStorage.setItem(name, value);
};
kimchi.readGuestView = function(name) {
var viewName = window.localStorage.getItem(name);
if (viewName !== "") {
return viewName;
} else {
return null;
}
};
kimchi.showGuestGallery = function() {
$(".wok-guest-list").addClass("wok-guest-gallery");
$(".wok-list").addClass("wok-gallery");
$(".wok-guest-gallery").removeClass("wok-guest-list");
$(".wok-gallery").removeClass("wok-list");
$('#guest-gallery-table-button span.text').text(i18n['KCHTMPL6004M']);
};
kimchi.showGuestList = function() {
$(".wok-guest-list").removeClass("wok-guest-gallery");
$(".wok-list").removeClass("wok-gallery");
$(".wok-guest-gallery").addClass("wok-guest-list");
$(".wok-gallery").addClass("wok-list");
$('#guest-gallery-table-button span.text').text(i18n['KCHTMPL6005M']);
};
kimchi.guest_main = function() {
$('body').addClass('wok-list');
var viewFound = kimchi.readGuestView("guestView");
if (viewFound) {
if(viewFound === "gallery") {
// should be showing gallery
kimchi.showGuestGallery();
} else {
// Should be showing list
kimchi.showGuestList();
}
} else {
// Default to showing list
kimchi.showGuestList();
}
var toolsHtml = '
'
var viewFound = kimchi.readTemplateView("templateView");
if (viewFound) {
if(viewFound === "gallery") {
// should be showing gallery
kimchi.showTemplateGallery();
} else {
// Should be showing list
kimchi.showTemplateList();
}
} else {
// Default to showing list
kimchi.showTemplateList();
}
if (wok.tabMode['templates'] === 'admin') {
$('#toolbar ul.tools').html(toolsHtml);
$("#template-add").on("click", function(event) {
wok.window.open({
url: 'plugins/kimchi/template-add.html',
close: function() {
if (kimchi.deepScanHandler) {
kimchi.deepScanHandler.stop = true;
}
}
});
});
}
// Register listeners to update the page according to user interactions
wok.addNotificationListener('POST:/kimchi/templates', kimchi.doListTemplates);
wok.addNotificationListener('DELETE:/kimchi/template', kimchi.doListTemplates);
wok.addNotificationListener('PUT:/kimchi/template', kimchi.doListTemplates);
kimchi.doListTemplates();
};
================================================
FILE: ui/pages/Makefile.am
================================================
#
# Kimchi
#
# Copyright IBM Corp, 2013-2016
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
SUBDIRS = help tabs
htmldir = $(datadir)/wok/plugins/kimchi/ui/pages
dist_html_DATA = $(wildcard *.tmpl) $(NULL)
================================================
FILE: ui/pages/guest-add.html.tmpl
================================================
#*
* Project Kimchi
*
* Copyright IBM Corp, 2013-2017
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*#
#unicode UTF-8
#import gettext
#from wok.cachebust import href
#silent t = gettext.translation($lang.domain, $lang.localedir, languages=$lang.lang, fallback=True)
#silent _ = t.gettext
#silent _t = t.gettext
$_("Create a New Virtual Machine")
================================================
FILE: ui/pages/guest-clone.html.tmpl
================================================
#*
* Project Kimchi
*
* Copyright IBM Corp, 2016
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*#
#unicode UTF-8
#import gettext
#from wok.cachebust import href
#silent t = gettext.translation($lang.domain, $lang.localedir, languages=$lang.lang, fallback=True)
#silent _ = t.gettext
#silent _t = t.gettext
$_("Clone a Guest")
$_("When the target guest has SCSI or iSCSI volumes, they will be cloned on the default storage pool. The same will happen when the target pool does not have enough space to clone the volumes. Do you want to continue?")
================================================
FILE: ui/pages/guest-edit.html.tmpl
================================================
#*
* Project Kimchi
*
* Copyright IBM Corp, 2013-2017
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*#
#unicode UTF-8
#import gettext
#silent t = gettext.translation($lang.domain, $lang.localedir, languages=$lang.lang, fallback=True)
#silent _ = t.gettext
#silent _t = t.gettext
================================================
FILE: ui/pages/guest-migration.html.tmpl
================================================
#*
* Project Kimchi
*
* Copyright IBM Corp, 2016-2017
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*#
#unicode UTF-8
#import gettext
#from wok.cachebust import href
#silent t = gettext.translation($lang.domain, $lang.localedir, languages=$lang.lang, fallback=True)
#silent _ = t.gettext
#silent _t = t.gettext
$_("Migrate a Guest")
$_("Disclaimer: This process cannot be stopped after started, can take a long time to complete and will turn off the VM on this Hypervisor when it is successfully migrated to the remote destination.")
$_("IP Address or Hostname")
$_("The following fields are optional. Fill them if you want Kimchi to setup a password-less ssh session between the localhost and the remote host. The setup process will only be successful if the user has 'SUDO ALL' permission in the remote machine.")
$_("Username of the remote host")
$_("Password of the user in the remote host")
$_("Check this option only if RDMA is properly configured in both source and destination hosts, otherwise migration will fail.")
================================================
FILE: ui/pages/guest-storage-add.html.tmpl
================================================
#*
* Project Kimchi
*
* Copyright IBM Corp, 2014-2016
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*#
#unicode UTF-8
#import gettext
#from wok.cachebust import href
#silent t = gettext.translation($lang.domain, $lang.localedir, languages=$lang.lang, fallback=True)
#silent _ = t.gettext
#silent _t = t.gettext
$_("Add a Storage Device to VM")
================================================
FILE: ui/pages/guest.html.tmpl
================================================
#*
* Project Kimchi
*
* Copyright IBM Corp, 2013-2017
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*#
#unicode UTF-8
#import gettext
#from wok.cachebust import href
#silent t = gettext.translation($lang.domain, $lang.localedir, languages=$lang.lang, fallback=True)
#silent _ = t.gettext
#silent _t = t.gettext
================================================
FILE: ui/pages/help/Makefile.am
================================================
# Copyright IBM Corp, 2014-2016
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
SUBDIRS = zh_CN it_IT en_US zh_TW pt_BR ja_JP ru_RU ko_KR fr_FR de_DE es_ES
DITA_HTML_FILES = $(patsubst %.dita,%.html,$(wildcard */*.dita))
HTML_FILES = $(if $(DITA_HTML_FILES), $(DITA_HTML_FILES), $(wildcard */*.html))
DITA_XSL_FILE = dita-help.xsl
EXTRA_DIST = $(DITA_XSL_FILE)
helpdir = $(datadir)/wok/plugins/kimchi/ui/pages/help
dist_help_DATA = kimchi.css
all: $(HTML_FILES) $(wildcard */*.dita)
%.html: %.dita $(DITA_XSL_FILE)
xsltproc -o $@ $(DITA_XSL_FILE) $<
CLEANFILES = $(HTML_FILES)
================================================
FILE: ui/pages/help/de_DE/Makefile.am
================================================
# Copyright IBM Corp, 2014-2016
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
de_DE_helpdir = $(datadir)/wok/plugins/kimchi/ui/pages/help/de_DE
dist_de_DE_help_DATA = $(wildcard *.html) $(NULL)
EXTRA_DIST = $(wildcard *.dita)
CLEANFILES = $(wildcard *.html)
================================================
FILE: ui/pages/help/de_DE/guests.dita
================================================
GästeAuf der Seite Gäste sind die definierten Gäste Ihres Servers aufgelistet.
Für jeden Gast werden die folgenden Informationen angezeigt:
Name
Name des Gastes.
CPU
Prozentsatz der Prozessorauslastung auf dem Gastsystem.
Platten-E/A
Platten-E/A-Übertragungsrate in KB pro Sekunde.
Netz-E/A
Netz-E/A-Übertragungsrate in KB pro Sekunde.
Live Tile
Status der Konsole für das Gastbetriebssystem oder ein Symbol, das die
Linux-Verteilung darstellt, wenn
der Gast nicht aktiv ist.
Die folgenden Aktionssymbole werden für jeden Gast angezeigt:
Zurücksetzen
Klicken Sie hier, um den Gast zurückzusetzen.
Power (Starten oder Stoppen)
Klicken Sie hier, um den Gast ein- bzw. auszuschalten. Wenn das Symbol rot ist,
ist er ausgeschaltet. Wenn das Symbol grün ist, ist er eingeschaltet.
Die folgenden Aktionen können für jeden Gast ausgewählt werden:
Wählen Sie Verbinden aus, um eine Verbindung zur fernen Konsole
für das Gastbetriebssystem herzustellen.
Wählen Sie Klonen aus, um eine vorhandene Gastdefinition zur Erstellung eines Gastes zu kopieren.
Wählen Sie Zurücksetzen aus, um den Gast zurückzusetzen. Sie können nur Gäste zurücksetzen, die bereits gestartet
wurden.
Wählen Sie Bearbeiten aus, um die Eigenschaften eines
bestehenden Gastes zu bearbeiten. Gäste können nur bearbeitet werden, wenn sie gestoppt sind.
Wählen Sie Starten aus, um einen Gast zu starten.
Wählen Sie Herunterfahren aus, um einen Gast ordnungsgemäß zu beenden.
Wählen Sie Ausschalten aus, um eine sofortige Beendigung des Gastes zu erzwingen.
Wählen Sie Löschen aus, um den Gast zu löschen.
Um einen Gast zu erstellen, klicken Sie auf das Symbol Plus (+) auf der Seite.
Gast erstellenErstellen Sie einen Gast mithilfe einer bestehenden Vorlage.
Geben Sie den Namen ein, mit dem der Gast gekennzeichnet wird.
Wählen Sie eine Vorlage aus.
Wenn Vorlagen vorhanden sind, wählen Sie eine aus den angezeigten Vorlagen aus.
Wenn keine Vorlagen vorhanden sind, klicken Sie auf Vorlage erstellen, um eine Vorlage zu erstellen.
Sie können Informationen zu einer Vorlage anzeigen, wenn Sie den Mauszeiger über das entsprechende Element bewegen.
Klicken Sie auf Erstellen.
Gast bearbeitenBearbeiten Sie die Eigenschaften eines vorhandenen Gastes. Einige Eigenschaften können nur bearbeitet werden, solange der Gast gestoppt ist. Andere Eigenschaften treten beim nächsten Booten in Kraft.
Allgemein
Zeigt Informationen zu Ihrem Gast (einschließlich Name, CPUs, Speicher) und ein Symbol an, das für Ihren Gast verwendet werden kann. Sie können den Namen eines gestoppten Gastes bearbeiten. Änderungen der CPUs und des Speichers werden nach dem nächsten Bootvorgang wirksam.
Speicher
Zeigt die Einheit und den Speicherpfad für den ausgewählten Gast an.
Sie können Speichereinheiten für Ihren Gast hinzufügen, bearbeiten und entfernen.
Schnittstelle
Zeigt Netzinformationen für den Gast (einschließlich Name, Typ und MAC-Adresse) an. Sie können Schnittstellen für Ihren Gast hinzufügen, bearbeiten und entfernen.
Berechtigung
Zeigt die Benutzer und Gruppen an, die über eine Berechtigung für den Gast verfügen.
PCI-Einheit für Host
Zeigt eine Liste aller PCI-Einheiten an, die auf dem Host verfügbar sind.
Snapshot
Zeigt Snapshots des Gastes an. Sie können einen Snapshot erstellen, bearbeiten oder löschen. Durch Auswahl eines Snapshots und der Option zum Zurücksetzen wird der Gast auf den zu einem bestimmten Zeitpunkt in der Vergangenheit bestehenden Status zurückgesetzt, der anhand der Snapshotdaten ermittelt wird. Alle Änderungen, die nach diesem Zeitpunkt durchgeführt wurden, werden verworfen.
Felder, die nicht inaktiviert sind, können bearbeitet werden. Nachdem Sie ein Feld bearbeitet haben, klicken Sie auf Speichern.
Gast klonenDurch das Klonen eines Gastes kann eine Kopie des Gastes erstellt werden.
Gehen Sie wie folgt vor, um einen Gast zu klonen:
Wählen Sie im Aktionsmenü eines Gastes Klonen aus.
Akzeptieren Sie die Warnung. Wenn ein Zielgast mit SCSI- oder iSCSI-Datenträgern arbeitet oder wenn der Zielpool nicht über genügend Speicherplatz verfügt, dann wird der Klon in einem Standardspeicherpool erstellt.
Ein Gast wird in Ihrer Liste mit der Bezeichnung Wird geklont... angezeigt. Nach Abschluss des Prozesses steht der geklonte Gast zur Benutzung zur Verfügung.
================================================
FILE: ui/pages/help/de_DE/network.dita
================================================
NetzDie Seite Netz zeigt Informationen zur Netzverbindung an.
Netzname
Name des Netzes oder Standard.
Status
Status des Netzes, aktiv (grün) oder inaktiv (rot).
Netztyp
Netztyp, zum Beispiel NAT (Network
Address Translation, Netzadressumsetzung).
Schnittstelle
Netzschnittstelle, zum Beispiel virbr0 (Standard).
Adressraum
IP-Adresse.
Die folgenden Aktionen können ausgewählt werden:
Wählen Sie Starten aus, um die Netzverbindung herzustellen.
Wählen Sie Stoppen aus, um die Netzverbindung zu beenden.
Wählen Sie Löschen aus, um die Verbindungsinformationen zu löschen.
Um ein Netz zu erstellen, klicken Sie auf das Symbol Plus (+).
Netz erstellenErstellen Sie ein Netz.
Geben Sie den Namen des Netzes ein.
Klicken Sie hier, um den Netztyp auszuwählen.
Isoliert
Isolierter Modus. Gäste können keine Kommunikation an externe Systeme senden oder von ihnen empfangen.
NAT
Network Address Translation-Modus. Bei der Kommunikation von Gästen mit externen Systemen wird die Host-IP-Adresse verwendet. Externe Systeme können keine Kommunikation mit Gästen initiieren.
Überbrückt
Überbrückt-Modus. Gäste können mit externen Systemen kommunizieren und von externen Systemen kontaktiert werden, als ob sie physische Systeme im Netz wären. Für den Überbrückt-Modus müssen Sie zusätzliche Ziel- und VLAN-Informationen angeben.
Klicken Sie auf Erstellen.
================================================
FILE: ui/pages/help/de_DE/storage.dita
================================================
SpeicherAuf der Seite Speicher werden die verfügbaren Speicherpools aufgelistet, einschließlich der sofort einsatzfähigen Speicherpools 'default' und 'ISO'. Wenn Sie ein eigenes ISO-Image verwenden möchten, fügen Sie es zum Speicherpoolpfad 'ISO' hinzu.
Für jeden Speicherpool werden die folgenden Informationen angezeigt:
Name
Name des Speicherpools.
% belegt
Prozentsatz des Speicherpools, der momentan belegt ist.
Status
Status des Speicherpools, aktiv (grün) oder inaktiv (rot).
Position
Dateipfad zur Position des Speicherpools.
Typ
Typ des Speicherpools, zum Beispiel dir.
Kapazität
Speicherkapazität im Speicherpool.
Zugeordnet
Speicherplatz, der bereits im Speicherpool zugeordnet ist.
Die folgenden Aktionen können für jeden Speicherpool ausgewählt werden:
Wählen Sie Aktivieren aus, um den Speicherpool zu aktivieren, damit er genutzt werden kann.
Wählen Sie Inaktivieren aus, um einen aktiven Speicherpool zu inaktivieren.
Wählen Sie Datenträger hinzufügen aus, um einem aktiven Speicherpool weitere Datenträger hinzuzufügen.
Wählen Sie Definition aufheben, um einen inaktiven Speicherpool zu entfernen.
Um Details zum Speicherdatenträger anzuzeigen, klicken Sie auf den Pfeil auf der rechten Seite der Speicherpoolzeile. Um einen Speicherpool zu definieren, klicken Sie auf das Symbol Plus (+).
Speicherpool definieren Definieren Sie einen Speicherpool.
Geben Sie im Feld Speicherpoolname den Namen ein, mit dem der Speicherpool gekennzeichnet werden soll.
Wählen Sie aus der Liste Speicherpooltyp den Typ aus:
DIR
Gibt einen Verzeichnispool an. Wenn Sie DIR auswählen, geben Sie den Speicherpfad ein (Dateipfad zum Speicherpool).
NFS
Gibt einen Netzdateisystempool an. Wenn Sie NFS auswählen,
geben Sie NFS-Server-IP und NFS-Pfad an (Pfad des exportierten Verzeichnisses).
iSCSI
Gibt einen Pool an, der auf einem Ziel basiert, der auf einem iSCSI-Server zugeordnet ist.
Wenn Sie iSCSI auswählen, geben Sie die IP-Adresse vom iSCSI-Server und das Ziel auf dem iSCSI-Server an. Sie können optional iSCSI-Authentifizierung hinzufügen.
Logisch
Gibt einen Speicherpool aus logischen Datenträgern an. Wählen Sie die Position zur Einheit im Einheitenpfad aus.
SCSI-Fibre Channel
Gibt einen Pool an, der auf einem SCSI-Fibre Channel basiert. Wählen Sie aus, welcher Adapter verwendet werden soll.
Geben Sie einen Speicherpfad für den Speicherpool an. Der Speicherpfad gibt die Position im lokalen Dateisystem an, der der Pool zugeordnet ist.
Der Pfad muss eindeutig sein. Wenn das Verzeichnis bei der Poolerstellung noch nicht vorhanden ist, dann wird es vom System für Sie erstellt.
Klicken Sie auf Erstellen.
Datenträger hinzufügenFügt einen Datenträger zu einem Speicherpool hinzu.
Über Remote URL abrufen
Gibt eine Position an, von der der Datenträger heruntergeladen werden soll. Beispiel: https://my-server/fedora22.img.
Datei hochladen
Gibt eine Position auf Ihrem lokalen System an.
================================================
FILE: ui/pages/help/de_DE/templates.dita
================================================
VorlagenDie Seite Vorlagen zeigt die definierten Vorlagen der virtuellen Maschine an, die zum Erstellen von KVM-Gästen verwendet werden können.
Für jede Vorlage werden die folgenden Informationen angezeigt:
BS
Name des Betriebssystems oder der Verteilung.
Version
Version des Betriebssystems oder der Verteilung.
CPUs
Anzahl der Prozessoren, die für die Vorlage definiert sind.
Speicher
Größe des zuzuordnenden Arbeitsspeichers in MB.
Die folgenden Aktionen können für jede Vorlage ausgewählt werden:
Wählen Sie Bearbeiten aus, um die Vorlage zu bearbeiten.
Wählen Sie Klonen aus, um eine Vorlage zu kopieren.
Wählen Sie Löschen aus, um die Vorlage zu löschen.
Um eine Vorlage hinzuzufügen, klicken Sie auf das Symbol Plus (+).
Vorlage bearbeitenBearbeiten Sie eine bestehende Vorlage.
Für jede Vorlage werden die folgenden Informationen angezeigt:
Allgemein
Zeigt den Namen, die Anbieterverteilung, die Version, den Speicher sowie den Dateipfad zur ISO-Datei und die Grafikvorgaben an.
Speicher
Geben Sie die Speicherpoolinformationen für die Vorlage an.
Schnittstelle
Zeigt die Standardnetzschnittstellen an, die für den KVM-Gast verfügbar sind.
Sie können mehrere Netze auswählen.
Prozessor
Geben Sie im Feld CPU-Anzahl die Anzahl der Prozessoren an, die für die Vorlage definiert sind.
Wählen Sie aus, dass die CPU-Topologie für jeden Gast manuell definiert werden soll.
Vorlage hinzufügenFügen Sie eine Vorlage vom Quellendatenträger hinzu. Sie können für eine nachfolgende Erkennung Ihr eigenes ISO-Image zum Speicherpool 'ISO' hinzufügen.
Wählen Sie die Position des Quellendatenträgers aus den folgenden Optionen aus:
Lokales ISO-Image
Wählen Sie diese Option aus, um Speicherpools nach Installations-ISO-Images zu durchsuchen, die im System verfügbar sind.
Lokale Imagedatei
Wählen Sie aus, dass ein Pfad zur lokalen Imagedatei angegeben werden soll.
Fernes ISO-Image
Wählen Sie diese Option aus, um eine ferne Position für ein Installations-ISO-Image anzugeben.
Vorlage hinzufügen - ISO-ImageFügen Sie eine Vorlage aus einem ISO-Image hinzu.
Die im System verfügbaren fernen ISO-Images werden angezeigt.
BS
Name des Betriebssystems oder der Verteilung.
Version
Version des Betriebssystems oder der Verteilung.
Größe
Größe des ISO-Image.
Um eine Vorlage aus einem ISO-Image zu erstellen, wählen Sie aus den folgenden
Optionen aus:
Wählen Sie ein ISO-Image aus, aus dem Sie eine Vorlage erstellen möchten, und klicken Sie dann auf Vorlagen aus ausgewähltem ISO erstellen.
Wählen Sie Alle aus, um eine Vorlage aus jedem aufgelisteten ISO-Image zu erstellen, und klicken Sie dann auf Vorlagen aus ausgewähltem ISO erstellen.
Wenn das ISO-Image, das Sie verwenden möchten, nicht in den Suchergebnissen angezeigt wird, können Sie aus den folgenden Optionen auswählen:
Wählen Sie Ich möchte eine bestimmte ISO-Datei verwenden aus, um einen Pfad zum ISO-Image anzugeben.
Klicken Sie auf Weitere ISOs suchen, um weitere ISO-Images zu suchen.
================================================
FILE: ui/pages/help/en_US/Makefile.am
================================================
# Copyright IBM Corp, 2014-2016
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
en_US_helpdir = $(datadir)/wok/plugins/kimchi/ui/pages/help/en_US
dist_en_US_help_DATA = $(wildcard *.html) $(NULL)
EXTRA_DIST = $(wildcard *.dita)
CLEANFILES = $(wildcard *.html)
================================================
FILE: ui/pages/help/en_US/guests.dita
================================================
GuestsThe Guests page lists the defined
guests for your server.
For each guest, the following information is displayed:
Name
Name of the guest.
CPU
Percentage of processor utilization in the guest.
Disk I/O
Disk input/output transmission rate in KB per seconds.
Network I/O
Network input/output transmission rate in KB per seconds.
Livetile
State of guest operating system console, or an icon that represents
the Linux distribution if the
guest is not active.
The following actions icons are displayed for each guest:
Reset
Click to reset the guest.
Power (Start or Stop)
Click to power on or power off the guest. If the icon is red,
the power is off; if the icon is green, the power is on.
The following actions can be selected for each guest:
Select Connect to connect to the remote
console for the guest operating system.
Select Clone to copy an existing guest
definition to create a guest.
Select Reset to reset the guest. You can
only reset a guest that is started.
Select Edit to edit the properties of an
existing guest. Guests can be edited only while stopped.
Select Start to start a guest
Select Shut Down to shut down a guest gracefully.
Select Power Off to force an immediate
shut down of the guest.
Select Delete to delete the guest.
To create a guest, click the plus (+) icon
on the page.
Create a guestCreate a guest by using an existing template.
Type the name to be used to identify the guest.
Select a template.
If templates exist, select from displayed templates.
If no templates exist, click Create a template to
create a template.
You can view information about a template by hovering over it.
Click Create.
Edit guestEdit the properties of an existing guest. Some properties
can be edited only while guest is stopped. Others will take effect
in next boot.
If guest is off: CPU and Memory new values
takes effect after next boot.
If guest is running: Guest must support
hotplug/hotunplug of CPU and Memory devices, otherwise changes in these fields will not take effect. For Power systems, the guest must have:
Latest versions of packages powerpc-utils, ppc64-diag and librtas
must be installed.
Service rtas_err must be running.
General
Displays information about your guest, including name, CPUs, memory,
and icon to use for your guest. You can edit the name of a stopped
guest. Changing the CPUs and memory takes effect after the next boot.
Storage
Displays the device and path for storage for the selected guest.
You can add, edit, and remove storage devices for your guest.
Interface
Displays network information for the guest, including name, type,
and MAC address. You can add, edit, and remove interfaces for your
guest.
Permission
Displays the users and groups that are authorized for the guest.
Host PCI Device
Displays a list of all PCI devices available on the host.
Snapshot
Displays snapshots of the guest. You can create, edit, or delete
a snapshot. By selecting a snapshot and selecting revert, the guest
is restored to a point in the past, determined by the snapshot data,
and discards any changes made beyond that point in time.
Fields that are not disabled can be edited. After you edit a field,
click Save.
Cloning a guestCloning a guests allows you to create a copy of a guest.
To clone a guest:
Select Clone from the Action menu of a
guest.
Accept the warning. When a target guest is using SCSI or
iSCSI volumes or if the target pool does not have enough space, the
clone will be created on a default storage pool.
A guest appears in your list with the label Cloning... When
the process is complete, the cloned guest is available to use.
================================================
FILE: ui/pages/help/en_US/network.dita
================================================
NetworkThe Network page displays information
about the network connection.
Network Name
Name of the network, or default.
State
State of the network, active (green) or inactive (red).
Network type
Network type, for example, NAT (network
address translation).
Interface
Network interface, for example, virbr0 (default).
Address space
IP address.
The following actions can be selected:
Select Start to begin the network
connection.
Select Stop to end the network connection.
Select Delete to delete the connection
information.
To create a network, click the plus (+) icon.
Create a networkCreate a network.
Type the name of the network.
Click to select the network type.
Isolated
Isolated mode. Guests cannot send or receive communication to
or from external systems.
NAT
Network Address Translation mode. Communication from guests to
external systems uses the host IP address. External systems cannot
initiate communication to guests.
Bridged
Bridged mode. Guests can communicate with external systems and
be contacted by external systems as if they were physical systems
on the network. For bridged mode, you must specify additional destination
and VLAN information.
Click Create.
================================================
FILE: ui/pages/help/en_US/storage.dita
================================================
StorageThe Storage page lists the available
storage pools, including the out of box 'default' and 'ISO' storage
pool. If you want to use your own ISO, please add it to 'ISO' storage
pool path.
For each storage pool, the following information is displayed:
Name
Name of the storage pool.
% Used
Percentage of the storage pool that is being used.
State
State of the storage pool, active (green) or inactive (red).
Location
File path to the location of the storage pool.
Type
Type of storage pool, for example, dir.
Capacity
Amount of space in the storage pool.
Allocated
Amount of space that is already allocated in the storage pool.
The following actions can be selected for each storage pool:
Select Activate to activate the storage
pool so that it can be used.
Select Deactivate to deactivate an active
storage pool.
Select Add Volume to add more volume to
an active storage pool.
Select Undefine to remove an inactive storage
pool.
To display storage volume details for a storage pool, click the
arrow on the right side of the storage pool row. To define a storage
pool, click the plus (+) icon.
Define a storage pool Define a storage pool.
In the Storage pool name field, type the
name to be used to identify the storage pool.
In the Storage pool type list, select the
type:
DIR
Specifies a directory pool. When selecting DIR,
type the Storage path (file path to the storage
pool).
NFS
Specifies a network filesystem pool. When selecting NFS,
type the NFS server IP address and NFS
path (path of the exported directory).
iSCSI
Specifies a pool based on a target allocated on an iSCSI server.
When selecting iSCSI, type the iSCSI
server IP address and Target on
the iSCSI server. You can optionally select to add iSCSI authentication.
Logical
Specifies a logical volume storage pool. Select the location to
the device in Device path.
SCSI Fibre Channel
Specifies a pool based on an SCSI Fibre Channel. Select which
SCSI adapter to use.
Specify a storage path for the storage pool. The storage path
is the location in the local file system that the pool is mapped to.
The path must be unique. If the directory does not exist when the
pool is created, it will be created for you.
Click Create.
Add volumeAdds volume to a storage pool.
Fetch from remote URL
Specifies a location to download the volume from. For example: https://my-server/fedora22.img.
Upload a file
Specifies a location on your local system.
================================================
FILE: ui/pages/help/en_US/templates.dita
================================================
TemplatesThe Templates page shows the defined
virtual machine templates that can be used to create KVM guests.
For each template, the following information is displayed:
OS
Name of the operating system or distribution.
Version
Version of the operating system or distribution.
CPUs
Number of processors that are defined for the template.
Memory
Amount of random access memory to be allocated, in MB.
The following actions can be selected for each template:
Select Edit to edit the template.
Select Clone to copy a template.
Select Delete to delete the template.
To add a template, click the plus (+) icon.
Edit templateEdit an existing template.
For each template, the following information is displayed:
General
Displays the name, vendor distribution, version, memory, file
path to ISO file, and graphics preferences.
Storage
Specify the storage pool information for the template.
Interface
Displays the default network interfaces available to the KVM guest.
You can select multiple networks.
Processor
In the CPU Number field, specify the number
of processors that are defined for the template.
Select to Manually set CPU topology for each guest.
Add templateAdd a template from source media. You can add your own
ISO image to 'ISO' storage pool for following discovery.
Select the location of the source media from the following options:
Local ISO image
Select to scan storage pools for installation ISO images available
on the system.
Local Image File
Select to specify a path to the local image file.
Remote ISO image
Select to specify a remote location for an installation ISO image.
Add template - ISO imageAdd a template from a ISO image.
The ISO images available on the system are remotely are displayed.
OS
Name of the operating system or distribution.
Version
Version of the operating system or distribution.
Size
Size of the ISO image.
To create a template from an ISO image, choose from the following
options:
Select an ISO image from which to create a template, then click Create
Templates from Selected ISO.
Select All to create a template from each
listed ISO image, then click Create Templates from Selected
ISO.
If the ISO image that you want to use does not appear in the scan
results, you can select from the following options:
Select I want to use a specific ISO file to
specify a path to the ISO image.
Click Search more ISOs to search for more
ISO images.
================================================
FILE: ui/pages/help/es_ES/Makefile.am
================================================
# Copyright IBM Corp, 2014-2016
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
es_ES_helpdir = $(datadir)/wok/plugins/kimchi/ui/pages/help/es_ES
dist_es_ES_help_DATA = $(wildcard *.html) $(NULL)
EXTRA_DIST = $(wildcard *.dita)
CLEANFILES = $(wildcard *.html)
================================================
FILE: ui/pages/help/es_ES/guests.dita
================================================
InvitadosEn la página Invitados se listan los invitados definidos para su servidor.
Se visualiza la siguiente información para cada invitado:
Nombre
Nombre del invitado.
CPU
Porcentaje de utilización del procesador en el invitado.
E/S de disco
Velocidad de transmisión de entrada/salida de disco en KB por segundos.
E/S de red
Velocidad de transmisión de entrada/salida de red en KB por segundos.
Livetile
Estado de la consola del sistema operativo invitado, o un icono que representa la distribución de Linux si el invitado no está activo.
Se visualizan los siguientes iconos de acciones para cada invitado:
Restablecer
Pulse aquí para restablecer el invitado.
Alimentación (Iniciar o Detener)
Pulse aquí para encender o apagar el invitado. Si el icono es de color rojo, la alimentación está apagada; si el icono es de color verde, la alimentación está encendida.
Se pueden seleccionar las siguientes acciones para cada invitado:
Seleccione Conectar para conectarse a la consola remota para el sistema operativo invitado.
Seleccione Clonar para copiar una definición de invitado existente con el fin de crear un invitado.
Seleccione Restablecer para restablecer el invitado. Solamente puede restablecer un invitado que se haya iniciado.
Seleccione Editar para editar las propiedades de un invitado existente. Los invitados sólo pueden editarse mientras están detenidos.
Seleccione Iniciar para iniciar un invitado
Seleccione Concluir para concluir un invitado con elegancia.
Seleccione Apagar para forzar una conclusión inmediata del invitado.
Seleccione Suprimir para suprimir el invitado.
Para crear un invitado, pulse el icono más (+) en la página.
Creación de un invitadoCree un invitado utilizando una plantilla existente.
Escriba el nombre que se va a utilizar para identificar al invitado.
Seleccione una plantilla.
Si existen plantillas, seleccione entre las plantillas mostradas.
Si no existen plantillas, pulse Crear una plantilla para crear una plantilla.
Puede ver información sobre una plantilla pasando el cursor por encima.
Pulse Crear.
Editar invitadoEdite las propiedades de un invitado existente. Algunas propiedades pueden editarse sólo cuando el invitado se ha detenido. Otras surtirán efecto en el arranque siguiente.
General
Muestra información sobre el invitado, incluyendo el nombre, las CPU, la memoria y el icono para utilizarlo con su invitado. Puede editar el nombre de un invitado detenido. El cambio de CPU y de memoria entra en vigor tras el siguiente arranque.
Almacenamiento
Muestra el dispositivo y la vía de acceso para el almacenamiento del invitado seleccionado.
Puede añadir, editar y eliminar dispositivos de almacenamiento para su invitado.
Interfaz
Muestra información de red del invitado, incluyendo el nombre, el tipo y la dirección MAC. Puede añadir, editar y eliminar interfaces para su invitado.
Permiso
Muestra los usuarios y grupos que están autorizados para el invitado.
Dispositivo PCI de host
Muestra una lista de todos los dispositivos PCI disponibles en el host.
Instantánea
Muestra las instantáneas del invitado. Puede crear, editar o suprimir una instantánea. Al seleccionar una instantánea y seleccionar revertir, se restaura el invitado en un punto del pasado, que viene determinado por los datos de la instantánea y se descartan los cambios realizados pasado ese punto del tiempo.
Los campos que no están inhabilitados pueden editarse. Después de editar un campo, pulse Guardar.
Clonación de un invitado La clonación de un invitado le permite crear una copia de un invitado.
Para clonar un invitado:
Seleccione Clonar del menú Acción de un invitado.
Acepte el aviso. Cuando un invitado de destino está utilizando volúmenes SCSI o iSCSI o si la agrupación de destino no tiene suficiente espacio, el clon se creará en una agrupación de almacenamiento predeterminada.
Un invitado aparece en su lista con la etiqueta Clonando... Cuando el proceso se ha completado, el invitado clonado está disponible para utilizarlo.
================================================
FILE: ui/pages/help/es_ES/network.dita
================================================
RedLa página Red muestra información sobre la conexión de red.
Nombre de red
Nombre de la red, o predeterminado.
Estado
Estado de la red, activa (verde) o inactiva (rojo).
Tipo de red
Tipo de red, por ejemplo, NAT (conversión de direcciones de red).
Interfaz
La interfaz de red, por ejemplo, virbr0 (predeterminada).
Espacio de direcciones
Dirección IP.
Se pueden seleccionar las siguientes acciones:
Seleccione Iniciar para iniciar la conexión de red.
Seleccione Detener para finalizar la conexión de red.
Seleccione Suprimir para suprimir la información de conexión.
Para crear una red, pulse el icono más (+).
Crear una redCrear una red.
Escriba el nombre de la red.
Pulse para seleccionar el tipo de red.
Aislada
Modalidad aislada. Los invitados no pueden enviar ni recibir comunicación a sistemas externos o desde ellos.
NAT
Modalidad de Conversión de direcciones de red. La comunicación de invitados a sistemas externos utiliza la dirección IP del host. Los sistemas externos no pueden iniciar la comunicación con los invitados.
Puenteada
Modalidad puenteada. Los invitados pueden comunicarse con sistemas externos y ser contactados por sistemas externos como si fueran sistemas físicos en la red. Para la modalidad puenteada, debe especificar información de destino y VLAN adicional.
Pulse Crear.
================================================
FILE: ui/pages/help/es_ES/storage.dita
================================================
AlmacenamientoLa página Almacenamiento lista las agrupaciones de almacenamiento disponibles, incluyendo la agrupación de almacenamiento predefinida 'default' e 'ISO'.
Si desea utilizar su propia ISO, añádala a la vía de acceso de la agrupación de almacenamiento 'ISO'.
Se visualiza la siguiente información para cada agrupación de almacenamiento:
Nombre
El nombre de la agrupación de almacenamiento.
% utilizado
Porcentaje de la agrupación de almacenamiento que se está utilizando.
Estado
Estado de la agrupación de almacenamiento, activa (verde) o inactiva (rojo).
Ubicación
Vía de acceso de archivo a la ubicación de la agrupación de almacenamiento.
Tipo
Tipo de agrupación de almacenamiento, por ejemplo, dir.
Capacidad
Cantidad de espacio en la agrupación de almacenamiento.
Asignado
Cantidad de espacio que ya está asignado en la agrupación de almacenamiento.
Se pueden seleccionar las siguientes acciones para cada agrupación de almacenamiento:
Seleccione Activar para activar la agrupación de almacenamiento para que pueda utilizarse.
Seleccione Desactivar para desactivar una agrupación de almacenamiento activa.
Seleccione Añadir volumen para añadir más volumen a una agrupación de almacenamiento activa.
Seleccione No definir para eliminar una agrupación de almacenamiento inactiva.
Para visualizar detalles de volumen de almacenamiento para una agrupación de almacenamiento, pulse la flecha situada en el lado derecho de la fila de agrupación de almacenamiento. Para definir una agrupación de almacenamiento, pulse el icono más (+).
Definir una agrupación de almacenamiento Definir una agrupación de almacenamiento.
En el campo Nombre de agrupación de almacenamiento, escriba el nombre que se utilizará para identificar la agrupación de almacenamiento.
En la lista Tipo de agrupación almacenamiento, seleccione el tipo:
DIR
Especifica una agrupación de directorio. Al seleccionar DIR, escriba la Vía de acceso de almacenamiento (vía de acceso de archivo a la agrupación de almacenamiento).
NFS
Especifica una agrupación de sistema de archivos de red. Al seleccionar NFS, escriba la dirección IP de servidor NFS y vía de acceso de NFS (vía de acceso del directorio exportado).
iSCSI
Especifica una agrupación basada en un destino asignado en un servidor iSCSI.
Al seleccionar iSCSI, escriba la dirección IP del Servidor iSCSI y el Destino en el servidor iSCSI. Opcionalmente puede seleccionar añadir autenticación iSCSI.
Lógico
Especifica una agrupación de almacenamiento de volumen lógico. Seleccione la ubicación al dispositivo en Vía de acceso de dispositivo.
Canal de fibra de SCSI
Especifica una agrupación basada en un Canal de fibra SCSI. Seleccione qué adaptador SCSI se utilizará.
Especifique una vía de acceso de almacenamiento para la agrupación de almacenamiento. La vía de acceso de almacenamiento es la ubicación en el sistema de archivos local al que se correlaciona la agrupación.
La vía de acceso debe ser exclusiva. Si el directorio no existe cuando se crea la agrupación, se creará para el usuario.
Pulse Crear.
Añadir volumenAñade volumen a una agrupación de almacenamiento.
Captar de URL remoto
Especifica una ubicación de donde descargar el volumen. Por ejemplo: https://my-server/fedora22.img.
Cargar un archivo
Especifica una ubicación en su sistema local.
================================================
FILE: ui/pages/help/es_ES/templates.dita
================================================
PlantillasLa página Plantillas muestra las plantillas de máquina virtual definidas que se pueden utilizar para crear invitados KVM.
Se visualiza la siguiente información para cada plantilla:
SO
Nombre del sistema operativo o distribución.
Versión
Versión del sistema operativo o distribución.
CPUs
Número de procesadores que están definidos para la plantilla.
Memoria
Cantidad de memoria de acceso aleatorio a asignar, en MB.
Se pueden seleccionar las siguientes acciones para cada plantilla:
Seleccione Editar para editar la plantilla.
Seleccione Clonar para copiar una plantilla.
Seleccione Suprimir para suprimir la plantilla.
Para añadir una plantilla, pulse el icono más (+).
Editar plantillaEditar una plantilla existente.
Se visualiza la siguiente información para cada plantilla:
General
Muestra el nombre, la distribución de proveedor, la versión, la memoria, la vía de acceso del archivo al archivo ISO y las preferencias de gráficos.
Almacenamiento
Especifica información de la agrupación de almacenamiento para la plantilla.
Interfaz
Muestra las interfaces de red predeterminadas que hay disponibles para el invitado KVM.
Puede seleccionar varias redes.
Procesador
En el campo Número de CPU, especifique el número de procesadores que se han definido para la plantilla.
Seleccione Establecer manualmente la topología de la CPU para cada invitado.
Añadir plantillaAñadir una plantilla desde el soporte de origen. Puede añadir su propia imagen ISO a la agrupación de almacenamiento 'ISO' para el siguiente descubrimiento.
Seleccione la ubicación del soporte de origen entre una de las opciones siguientes:
Imagen ISO local
Seleccione esta opción para explorar las agrupaciones de almacenamiento en busca de imágenes ISO de instalación disponibles en el sistema.
Archivo de imagen local
Seleccione esta opción para especificar una vía de acceso al archivo de imagen local.
Imagen ISO remota
Seleccione esta opción para especificar una ubicación remota para una imagen ISO de instalación.
Añadir plantilla - imagen ISOAñade una plantilla desde una imagen ISO.
Las imágenes ISO disponibles en el sistema se visualizan de forma remota.
SO
Nombre del sistema operativo o distribución.
Versión
Versión del sistema operativo o distribución.
Tamaño
Tamaño de la imagen ISO.
Para crear una plantilla a partir de una imagen ISO, elija entre las opciones siguientes:
Seleccione una imagen ISO desde la que desea crear una plantilla y, a continuación, pulse Crear plantillas desde ISO seleccionada.
Seleccione Todo para crear una plantilla desde cada imagen ISO en la lista y, a continuación, pulse Crear plantillas desde ISO seleccionada.
Si la imagen ISO que desea utilizar no aparece en los resultados de la exploración, puede seleccionar entre las opciones siguientes:
Seleccione Deseo utilizar un archivo ISO específico para especificar una vía de acceso a la imagen ISO.
Pulse Buscar más ISO para buscar más imágenes ISO.
================================================
FILE: ui/pages/help/fr_FR/Makefile.am
================================================
# Copyright IBM Corp, 2014-2016
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
fr_FR_helpdir = $(datadir)/wok/plugins/kimchi/ui/pages/help/fr_FR
dist_fr_FR_help_DATA = $(wildcard *.html) $(NULL)
EXTRA_DIST = $(wildcard *.dita)
CLEANFILES = $(wildcard *.html)
================================================
FILE: ui/pages/help/fr_FR/guests.dita
================================================
InvitésLa page Invités répertorie les invités définis pour le serveur.
Pour chaque invité, les informations suivantes sont affichées :
Nom
Nom de l'invité.
UC
Pourcentage d'utilisation du processeur sur l'invité.
E-S disque
Vitesse de transmission d'entrée-sortie du disque, exprimée en ko par seconde.
E-S réseau
Vitesse de transmission d'entrée-sortie du réseau, exprimée en ko par seconde.
Livetile
Etat de la console du système d'exploitation de l'hôte, ou
icône représentant la distribution Linux
si l'invité n'est pas actif.
Les icônes d'action suivantes sont affichées pour chaque invité :
Réinitialiser
Cliquez pour réinitialiser l'invité.
Alimentation (Démarrer ou Arrêter)
Cliquez pour mettre sous ou hors tension l'invité. Si l'icône est rouge,
l'alimentation est démarrée ; si l'icône est verte, l'alimentation est arrêtée.
Les actions suivantes peuvent être sélectionnées pour chaque invité :
Sélectionnez Connexion pour vous connecter à la console
distante du système d'exploitation invité.
Sélectionnez Cloner pour copier une définition d'invité existante afin de créer un invité.
Sélectionnez Réinitialiser pour réinitialiser l'invité. Seul un hôte démarré peut être réinitialisé.
Sélectionnez Editer pour éditer les propriétés d'un invité existant. Les invités peuvent être édités uniquement lorsqu'ils sont à l'arrêt.
Sélectionnez Démarrer pour démarrer un invité
Sélectionnez Arrêter pour arrêter un invité.
Sélectionnez Mettre hors tension pour forcer un arrêt immédiat de l'invité.
Sélectionnez Supprimer pour supprimer l'invité.
Pour créer un invité, cliquez sur l'icône plus (+) sur la page.
Créer un invitéCréation d'un invité à l'aide d'un modèle existant.
Entrez le nom à utiliser pour identifier l'invité.
Sélectionnez un modèle.
Si des modèles existent, faites un choix parmi les modèles affichés.
Si aucun modèle n'existe, cliquez sur Créer un modèle pour créer un modèle.
Vous pouvez afficher des informations sur un modèle en le survolant avec la souris.
Cliquez sur Créer.
Editer l'invitéEdition des propriétés d'un invité existant. Certaines propriétés
peuvent être éditées uniquement lorsque l'invité est arrêté. D'autres seront appliquées à l'amorçage suivant.
Général
Affiche des informations sur l'invité, parmi lesquelles le nom, les UC, la mémoire et l'icône à utiliser pour l'invité. Vous pouvez modifier le nom d'un invité arrêté. La modification des UC et de la mémoire prend effet à l'amorçage suivant.
Stockage
Affiche l'unité et le chemin pour le stockage de l'invité sélectionné.
Vous pouvez ajouter, modifier et supprimer les unités de stockage de l'invité.
Interface
Affiche les informations de réseau pour l'invité, parmi lesquelles le nom, le type et l'adresse MAC. Vous pouvez ajouter, modifier et supprimer les interfaces de l'invité.
Droits
Affiche les utilisateurs et les groupes autorisés pour l'invité.
Unité PCI hôte
Affiche une liste de toutes les unités PCI disponibles sur l'hôte.
Image instantanée
Affiche les images instantanées de l'invité. Vous pouvez créer, modifier ou supprimer une image instantanée. En sélectionnant une image instantanée et en choisissant l'option de rétablissement, l'invité est restauré à un point dans le passé, déterminé par les données d'image instantanée et annule les modifications apportées au-delà de ce point dans le temps.
Les zones qui ne sont pas désactivées peuvent être éditées. Après que vous avez édité une zone, cliquez sur Sauvegarder.
Clonage d'un invitéLe clonage d'un invité permet de créer une copie d'un invité.
Pour cloner un invité :
Sélectionnez Cloner dans le menu Action d'un invité.
Acceptez l'avertissement. Lorsqu'un invité cible utilise des volumes SCSI ou iSCSI ou si le pool cible ne dispose pas de suffisamment d'espace, le clone est créé dans un pool de stockage par défaut.
Un invité apparaît dans la liste avec le libellé Clonage en cours... Une fois le processus terminé, l'invité cloné est disponible.
================================================
FILE: ui/pages/help/fr_FR/network.dita
================================================
RéseauLa page Réseau affiche des informations sur la connexion réseau.
Nom du réseau
Nom du réseau, ou par défaut.
Etat
Etat du réseau, actif (vert) ou inactif (rouge).
Type de réseau
Type du réseau, par exemple NAT (conversion d'adresses réseau).
Interface
Interface réseau, par exemple virbr0 (par défaut).
Espace adresse
Adresse IP.
Les actions suivantes peuvent être sélectionnées :
Sélectionnez Démarrer pour démarrer la connexion au réseau.
Sélectionnez Arrêter pour mettre fin à la connexion au réseau.
Sélectionnez Supprimer pour supprimer les informations de connexion.
Pour créer un réseau, cliquez sur l'icône plus (+).
Créer un réseauCréez un réseau.
Entrez le nom du réseau.
Cliquez pour sélectionner le type de réseau.
Isolé
Mode isolé. Les invités ne peuvent pas envoyer ni recevoir de communication avec des systèmes externes.
NAT
Mode de conversion d'adresses réseau. La communication à partir d'invités
vers des systèmes externes utilise l'adresse IP hôte. Les systèmes externes ne
peuvent pas initier de communication vers les invités.
Routé
Mode routé. Les invités peuvent communiquer avec des systèmes externes et
être contactés par des systèmes externes comme s'il s'agissait de systèmes physiques
sur le réseau. Pour le mode routé, vous devez spécifier des informations supplémentaires
sur la destination et le réseau local virtuel.
Cliquez sur Créer.
================================================
FILE: ui/pages/help/fr_FR/storage.dita
================================================
StockageLa page Stockage répertorie les pools de stockage disponibles,
y compris les pools de stockage 'default' et 'ISO' prêts à l'emploi. Si vous souhaitez utiliser votre propre pool de stockage ISO, ajoutez-le dans le chemin du pool de stockage 'ISO'.
Pour chaque pool de stockage, les informations suivantes sont affichées :
Nom
Nom du pool de stockage.
% utilisé
Pourcentage du pool de stockage utilisé.
Etat
Etat du pool de stockage, actif (vert) ou inactif (rouge).
Emplacement
chemin d'accès au fichier pour l'emplacement du pool de stockage.
Type
Type de pool de stockage, par exemple dir.
Capacité
Quantité d'espace dans le pool de stockage.
Alloué
Quantité d'espace déjà allouée dans le pool de stockage.
Les actions suivantes peuvent être sélectionnées pour chaque pool de stockage :
Sélectionnez Activer pour activer le pool de stockage pour utilisation.
Sélectionnez Désactiver pour désactiver un pool de stockage actif.
Sélectionnez Ajouter un volume pour ajouter un volume supplémentaire à un pool de stockage actif.
Sélectionnez Annuler définition pour retirer un pool de stockage inactif.
Pour afficher les détails de volume de stockage pour un pool de stockage, cliquez sur la
flèche située à droite de la ligne du pool de stockage. Pour définir un pool de stockage, cliquez sur l'icône plus (+).
Définir un pool de stockage Définissez un pool de stockage.
Dans la zone Nom du pool de stockage, entrez le nom à utiliser pour identifier le pool de stockage.
Dans la zone Type de pool de stockage, sélectionnez le type :
DIR
Indique un pool de répertoires. Lorsque vous sélectionnez DIR,
indiquez le Chemin de stockage (chemin d'accès au fichier
du pool de stockage).
NFS
indique un pool de systèmes de fichiers réseau. Lorsque vous sélectionnez NFS,
indiquez l'adresse IP du serveur NFS et le Chemin NFS (chemin d'accès au répertoire d'exportation).
iSCSI
Indique un pool basé sur une cible allouée sur un serveur iSCSI.
Lorsque vous sélectionnez iSCSI, indiquez l'adresse IP du Serveur iSCSI
et la Cible sur le serveur iSCSI. Vous avez la possibilité d'ajouter l'authentification iSCSI.
Logique
Indique un pool de stockage de volumes logiques. Sélectionnez l'emplacement de l'unité dans Chemin d'unité.
Fibre Channel SCSI
Indique un pool basée sur une connexion Fibre Channel SCSI. Sélectionnez l'adaptateur SCSI à utiliser.
Indiquez un chemin de stockage pour le pool de stockage. Le chemin de stockage est l'emplacement sur le système de fichiers local vers lequel le pool est mappé.
Le chemin doit être unique. Si le répertoire n'existe pas lorsque le pool est créé, il est créé.
Cliquez sur Créer.
Ajouter un volumeAjoute un volume à un pool de stockage.
Extraire de l'URL distante
Indiquez l'emplacement à partir duquel le volume est téléchargé. Exemple : https://my-server/fedora22.img.
Télécharger un fichier
Indique un emplacement sur le système local.
================================================
FILE: ui/pages/help/fr_FR/templates.dita
================================================
ModèlesLa page Modèles affiche les modèles de machine virtuelle définis
pouvant être utilisés pour créer des hôtes KVM.
Pour chaque modèle, les informations suivantes sont affichées :
SE
Nom du système d'exploitation ou de la distribution.
Version
Version du système d'exploitation ou de la distribution.
UC
Nombre de processeurs définis pour le modèle.
Mémoire
Quantité de mémoire vive à allouer, en Mo.
Les actions suivantes peuvent être sélectionnées pour chaque modèle :
Sélectionnez Editer pour éditer le modèle.
Sélectionnez Cloner pour copier un modèle.
Sélectionnez Supprimer pour supprimer le modèle.
Pour ajouter un modèle, cliquez sur l'icône plus (+).
Editer un modèleModifie un modèle existant.
Pour chaque modèle, les informations suivantes sont affichées :
Général
Affiche le nom, la distribution de fournisseur, la version, la mémoire, le chemin d'accès au fichier ISO et les préférences graphiques.
Stockage
Indique les informations de pool de stockage pour le modèle.
Interface
Affiche les interfaces réseau par défaut disponibles pour l'invité KVM.
Vous pouvez
sélectionner plusieurs réseaux.
Processeur
Dans la zone Nombre d'UC, indiquez le nombre de processus définis pour le modèle.
Choisissez de définir manuellement la topologie d'UC pour chaque invité.
Ajouter un modèleAjoute un modèle à partir du support source. Vous pouvez ajouter votre propre image ISO au pool de stockage 'ISO' pour la reconnaissance suivante.
Sélectionnez l'emplacement du support source à partir des options suivantes :
Image ISO locale
Sélectionnez cette option pour rechercher dans les pools de stockage l'image d'installation ISO disponible sur le système.
Fichier image local
Choisissez de sélectionner un chemin d'accès au fichier image local.
Image ISO distante
Sélectionnez cette option pour indiquer un emplacement distant pour une image d'installation ISO.
Ajouter un modèle - image ISOAjoute un modèle à partir d'une image ISO.
Les images ISO disponibles sur le système s'affichent à distance.
SE
Nom du système d'exploitation ou de la distribution.
Version
Version du système d'exploitation ou de la distribution.
Taille
Taille de l'image ISO.
Pour créer un modèle à partir d'une image ISO, choisissez parmi les options suivantes :
Sélectionnez une image ISO à partir de laquelle créer un modèle, puis cliquez sur Créer des modèles à partir de l'ISO sélectionné .
Sélectionnez Tout pour créer un modèle à partir de chaque
image ISO répertoriée, puis cliquez sur Créer des modèles à partir de l'ISO sélectionné.
Si l'image ISO que vous souhaitez utiliser ne figure pas dans les résultats
d'analyse, vous pouvez faire un choix parmi les options suivantes :
Sélectionnez Je souhaite utiliser un fichier ISO spécifique pour
spécifier un chemin d'accès à l'image ISO.
Cliquez sur Rechercher d'autres images ISO pour rechercher des images ISO supplémentaires.
================================================
FILE: ui/pages/help/it_IT/Makefile.am
================================================
# Copyright IBM Corp, 2014-2016
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
it_IT_helpdir = $(datadir)/wok/plugins/kimchi/ui/pages/help/it_IT
dist_it_IT_help_DATA = $(wildcard *.html) $(NULL)
EXTRA_DIST = $(wildcard *.dita)
CLEANFILES = $(wildcard *.html)
================================================
FILE: ui/pages/help/it_IT/guests.dita
================================================
GuestLa pagina Guest elenca le macchine guest
definite per il server.
Per ciascuna macchina guest vengono visualizzate le seguenti informazioni:
Nome
Il nome della macchina guest.
CPU
La percentuale di utilizzo del processore nella macchina guest.
I/O disco
La velocità di trasmissione dell'input/output disco in KB al secondo.
I/O di rete
La velocità di trasmissione dell'input/output di rete in KB al secondo.
Riquadro animato
Lo stato della console del sistema operativo della macchina guest o un'icona che rappresenta la distribuzione Linux se la macchina guest non è attiva.
Per ciascuna macchina guest vengono visualizzate le icone di azioni indicate di seguito:
Reimposta
Fare clic qui per reimpostare la macchina guest.
Alimentazione (Avvia o Arresta)
Fare clic qui per accendere o spegnere la macchina guest. Se l'icona è rossa, la macchina è spenta, se è verde è accesa.
Per ciascuna macchina guest è possibile selezionare le azioni indicate di seguito:
Selezionare Connetti per effettuare la connessione alla console remota per il sistema operativo della macchina guest.
Selezionare Clona per copiare una definizione di macchina guest esistente e creare una macchina guest.
Selezionare Reimposta per reimpostare la macchina guest. È possibile reimpostare solo una macchina guest che è stata avviata.
Selezionare Modifica per modificare le proprietà di una macchina guest esistente. È possibile modificare le macchine guest solo se sono arrestate.
Selezionare Avvia per avviare una macchina guest.
Selezionare Arresta per arrestare una macchina guest con il periodo di grazia.
Selezionare Spegni per forzare un arresto immediato della macchina guest.
Selezionare Elimina per eliminare la macchina guest.
Per creare una macchina guest fare clic sull'icona più
(+) sulla pagina.
Creare una macchina guestCreare una macchina guest utilizzando un modello esistente.
Immettere il nome da utilizzare per identificare la macchina guest.
Selezionare un modello.
Se il modello esiste, selezionarlo dai modelli visualizzati.
Se non esiste alcun modello, fare clic su Crea un modello per crearne uno.
È possibile visualizzare le informazioni su un modello passando con il cursore del mouse su esso.
Fare clic su Crea.
Modifica macchina guestModificare le proprietà di una macchina guest esistente. Alcune proprietà possono essere
modificate solo mentre la macchina guest è arrestata. Altre diventeranno effettive al prossimo avvio.
Generale
Visualizza informazioni sulla macchina guest, incluso il nome, le CPU, la memoria e l'icona per utilizzare la macchina guest. È possibile modificare il nome di una macchina guest arrestata. La modifica delle CPU e della memoria ha effetto al successivo avvio.
Memoria
Visualizza il dispositivo e il percorso per la memoria della macchina guest selezionata.
È possibile aggiungere, modificare e rimuovere i dispositivi di memoria per la macchina guest.
Interfaccia
Visualizza le informazioni di rete per la macchina guest, incluso il nome, il tipo e l'indirizzo MAC. È possibile aggiungere, modificare e rimuovere le interfacce per la macchina guest.
Autorizzazione
Visualizza gli utenti e i gruppi autorizzati per la macchina guest.
Dispositivo PCI host
Visualizza un elenco di tutti i dispositivi PCI disponibili sull'host.
Istantanea
Visualizza le istantanee della macchina guest. È possibile creare, modificare o eliminare un'istantanea. Selezionando un'istantanea e scegliendo l'opzione Inverti, la macchina guest viene ripristinata a un punto nel passato, determinato dai dati dell'istantanea, ed elimina le modifiche effettuate dopo tale punto nel tempo.
I campi non disabilitati possono essere modificati. Dopo aver modificato un campo, fare clic su Salva.
Clonazione di una macchina guestLa clonazione di una macchina guest consente all'utente di creare una copia di una macchina guest.
Per clonare una macchina guest:
Selezionare Clona dal menu Azione di una macchina guest.
Accettare l'avvertenza. Se una macchina guest di destinazione utilizza volumi SCSI o iSCSI o se un pool di destinazione non dispone di spazio sufficiente, il clone verrà creato su un pool di memoria predefinito.
Una macchina guest viene visualizzata nell'elenco con l'etichetta Clonazione.... Quando il processo è completo, la macchina guest clonata è disponibile per l'uso.
================================================
FILE: ui/pages/help/it_IT/network.dita
================================================
ReteLa pagina Rete visualizza le informazioni sulla connessione di rete.
Nome rete
Il nome della rete o il valore predefinito.
Stato
Lo stato della rete, attivo (verde) o non attivo (rosso).
Tipo di rete
I tipo di rete, ad esempio, NAT (network
address translation).
Interfaccia
L'interfaccia di rete, ad esempio, virbr0 (valore predefinito).
Spazio indirizzo
L'indirizzo IP.
È possibile selezionare le seguenti azioni:
Selezionare Avvia per iniziare la connessione di rete.
Selezionare Arresta per terminare la connessione di rete.
Selezionare Elimina per eliminare le informazioni di connessione.
Per creare una rete fare clic sull'icona più
(+).
Crea una reteCreare una rete.
Immettere il nome della rete.
Fare clic per selezionare il tipo di rete.
Isolata
La modalità isolata. Le macchine guest non possono inviare o ricevere comunicazioni verso o da i sistemi esterni.
NAT
La modalità NAT (Network Address Translation). La comunicazione dalle macchine guest ai sistemi esterni utilizza l'indirizzo IP host. I sistemi esterni non possono iniziare la comunicazione con le macchine guest.
Con bridge
La modalità con bridge. Le macchine guest possono comunicare con i sistemi esterni ed essere contattate dai sistemi esterni come se fossero sistemi fisici sulla rete. Per la modalità con bridge, è necessario specificare informazioni aggiuntive su destinazione e VLAN.
Fare clic su Crea.
================================================
FILE: ui/pages/help/it_IT/storage.dita
================================================
MemoriaLa pagina Memoria elenca i pool di memoria
disponibili, compresi i pool di memoria pronti per l'uso 'default' e 'ISO'. Se si desidera utilizzare un proprio ISO, aggiungerlo al percorso del pool di memoria 'ISO'.
Per ciascun pool di memoria vengono visualizzate le seguenti informazioni:
Nome
Il nome del pool di memoria.
% utilizzata
La percentuale del pool di memoria utilizzata.
Stato
Lo stato del pool di memoria, attivo (verde) o non attivo (rosso).
Ubicazione
Il percorso file all'ubicazione del pool di memoria.
Tipo
Il tipo di pool di memoria, ad esempio, dir.
Capacità
La quantità di spazio nel pool di memoria.
Assegnato
La quantità di spazio già assegnato nel pool di memoria.
Per ciascun pool di memoria è possibile selezionare le azioni indicate di seguito:
Selezionare Attiva per attivare il pool di memoria in modo da poterlo utilizzare.
Selezionare Disattiva per disattivare un pool di memoria attivo.
Selezionare Aggiungi volume per aggiungere altri volumi a un pool di memoria attivo.
Selezionare Rimuovi definizione per rimuovere un pool di memoria non attivo.
Per visualizzare i dettagli del volume di memoria per un pool di memoria, fare clic sulla freccia sul lato destro della riga del pool di memoria. Per definire un pool di memoria fare clic sull'icona più
(+).
Definire un pool di memoria Definire un pool di memoria.
Nel campo Nome pool di memoria, immettere i l nome da utilizzare per definire il pool di memoria.
Nell'elenco Tipo pool di memoria, selezionare il tipo:
DIR
Specifica un pool directory. Quando si seleziona DIR,
immettere il Percorso di memoria (percorso file al pool di memoria).
NFS
Specifica un pool NFS (Network File System). Quando si seleziona NFS,
immettere l'indirizzo IP del server NFS e il Percorso NFS (percorso alla directory esportata).
iSCSI
Specifica un pool basato su una destinazione assegnata su un server iSCSI.
Quando si seleziona iSCSI, immettere l'indirizzo IP del Server iSCSI e la Destinazione sul server iSCSI. È possibile, facoltativamente, selezionare di aggiungere l'autenticazione iSCSI.
Logico
Specifica un pool di memoria di tipo volume logico. Selezionare l'ubicazione del dispositivo in Percorso dispositivo.
Canale a fibre ottiche SCSI
Specifica un pool basato su un canale a fibre ottiche SCSI. Selezionare quale adattatore
SCSI utilizzare.
Specificare un percorso di memoria per il pool di memoria. Il percorso di memoria è l'ubicazione nel file system locale con cui il pool è associato.
Il percorso deve essere univoco. Se la directory non esiste al momento della creazione del
pool, verrà creata per l'utente.
Fare clic su Crea.
Aggiungi volumeAggiunge volumi a un pool di memoria.
Richiama da URL remoto
Specifica un'ubicazione da cui scaricare il volume. Ad esempio: https://my-server/fedora22.img.
Carica un file
Specifica un'ubicazione sul sistema locale.
================================================
FILE: ui/pages/help/it_IT/templates.dita
================================================
ModelliLa pagina Modelli visualizza i modelli di macchina virtuale definiti che è possibile utilizzare per creare macchine guest KVM.
Per ciascun modello vengono visualizzate le seguenti informazioni:
SO
Il nome del sistema operativo o della distribuzione.
Versione
La versione del sistema operativo o della distribuzione.
CPU
Il numero di processori definiti per il modello.
Memoria
La quantità di memoria ad accesso casuale da assegnare, in MB.
Per ciascun modello è possibile selezionare le azioni indicate di seguito:
Selezionare Modifica per modificare il modello.
Selezionare Clona per copiare un modello.
Selezionare Elimina per eliminare il modello.
Per aggiungere un modello fare clic sull'icona più
(+).
Modifica modelloModificare un modello esistente.
Per ciascun modello vengono visualizzate le seguenti informazioni:
Generale
Visualizza il nome, la distribuzione fornitore, la versione, la memoria, il percorso file al file ISO e le preferenze grafiche.
Memoria
Specificare le informazioni pool di memoria per il modello.
Interfaccia
Visualizza le interfacce di rete predefinite disponibili per la macchina guest KVM.
È possibile selezionare più reti.
Processore
Il campo Numero CPU, specifica il numero di processori definiti per il modello.
Selezionare l'impostazione manuale della topologia della CPU per ogni macchina guest.
Aggiungi modelloAggiungere un modello dal supporto di origine. È possibile aggiungere una propria immagine ISO al pool di memoria 'ISO' per la seguente individuazione.
Selezionare l'ubicazione del supporto di origine dalle seguenti opzioni:
Immagine ISO locale
Selezionare questa opzione per eseguire la scansione dei pool di memoria alla ricerca di immagini ISO di installazione disponibili sul sistema.
File immagine locale
Selezionare per specificare un percorso al file immagine locale.
Immagine ISO remota
Selezionare questa opzione per specificare un'ubicazione remota per un'immagine ISO di installazione.
Aggiungi modello - Immagine ISOAggiungere un modello da un'immagine ISO.
Vengono visualizzate in remoto le immagini ISO disponibili sul sistema.
SO
Il nome del sistema operativo o della distribuzione.
Versione
La versione del sistema operativo o della distribuzione.
Dimensione
La dimensione dell'immagine ISO.
Per creare un modello da un'immagine ISO scegliere tra le seguenti opzioni:
Selezionare un'immagine ISO da cui creare un modello, quindi fare clic su Crea modelli da ISO selezionato.
Selezionare Tutti per creare un modello da ciascuna immagine ISO elencata, quindi fare clic su Crea modelli da ISO selezionato.
Se nei risultati della scansione non viene visualizzata l'immagine ISO che si desidera utilizzare, è possibile selezionare dalle seguenti opzioni:
Selezionare Utilizzare un file ISO specifico per specificare un percorso all'immagine ISO.
Fare clic su Ricerca più ISO per ricercare più immagini
ISO.
================================================
FILE: ui/pages/help/ja_JP/Makefile.am
================================================
# Copyright IBM Corp, 2014-2016
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
ja_JP_helpdir = $(datadir)/wok/plugins/kimchi/ui/pages/help/ja_JP
dist_ja_JP_help_DATA = $(wildcard *.html) $(NULL)
EXTRA_DIST = $(wildcard *.dita)
CLEANFILES = $(wildcard *.html)
================================================
FILE: ui/pages/help/ja_JP/guests.dita
================================================
ゲスト「ゲスト」ページには、サーバーの定義済みゲストがリストされます。
テンプレートの追加テンプレートをソース・メディアから追加します。
今後のディスカバリーのために、独自の ISO イメージを「ISO」ストレージ・プールに追加できます。
ソース・メディアのロケーションを以下のオプションから選択してください。
ローカル ISO イメージ
これを選択して、システムで使用可能なインストール ISO イメージを、ストレージ・プールでスキャンします。
ローカル・イメージ・ファイル
これを選択して、ローカル・イメージ・ファイルのパスを指定します。
リモート ISO イメージ
これを選択して、インストール ISO イメージのリモート・ロケーションを指定します。
テンプレートの追加 - ISO イメージテンプレートを ISO イメージから追加します。
システム上で使用可能な ISO イメージがリモート側で表示されます。
OS
オペレーティング・システムまたはディストリビューションの名前。
バージョン
オペレーティング・システムまたはディストリビューションのバージョン。
サイズ
ISO イメージのサイズ。
テンプレートを ISO イメージから作成するには、以下のオプションを選択してください。
テンプレートを作成する元になる ISO イメージを選択して、「選択した ISO からテンプレートを作成」をクリックします。
リストされている ISO イメージそれぞれからテンプレートを作成するには、「すべて」を選択してから「選択した ISO からテンプレートを作成」をクリックします。
使用したい ISO イメージがスキャン結果に見つからない場合、以下のオプションを選択できます。
ISO イメージのパスを指定するには、「特定の ISO ファイルを使用する」を選択します。
それ以上の ISO イメージを検索するには、「ISO をさらに検索」をクリックします。
================================================
FILE: ui/pages/help/kimchi.css
================================================
/*
* Project Kimchi
*
* Copyright IBM Corp, 2014-2016
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
BODY {
background: #FFFFFF;
margin-bottom: 1em;
margin-left: .5em;
}
bold {
font-weight: bold;
}
boldItalic {
font-weight: bold;
font-style: italic;
}
italic {
font-style: italic;
}
underlined {
text-decoration: underline;
}
uicontrol {
font-weight: bold;
}
filepath {
font-family: monospace, monospace;
}.option {
font-family: monospace, monospace;
}
cmdname {
font-weight: bold;
font-family: monospace, monospace;
}
.defparmname {
font-weight: bold;
text-decoration: underline;
font-family: monospace, monospace;
}
.kwd {
font-weight: bold;
}
.defkwd {
font-weight: bold;
text-decoration: underline;
}
var {
font-style : italic;
}
strongwintitle {
font-weight : bold;
}
parmname {
font-weight: bold;
font-family: monospace, monospace;
white-space: nowrap;
}
code {
font-family: monospace, monospace;
}
pre {
font-family: monospace, monospace;
}
CITE {
font-style: italic;
}
EM {
font-style: italic;
}
STRONG {
font-weight: bold;
}
VAR {
font-style: italic;
}
dt {
font-weight: bold;
}
/***********************************************************
* Basic fonts
***********************************************************/
body,
td,
th,
caption {
font-family: Verdana, Arial, Helvetica, sans-serif;
font-size: 10pt;
}
pre, code {
font-family: MS Courier New, Courier, monospace;
}
h1, h2, h3 {
font-size: 12pt;
font-weight: bold;
color: #336699;
}
h4 {
font-size: 10pt;
font-weight: bold;
color: #336699;
}
/***********************************************************
* Basic indents, padding, and margin
***********************************************************/
body {
color: black;
background-color: white;
margin: 0;
padding-top: 0.2em;
padding-left: 0.6em;
padding-right: 0.2em;
padding-bottom: 1em;
}
h1,
h2,
h3,
h4,
h5,
h6 {
padding: 0;
margin-top: 1em;
margin-bottom: 0.75em;
margin-left: 0;
margin-right: 0;
}
address,
dl,
li,
p {
padding: 0;
margin-top: 0.75em;
margin-bottom: 0.75em;
margin-left: 0;
margin-right: 0;
line-height: 125%;
}
td dl {
margin-left: 2em;
}
pre {
padding: 0;
margin-top: 0.75em;
margin-bottom: 0.75em;
margin-left: 2em;
margin-right: 0;
}
ol,
ul {
padding: 0;
margin-top: 0.75em;
margin-bottom: 0.75em;
margin-left: 2.00em;
margin-right: 0;
}
dd {
margin-left: 3.00em;
margin-top: 0.75em;
margin-bottom: 0.75em;
}
dt {
margin-left: 1.00em;
margin-top: 0.75em;
}
================================================
FILE: ui/pages/help/ko_KR/Makefile.am
================================================
# Copyright IBM Corp, 2014-2016
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
ko_KR_helpdir = $(datadir)/wok/plugins/kimchi/ui/pages/help/ko_KR
dist_ko_KR_help_DATA = $(wildcard *.html) $(NULL)
EXTRA_DIST = $(wildcard *.dita)
CLEANFILES = $(wildcard *.html)
================================================
FILE: ui/pages/help/ko_KR/guests.dita
================================================
게스트게스트 페이지에는 서버에 정의된
게스트가 나열됩니다.
각 게스트에 대해 다음 정보가 표시됩니다.
이름
게스트의 이름입니다.
CPU
게스트의 프로세서 이용률입니다.
디스크 I/O
초당 디스크 입/출력(I/O) 전송 속도(KB)입니다.
네트워크 I/O
초당 네트워크 입/출력(I/O) 전송 속도(KB)입니다.
라이브타일
게스트 운영 체제의 상태이거나, 게스트가 활성이 아닌 경우 Linux 배포를 나타내는 아이콘입니다.
다음 조치 아이콘이 각 게스트마다 표시됩니다.
다시 설정
게스트를 다시 설정하려면 클릭합니다.
전원(시작 또는 중지)
게스트의 전원을 켜거나 끄려면 클릭합니다. 아이콘이 빨간색이면 전원이 꺼진 것이고 아이콘이 녹색이면 전원이 켜진 것입니다.
각 게스트마다 다음 조치를 선택할 수 있습니다.
게스트 운영 체제의 원격 콘솔에 연결하려면 연결을 선택합니다.
게스트를 작성하려면 복제를 선택하여 기존 게스트 정의를
복사합니다.
게스트를 다시 설정하려면 다시 설정을 선택합니다. 시작한 게스트만
다시 설정할 수 있습니다.
기존 게스트의 특성을 편집하려면 편집을 선택합니다. 게스트는 중지 상태일 때만 편집할 수 있습니다.
게스트를 시작하려면 시작을 선택합니다.
게스트를 종료하려면 시스템 종료를 선택합니다.
게스트의 즉시 종료를 강제 실행하려면 전원 끄기를
선택합니다.
게스트를 삭제하려면 삭제를 선택합니다.
게스트를 작성하려면 페이지에 있는 더하기(+) 아이콘을
클릭합니다.
게스트 작성기존 템플리트를 사용하여 게스트를 작성합니다.
게스트를 식별하는 데 사용될 이름을 입력하십시오.
템플리트를 선택하십시오.
템플리트가 존재하는 경우, 표시된 템플리트 중에서 선택하십시오.
템플리트가 없는 경우, 템플리트 작성을 클릭하여 템플리트를 작성하십시오.
마우스를 올려 놓으면 템플리트 정보를 볼 수 있습니다.
작성을 클릭하십시오.
게스트 편집기존 게스트의 특성을 편집합니다. 일부 특성은 게스트가 중지된 동안에만 편집할 수 있습니다.
다른 특성은 다음 부트에서 적용됩니다.
일반
게스트에 사용할 이름, CPU, 메모리 및 아이콘을 포함하여
게스트에 대한 정보를 표시합니다. 중지된 게스트의 이름을 편집할 수
있습니다. CPU와 메모리를 변경하면 다음 부팅 후 적용됩니다.
스토리지
선택한 게스트에 대한 스토리지의 장치 및 경로를 표시합니다.
게스트의 스토리지 장치를 추가, 편집 및 제거할 수 있습니다.
인터페이스
이름, 유형 및 MAC 주소를 포함하여 게스트에 대한 네트워크 정보를
표시합니다. 게스트의 인터페이스를 추가, 편집 및 제거할 수
있습니다.
권한
게스트에 대한 권한이 부여된 사용자 및 그룹을 표시합니다.
호스트 PCI 장치
호스트에서 사용 가능한 모든 PCI 장치 목록을 표시합니다.
스냅샷
게스트의 스냅샷을 표시합니다. 스냅샷을 작성, 편집 또는 삭제할 수
있습니다. 스냅샷을 선택하고 되돌리기를 선택함으로써 게스트는
스냅샷 데이터에 의해 결정되는 과거의 시점으로 복원되며
해당 시점을 넘어 작성된 변경사항을 삭제합니다.
사용 안함으로 설정되지 않은 필드를 편집할 수 있습니다. 필드를 편집한 후에 저장을 클릭합니다.
게스트 복제게스트를 복제하여 게스트 사본을 작성할 수 있습니다.
게스트를 복제하려면 다음을 수행하십시오.
게스트의 조치 메뉴에서 복제를
선택합니다.
경고에 동의합니다. 대상 게스트가 SCSI 또는
iSCSI 볼륨을 사용하거나 대상 풀에 충분한 공간이 없는 경우
복제는 기본 스토리지 풀에 작성됩니다.
프로세스가 완료되면 복제 중... 레이블 목록에 게스트가 표시되고
복제된 게스트는 사용할 수 있습니다.
================================================
FILE: ui/pages/help/ko_KR/network.dita
================================================
네트워크네트워크 페이지에는 네트워크 연결에 대한 정보가 표시됩니다.
네트워크 이름
네트워크의 이름 또는 기본값입니다.
상태
네트워크의 상태(활성의 경우 녹색, 비활성의 경우 빨간색)입니다.
네트워크 유형
네트워크 유형입니다. 예: NAT(Network Address Translation)
인터페이스
네트워크 인터페이스입니다. 예: virbr0(기본값)
주소 공간
IP 주소입니다.
다음 조치를 선택할 수 있습니다.
네트워크 연결을 시작하려면 시작을 선택합니다.
네트워크 연결을 종료하려면 중지를 선택합니다.
연결 정보를 삭제하려면 삭제를 선택합니다.
네트워크를 작성하려면 더하기(+) 아이콘을 클릭합니다.
네트워크 작성네트워크를 작성합니다.
네트워크의 이름을 입력하십시오.
네트워크 유형을 선택하려면 클릭하십시오.
격리됨
격리 모드입니다. 게스트는 외부 시스템에 대해 통신을 보내거나 받을 수 없습니다.
NAT
Network Address Translation 모드입니다. 게스트가 외부 시스템으로 보내는 통신에서 호스트 IP 주소를 사용합니다. 외부 시스템은 게스트로의 통신을 시작할 수 없습니다.
브릿지됨
브릿지 모드입니다. 게스트는 외부 시스템과 통신할 수 있고 외부 시스템은 네트워크상의 물리적 시스템처럼 게스트에 접속할 수 있습니다. 브릿지 모드의 경우, 추가 목적지 및 VLAN 정보를 지정해야 합니다.
작성을 클릭하십시오.
================================================
FILE: ui/pages/help/ko_KR/storage.dita
================================================
스토리지스토리지 페이지에는 바로 사용할 수 있는 '기본' 및 'ISO' 스토리지 풀을 포함하여 사용 가능한 스토리지 풀이 나열됩니다.
사용자 전용 ISO를 사용하려면 이를 'ISO' 스토리지 풀 경로에 추가하십시오.
각 스토리지 풀에 대해 다음 정보가 표시됩니다.
이름
스토리지 풀의 이름입니다.
% Used
사용 중인 스토리지 풀의 사용률입니다.
상태
스토리지 풀의 상태(활성의 경우 녹색, 비활성의 경우 빨간색)입니다.
위치
스토리지 풀의 위치에 대한 파일 경로입니다.
유형
스토리지 풀의 유형입니다. 예: dir
용량
스토리지 풀에서 공간의 양입니다.
할당됨
스토리지 풀에 이미 할당된 공간의 양입니다.
각 스토리지 풀마다 다음 조치를 선택할 수 있습니다.
사용 가능하도록 스토리지 풀을 활성화하려면 활성화를 선택합니다.
스토리지 풀을 비활성화하려면 비활성화를 선택합니다.
활성 스토리지 풀에 볼륨을 추가하려면 볼륨 추가를
선택합니다.
비활성 스토리지 풀을 제거하려면 정의 취소를 선택합니다.
스토리지 풀에 대한 스토리지 볼륨 세부사항을 표시하려면 스토리지 풀 행의 오른쪽에 있는 화살표를 클릭하십시오. 스토리지 풀을 정의하려면
더하기(+) 아이콘을 클릭합니다.
스토리지 풀 정의 스토리지 풀을 정의합니다.
스토리지 풀 이름 필드에서, 스토리지 풀을 식별하는 데 사용될 이름을 입력하십시오.
스토리지 풀 유형 목록에서 다음 유형을 선택하십시오.
DIR
디렉토리 풀을 지정합니다. DIR 유형을 선택한 경우, 스토리지 경로(스토리지 풀의 파일 경로)를 입력합니다.
NFS
네트워크 파일 시스템 풀을 지정합니다. NFS를 선택한 경우, NFS 서버 IP 주소 및 NFS 경로(예상 디렉토리의 경로)를 입력합니다.
iSCSI
iSCSI 서버에 할당된 대상을 기반으로 풀을 지정합니다.
iSCSI를 선택한 경우, iSCSI 서버에 대한 iSCSI 서버 IP 주소 및 대상을 입력합니다. 선택적으로, iSCSI 인증을 추가하도록 선택할 수 있습니다.
논리적
논리적 볼륨 스토리지 풀을 지정합니다. 장치 경로에서 장치에 대한 위치를 선택합니다.
SCSI 파이버 채널
SCSI 파이버 채널을 기반으로 풀을 지정합니다. 사용할 SCSI 어댑터를 선택합니다.
스토리지 풀의 스토리지 경로를 지정합니다. 스토리지 경로는
풀이 맵핑되는 로컬 파일 시스템의 위치입니다.
경로는 고유해야 합니다. 풀이 작성될 때 디렉토리가 없는 경우
사용자에 대해 작성됩니다.
작성을 클릭하십시오.
볼륨 추가스토리지 풀에 볼륨을 추가합니다.
원격 URL에서 페치
볼륨을 다운로드할 위치를 지정합니다. 예를 들어, https://my-server/fedora22.img입니다.
파일 업로드
로컬 시스템에 위치를 지정합니다.
================================================
FILE: ui/pages/help/ko_KR/templates.dita
================================================
템플리트템플리트 페이지에는 KVM 게스트를 작성하는 데 사용될 수 있는 정의된 가상 머신 템플리트가 표시됩니다.
각 템플리트에 대해 다음 정보가 표시됩니다.
OS
운영 체제 또는 배포의 이름입니다.
버전
운영 체제 또는 배포의 버전입니다.
CPU
템플리트에 대해 정의된 프로세서의 수입니다.
메모리
할당될 RAM(Random Access Memory)의 양(MB)입니다.
각 템플리트마다 다음 조치를 선택할 수 있습니다.
템플리트를 편집하려면 편집을 선택합니다.
템플리트를 복사하려면 복제를 선택합니다.
템플리트를 삭제하려면 삭제를 선택합니다.
템플리트를 추가하려면 더하기(+) 아이콘을 클릭합니다.
템플리트 편집기존 템플리트를 편집합니다.
각 템플리트에 대해 다음 정보가 표시됩니다.
일반
이름, 벤더 배포, 버전, 메모리,
ISO 파일에 대한 파일 경로 및 그래픽 환경 설정을 표시합니다.
스토리지
템플리트에 대한 스토리지 풀 정보를 지정합니다.
인터페이스
KVM 게스트에 사용 가능한 기본 네트워크 인터페이스를 표시합니다.
여러 네트워크를 선택할 수 있습니다.
프로세서
CPU 번호 필드에서 템플리트에 대해 정의된
프로세서의 수를 지정합니다.
각 게스트에 대해 CPU 토폴로지를 수동으로 설정하려면 선택합니다.
템플리트 추가소스 매체로부터 템플리트를 추가합니다. 다음 검색에 대해 'ISO' 스토리지 풀에 사용자 전용 ISO 이미지를 추가할 수 있습니다.
다음 옵션 중에서 소스 매체의 위치를 선택하십시오.
로컬 ISO 이미지
시스템에서 사용 가능한 설치 ISO 이미지의 스토리지 풀을 스캔하려면 선택합니다.
로컬 이미지 파일
로컬 이미지 파일 경로를 지정하려면 선택합니다.
원격 ISO 이미지
설치 ISO 이미지의 원격 위치를 지정하려면 선택합니다.
템플리트 추가 - ISO 이미지ISO 이미지로부터 템플리트를 추가합니다.
시스템에서 사용 가능한 ISO 이미지가 원격으로 표시됩니다.
OS
운영 체제 또는 배포의 이름입니다.
버전
운영 체제 또는 배포의 버전입니다.
크기
ISO 이미지의 크기입니다.
ISO 이미지로부터 템플리트를 작성하려면 다음 옵션 중에서 선택하십시오.
템플리트를 작성하기 위한 ISO 이미지를 선택한 후 선택한 ISO로부터 템플리트 작성을 클릭합니다.
나열된 각 ISO 이미지로부터 템플리트를 작성하려면 모두를 선택한 후 선택한 ISO로부터 템플리트 작성을 클릭합니다.
사용하려는 ISO 이미지가 스캔 결과에 표시되지 않는 경우, 다음 옵션 중에서 선택할 수 있습니다.
ISO 이미지의 경로를 지정하려면 특정 ISO 파일을 사용하려고 합니다.를 선택합니다.
추가 ISO 이미지를 검색하려면 추가 ISO 검색을 클릭합니다.
================================================
FILE: ui/pages/help/pt_BR/Makefile.am
================================================
# Copyright IBM Corp, 2014-2016
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
pt_BR_helpdir = $(datadir)/wok/plugins/kimchi/ui/pages/help/pt_BR
dist_pt_BR_help_DATA = $(wildcard *.html) $(NULL)
EXTRA_DIST = $(wildcard *.dita)
CLEANFILES = $(wildcard *.html)
================================================
FILE: ui/pages/help/pt_BR/guests.dita
================================================
Máquinas VirtuaisA página Convidados lista os convidados definidos para o seu servidor.
Para cada convidado, as informações a seguir são exibidas:
Nome
Nome do convidado.
CPU
Porcentagem de utilização do processador no convidado.
E/S de disco
Taxa de transmissão de entrada/saída de disco em KB por segundo.
E/S de rede
Taxa de transmissão de entrada/saída de rede em KB por segundo.
Livetile
Estado do console do sistema operacional guest ou um ícone que representa
a distribuição Linux se o
convidado não estiver ativo.
Os ícones de ações a seguir são exibidos para cada convidado:
Reiniciar
Clique para Reiniciar o convidado.
Energia (iniciar ou parar)
Clique para ligar ou desligar o convidado. Se o ícone estiver vermelho,
a energia está desligada; se o ícone estiver verde, a energia está ligada.
As ações a seguir podem ser selecionadas para cada convidado:
Selecione Conectar para conectar-se ao console
remoto para o sistema operacional guest.
Selecione Clonar para copiar uma definição de convidado existente para criar um convidado.
Selecione Reiniciar para Reiniciar o convidado. Somente é possível reconfigurar um convidado que esteja iniciado.
Selecione Editar para editar as propriedades de um
convidado existente. Os Máquinas Virtuais podem ser editados somente quando interrompidos.
Selecione Iniciar para iniciar um convidado.
Selecione Encerrar para encerrar um convidado corretamente.
Selecione Desligar para forçar um encerramento imediato do convidado.
Selecione Excluir para excluir o convidado.
Para criar um convidado, clique no ícone de mais (+) na página.
Criar um convidadoCrie um convidado usando um modelo existente.
Digite o nome a ser usado para identificar o convidado.
Selecione um modelo.
Se existirem modelos, selecione a partir dos modelos exibidos.
Se não existir nenhum modelo, clique em Criar um modelo para
criar um modelo.
É possível visualizar informações sobre um modelo passando o mouse sobre ele.
Clique em Criar.
Editar convidadoEdite as propriedades de um convidado existente. Algumas propriedades podem ser editadas enquanto a máquina virtual está interrompida. Outras entrarão em vigor na próxima inicialização.
Geral
Exibe informações sobre o seu convidado, incluindo nome, CPUs, memória e ícone para usar para o seu convidado. É possível editar o nome de um convidado interrompido. A mudança de CPUs e memória entra em vigor após a próxima inicialização.
Armazenamento
Exibe o dispositivo e o caminho para armazenamento para o convidado selecionado.
É possível incluir, editar e remover dispositivos de armazenamento para o seu convidado.
Interface
Exibe informações de rede para o convidado, incluindo nome, tipo e endereço MAC. É possível incluir, editar e remover interfaces para o seu convidado.
Permissão
Exibe os usuários e grupos que estão autorizados para o convidado.
Dispositivo PCI do host
Exibe uma lista de todos os dispositivos PCI disponíveis no host.
Captura instantânea
Exibe capturas instantâneas do convidado.É possível criar, editar ou excluir uma captura instantânea. Ao selecionar uma captura instantânea e selecionar reverter, o convidado é restaurado para um ponto no passado, determinado pelos dados da captura instantânea e descarta quaisquer mudanças feitas além desse momento.
Os campos que não estão desativados podem ser editados. Depois de editar um campo,
clique em Salvar.
Clonando um convidadoA clonagem de convidados permite criar uma cópia de um convidado.
Para clonar um convidado:
Selecione Clonar no menu Ação de um convidado.
Aceite o aviso. Quando um convidado de destino está usando volumes SCSI ou iSCSI ou se o conjunto de destino não tiver espaço suficiente, o clone será criado em um banco de armazenamento padrão.
Um convidado aparece na sua lista com o rótulo Clonando... Quando o processo for concluído, o convidado clonado estará disponível para uso.
================================================
FILE: ui/pages/help/pt_BR/network.dita
================================================
RedeA página Rede exibe informações
sobre a conexão de rede.
Nome da rede
Nome da rede ou padrão.
Estado
Estado da rede, ativo (verde) ou inativo (vermelho).
Tipo de rede
Tipo de rede, por exemplo, NAT (conversão
de endereço de rede).
Interface
Interface de rede, por exemplo, virbr0 (padrão).
Espaço de endereço
Endereço IP.
As ações a seguir podem ser selecionadas:
Selecione Iniciar para iniciar a conexão
de rede.
Selecione Parar para terminar a conexão de rede.
Selecione Excluir para excluir as informações
de conexão.
Para criar uma rede, clique no ícone de mais (+).
Criar uma redeCrie uma rede.
Digite o nome da rede.
Clique para selecionar o tipo de rede.
Isolado
Modo isolado. Os Máquinas Virtuais não podem enviar ou receber comunicação para
ou de sistemas externos.
NAT
Modo de Conversão de Endereço de Rede. A comunicação de Máquinas Virtuais com
sistemas externos usa o endereço IP do host. Os sistemas externos não podem
iniciar a comunicação com os Máquinas Virtuais.
bridged
Modo bridged. Os Máquinas Virtuais podem se comunicar com os sistemas externos e
ser contatados por sistemas externos como se fossem sistemas físicos
na rede. Para o modo bridged, devem-se especificar informações adicionais
de destino e de VLAN.
Clique em Criar.
================================================
FILE: ui/pages/help/pt_BR/storage.dita
================================================
ArmazenamentoA página Armazenamento lista os bancos de armazenamento disponíveis, inclusive os bancos de armazenamento 'default' e 'ISO' integrados. Se desejar usar seu próprio ISO, inclua-o em seu caminho do banco de armazenamento 'ISO'.
Para cada banco de armazenamento, as informações a seguir são exibidas:
Nome
Nome do banco de armazenamento.
% Usado
Porcentagem do banco de armazenamento que está sendo usada.
Estado
Estado do banco de armazenamento, ativo (verde) ou inativo (vermelho).
Local
Caminho do arquivo para o local do banco de armazenamento.
Tipo
Tipo de banco de armazenamento, por exemplo, dir.
Capacidade
Quantia de espaço no banco de armazenamento.
Alocado
Quantia de espaço já alocado no banco de armazenamento.
As ações a seguir podem ser selecionadas para cada banco de armazenamento:
Selecione Ativar para ativar o banco de armazenamento
para que ele possa ser usado.
Selecione Desativar para desativar um banco de armazenamento
ativo.
Selecione Incluir volume para incluir mais volume em um banco de armazenamento ativo.
Selecione Indefinir para remover um banco de armazenamento
inativo.
Para exibir detalhes do volume de armazenamento para um banco de armazenamento, clique na
seta no lado direito da linha do banco de armazenamento. Para definir um banco de armazenamento, clique no ícone de mais (+).
Definir um banco de armazenamento Defina um banco de armazenamento.
No campo Nome do banco de armazenamento, digite o
nome a ser usado para identificar o banco de armazenamento.
Na lista Tipo de banco de armazenamento, selecione o
tipo:
DIR
Especifica um banco de diretórios. Ao selecionar DIR,
digite o Caminho do armazenamento (caminho do arquivo para o
banco de armazenamento).
NFS
Especifica um banco de sistema de arquivos de rede. Ao selecionar NFS,
digite o endereço IP do servidor NFS e o Caminho
do NFS (caminho do diretório exportado).
iSCSI
Especifica um banco com base em um destino alocado em um servidor iSCSI.
Ao selecionar iSCSI, digite o endereço IP do Servidor
iSCSI e o Destino no
servidor iSCSI. Opcionalmente, é possível selecionar para incluir a autenticação iSCSI.
Lógico
Especifica um banco de armazenamento do volume lógico. Selecione o local para
o dispositivo em Caminho do dispositivo.
Fibre Channel SCSI
Especifica um banco com base em um Fibre Channel SCSI. Selecione qual
adaptador SCSI deve ser usado.
Especifique um caminho do armazenamento para o banco de armazenamento. O caminho do armazenamento é o local no sistema de arquivos local para o qual o banco está mapeado.
O caminho deve ser exclusivo. Se o diretório não existir quando o banco for criado, ele será criado para você.
Clique em Criar.
Incluir volumeInclui volume em um banco de armazenamento.
Buscar a partir da URL remota
Especifica um local do qual fazer o download do volume. Por exemplo: https://my-server/fedora22.img.
Fazer upload de um arquivo
Especifica um local em seu sistema local.
================================================
FILE: ui/pages/help/pt_BR/templates.dita
================================================
ModelosA página Modelos mostra os modelos de
máquina virtual definidos que podem ser usados para criar Máquinas Virtuais do KVM.
Para cada modelo, as informações a seguir são exibidas:
S.O.
Nome do sistema operacional ou distribuição.
Versão
Versão do sistema operacional ou distribuição.
CPUs
Número de processadores que estão definidos para o modelo.
Memória
Quantia de memória de acesso aleatório a ser alocada, em MB.
As ações a seguir podem ser selecionadas para cada modelo:
Selecione Editar para editar o modelo.
Selecione Clonar para copiar um modelo.
Selecione Excluir para excluir o modelo.
Para incluir um modelo, clique no ícone de mais (+).
Editar modeloEdite um modelo existente.
Para cada modelo, as informações a seguir são exibidas:
Geral
Exibe o nome, distribuição do fornecedor, versão, memória, caminho do arquivo para arquivo ISO e preferências de gráfico.
Armazenamento
Especifique as informações do banco de armazenamento para o modelo.
Interface
Exibe as interfaces de rede padrão disponíveis ao convidado KVM.
É possível
selecionar diversas redes.
Processador
No campo Número da CPU, especifique o número de processadores que são definidos para o modelo.
Selecione para Manualmente configurar a topologia da CPU para cada convidado.
Incluir modeloInclua um modelo a partir da mídia de origem. É possível incluir sua própria imagem ISO em seu banco de armazenamento 'ISO' para a descoberta a seguir.
Selecione o local da mídia de origem a partir das opções a seguir:
Imagem ISO local
Selecione para varrer banco de armazenamento para imagens ISO de instalação disponíveis
no sistema.
Arquivo da imagem local
Selecione para especificar um caminho para o arquivo de imagem local.
Imagem ISO remota
Selecione para especificar um local remoto para uma imagem ISO de instalação.
Incluir modelo - imagem ISOInclua um modelo a partir de uma imagem ISO.
As imagens ISO disponíveis no sistema são exibidas remotamente.
S.O.
Nome do sistema operacional ou distribuição.
Versão
Versão do sistema operacional ou distribuição.
Tamanho
Tamanho da imagem ISO.
Para criar um modelo a partir de uma imagem ISO, escolha a partir das opções
a seguir:
Selecione uma imagem ISO para criar um modelo a partir dela, em seguida, clique em Criar
modelos a partir do ISO selecionado.
Selecione Todos para criar um modelo a partir de cada
imagem ISO listada, em seguida, clique em Criar modelos a partir do
ISO selecionado.
Se a imagem ISO que você deseja usar não aparecer nos resultados de
varredura, será possível selecionar a partir das opções a seguir:
Selecione Eu desejo usar um arquivo ISO específico para
especificar um caminho para a imagem ISO.
Clique em Procurar mais ISOs para procurar mais
imagens ISO.
================================================
FILE: ui/pages/help/ru_RU/Makefile.am
================================================
# Copyright IBM Corp, 2014-2016
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
ru_RU_helpdir = $(datadir)/wok/plugins/kimchi/ui/pages/help/ru_RU
dist_ru_RU_help_DATA = $(wildcard *.html) $(NULL)
EXTRA_DIST = $(wildcard *.dita)
CLEANFILES = $(wildcard *.html)
================================================
FILE: ui/pages/help/ru_RU/guests.dita
================================================
Гостевые системыСтраница Гостевые системы содержит список гостевых систем сервера.
Для каждой гостевой системы показывается следующая информация:
Имя
Имя гостевой системы.
Процессор
Процент использования процессора в гостевой системе.
Дисковый ввод-вывод
Скорость дискового ввода-вывода в КБ/с.
Сетевой ввод-вывод
Скорость сетевого ввода-вывода в КБ/с.
Livetile
Состояние консоли гостевой операционной системы или значок, представляющий вариант ОС Linux, если гостевая система не активна.
Для каждой гостевой системы показываются следующие значки действий:
Сброс
Сброс гостевой системы.
Питание (запуск/остановка)
Включение/выключение питания гостевой системы. Если значок красный, питание выключено. Если значок зеленый, питание включено.
Для каждой гостевой системы доступны следующие действия:
Подключиться - подключиться к удаленной консоли гостевой операционной системы.
Выберите Дублировать, чтобы скопировать существующее определение гостевой системы и создать новую.
Сброс - сброс гостевой системы. Сбросить можно только работающую гостевую систему.
Изменить - настройка свойств гостевой системы. Свойства гостевой системы можно изменять, только когда система остановлена.
Выберите Пуск, чтобы запустить гостевую систему
Выберите Завершить работу, чтобы штатно завершить работу гостевой системы.
Выберите Выключить, чтобы принудительно завершить работу гостевой системы.
Выберите Удалить, чтобы удалить гостевую систему.
Для создания гостевой системы щелкните на значке плюса (+) на странице.
Создание гостевой системыСоздание гостевой системы из готового шаблона.
Введите имя, с помощью которого будет идентифицироваться гостевая система.
Выберите шаблон.
Если есть шаблоны, выберите шаблон в списке.
Если шаблонов нет, щелкните на Создать шаблон, чтобы создать шаблон.
Для просмотра информации о шаблоне наведите курсор мыши на него.
Щелкните на Создать.
Изменение гостевой системыИзменение свойств существующей гостевой системы. Некоторые свойства можно изменять только пока остановлена гостевая среда. Другие вступают в силу после перезагрузки.
Общие
Информация о гостевой системе, включая имя, число процессоров, объем памяти и значок. Имя остановленной гостевой системы можно изменить. Изменение числа процессоров и объема памяти вступает в силу после перезагрузки.
Дисковая память
Информация об устройстве и путь к дисковой памяти выбранной гостевой системы.
Можно добавлять, изменять и удалять устройства хранения гостевой системы.
Интерфейс
Сетевая информация для гостевой системы, включая имя, тип и MAC-адрес.
Можно добавлять, изменять и удалять интерфейсы гостевой системы.
Права доступа
Информация о пользователях и группах, которым разрешен доступ к гостевой системе.
Устройство PCI хоста
Список всех устройств PCI, доступных на хосте.
Моментальная копия
Информация о моментальных копиях гостевой системы. Можно создавать, изменять и удалять моментальные копии. Выберите моментальную копию и щелкните на Восстановить - восстановится одно из прошлых состояний гостевой системы, сохраненное в моментальной копии; все изменения, возникшие позднее, будут потеряны.
Активные поля можно изменять. После изменения поля щелкните на Сохранить.
Дублирование гостевых системДублирование гостевых систем позволяет создавать копии гостевых систем.
Для дублирования гостевой системы выполните следующие действия:
Выберите Дублировать в меню Действие гостевой системы.
Примите предупреждение.Если в целевой гостевой системе используются тома SCSI или iSCSI или если в целевом пуле недостаточно свободного места, дубликат будет создан в пуле памяти по умолчанию.
Появится гостевая система в списке с надписью Дубликат.... По окончании процесса копия гостевой системы станет доступна для использования.
================================================
FILE: ui/pages/help/ru_RU/network.dita
================================================
СетьНа странице Сеть показывается информация о сетевом соединении.
Имя сети
Имя сети или по умолчанию.
Состояние
Состояние сети - активная (зеленый) или неактивная (красный).
Тип сети
Тип сети, например NAT (преобразование сетевых адресов).
Интерфейс
Сетевой интерфейс, например virbr0 (по умолчанию).
Адресное пространство
IP-адрес.
Доступны следующие действия:
Запустить - открыть сетевое соединение.
Остановить - закрыть сетевое соединение.
Удалить - удалить информацию о соединении.
Для создания сети щелкните на значке плюса (+).
Создание сетиСоздание сети.
Введите имя сети.
Выберите тип сети.
Изолированный
Изолированный режим. Гостевые системы не могут обмениваться данными с внешними системами.
NAT
Режим преобразования сетевых адресов. Обмен данными между гостевыми и внешними системами осуществляется через IP-адрес хоста. Внешние системы не могут подключаться к гостевым.
Через мост
Режим работы через мост. Гостевые системы могут обмениваться данными с внешними системами, и внешние системы могут подключаться к гостевым, как если бы те были физическими системами в сети. В режиме работы через мост необходимо указать дополнительную информацию о целевом расположении и VLAN.
Щелкните на Создать.
================================================
FILE: ui/pages/help/ru_RU/storage.dita
================================================
Дисковая памятьНа странице Дисковая память показывается список доступных пулов памяти, включая пулы памяти 'по умолчанию' и 'ISO'. Для использования собственного ISO добавьте его в путь к пулу памяти 'ISO'.
Для каждого пула памяти показывается следующая информация:
Имя
Имя пула памяти.
% занято
Процент занятого места в пуле памяти.
Состояние
Состояние пула памяти - активный (зеленый) или неактивный (красный).
Расположение
Путь к расположению пула памяти.
Тип
Тип пула памяти, например каталог.
Емкость
Объем пула памяти.
Выделено
Объем выделенной памяти в пуле памяти.
Для каждого пула памяти можно выбирать следующие действия:
Активировать - активировать пул памяти, чтобы его можно было использовать.
Выберите Добавить том, чтобы добавить дополнительный том в активный пул памяти.
Удалить - удалить неактивный пул памяти.
Для просмотра сведений о томах пула памяти щелкните на стрелке в правой части строки пула памяти. Для того чтобы создать пул памяти, щелкните на значке плюса (+).
Создание пула памяти Создание пула памяти.
В поле Имя пула памяти введите имя для идентификации пула памяти.
В списке Тип пула памяти выберите тип:
Каталог
Задает пул-каталог. При выборе типа Каталог заполните поле
Путь к пулу памяти (путь к пулу памяти в файловой системе).
NFS
Задает пул на основе сетевой файловой системы. При выборе NFS укажите адрес в
поле IP-адрес сервера NFS и путь к экспортированному каталогу в поле Путь NFS.
iSCSI
Задает пул на основе целевого объекта, выделенного на сервере iSCSI.
При выборе типа iSCSI укажите IP-адрес в поле Сервер iSCSI и целевой объект на сервере iSCSI в поле Целевой объект. Можно также добавить идентификацию iSCSI.
Логический
Задает пул памяти на основе логического тома. Выберите расположение устройства в поле Путь к устройству.
SCSI Fibre Channel
Задает пул на основе SCSI Fibre Channel. Выберите адаптер SCSI.
Укажите путь к пулу памяти. Путь к пулу памяти указывает на место в файловой системе, куда отображен пул памяти. Путь должен быть уникальным. Если каталог не существует в момент создания пула, он будет создан автоматически.
Щелкните на Создать.
Добавление томаДобавление тома в пул памяти.
Загрузить с удаленного URL
Указывает, откуда следует загрузить том. Пример: https://my-server/fedora22.img.
Передать файл
Задает место в локальной системе.
================================================
FILE: ui/pages/help/ru_RU/templates.dita
================================================
ШаблоныНа странице Шаблоны показываются созданные шаблоны виртуальных машин, которые можно использовать для создания гостевых систем KVM.
Для каждого шаблона показывается следующая информация:
ОС
Имя операционной системы или варианта операционной системы.
Версия
Версия операционной системы или варианта операционной системы.
Процессоры
Количество процессоров для шаблона.
Память
Выделяемый объем оперативной памяти в МБ.
Для каждого шаблона можно выбирать следующие действия:
Изменить - изменить шаблон.
Выберите Дублировать, чтобы скопировать шаблон.
Удалить - удалить шаблон.
Для создания шаблона щелкните на значке плюса (+).
Изменить шаблонИзменить существующий шаблон.
Для каждого шаблона показывается следующая информация:
Общие
Информация об имени, варианте ОС от вендора, версии, памяти, пути к файлу ISO и графических параметрах.
Дисковая память
Параметры пула памяти для шаблона.
Интерфейс
Сетевые интерфейсы по умолчанию, доступные гостевой системе KVM. Можно выбрать несколько сетей.
Процессор
В поле Количество процессоров укажите число процессоров для шаблона.
Здесь можно вручную настроить топологию процессоров для каждой гостевой системы.
Добавление шаблонаДобавление шаблона с исходного носителя. Добавьте собственный образ ISO в пул памяти ISO для дальнейшего поиска.
Выберите один из следующих вариантов расположения исходного носителя:
Локальный образ ISO
Выберите этот вариант для поиска установочных образов ISO в локальных пулах памяти системы.
Локальный файл образа
Здесь можно указать путь к локальному файлу образа.
Удаленный образ ISO
Выберите этот вариант, чтобы указать удаленное расположение установочного образа ISO.
Добавление шаблона (образ ISO)Добавление шаблона из образа ISO.
Будут показаны образы ISO, доступные в системе удаленно.
ОС
Имя операционной системы или варианта операционной системы.
Версия
Версия операционной системы или варианта операционной системы.
Размер
Размер образа ISO.
Для создания шаблона из образа ISO выберите один из следующих вариантов:
Выберите образ ISO, из которого нужно создать шаблон, затем щелкните на Создать шаблоны из выбранных образов ISO.
Выберите Все, чтобы создать шаблон из каждого образа ISO в списке, затем щелкните на Создать шаблоны из выбранных образов ISO.
Если требуемый образ ISO отсутствует в результатах поиска, выберите один из следующих вариантов:
Выберите Использовать конкретный файл ISO, чтобы указать путь к образу ISO.
Щелкните на Поиск дополнительных образов ISO для поиска дополнительных образов ISO.
================================================
FILE: ui/pages/help/zh_CN/Makefile.am
================================================
# Copyright IBM Corp, 2014-2016
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
zh_CN_helpdir = $(datadir)/wok/plugins/kimchi/ui/pages/help/zh_CN
dist_zh_CN_help_DATA = $(wildcard *.html) $(NULL)
EXTRA_DIST = $(wildcard *.dita)
CLEANFILES = $(wildcard *.html)
================================================
FILE: ui/pages/help/zh_CN/guests.dita
================================================
访客“访客”页面列示已为服务器定义的访客。
================================================
FILE: ui/pages/help/zh_TW/Makefile.am
================================================
# Copyright IBM Corp, 2014-2016
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
zh_TW_helpdir = $(datadir)/wok/plugins/kimchi/ui/pages/help/zh_TW
dist_zh_TW_help_DATA = $(wildcard *.html) $(NULL)
EXTRA_DIST = $(wildcard *.dita)
CLEANFILES = $(wildcard *.html)
================================================
FILE: ui/pages/help/zh_TW/guests.dita
================================================
客體「客體」頁面會列出為伺服器定義的客體。
對於每一個客體,將會顯示下列資訊:
名稱
客體的名稱。
CPU
客體中的處理器使用率百分比。
磁碟 I/O
磁碟輸入/輸出傳輸速率 (KB/s)。
網路 I/O
網路輸入/輸出傳輸速率 (KB/s)。
Livetile
客體作業系統主控台的狀態,或是表示 Linux 發行套件的圖示(如果客體未處於作用中狀態)。
對於每一個客體,將會顯示下列動作圖示:
重設
按一下可重設客體。
電源(啟動或停止)
按一下可開啟或關閉客體的電源。如果該圖示為紅色,則表示電源關閉;如果該圖示為綠色,則表示電源開啟。
可針對每一個客體選取下列動作:
選取連接可連接至客體作業系統的遠端主控台。
選取複製可複製現有客體定義,來建立客體。
選取重設可重設客體。您可以只重設已啟動的客體。
選取編輯可編輯現有客體的內容。僅在停止時,才能編輯客體。
選取啟動以啟動客體
選取關閉以循序關閉客體。
選取關閉電源以強制立即關閉客體。
選取刪除可刪除客體。
如果要建立客體,請按一下頁面上的加號 (+) 圖示。
建立客體使用現有範本來建立客體。
鍵入要用於識別客體的名稱。
選取範本。
如果範本存在,請從顯示的範本中選取。
如果沒有範本,請按一下建立範本來建立範本。
您可以透過將游標移至範本上方,來檢視其相關資訊。
按一下建立。
編輯客體編輯現有客體的內容。部分內容只能在客體停止時進行編輯。其他內容將在下一次啟動時生效。
一般
顯示客體的相關資訊,其中包括用於客體的名稱、CPU、記憶體及圖示。
您可以編輯已停止客體的名稱。
變更 CPU 和記憶體會在下一次啟動之後生效。
新增範本從來源媒體中新增範本。您可以將自己的 ISO 映像檔新增至 'ISO' 儲存區,以進行下列探索。
從下列選項中選取來源媒體的位置:
本端 ISO 映像檔
選取此項可掃描儲存區以取得系統上可用的安裝 ISO 映像檔。
本端映像檔
選取此項以指定本端映像檔的路徑。
遠端 ISO 映像檔
選取此項可指定安裝 ISO 映像檔的遠端位置。
新增範本 - ISO 映像檔從 ISO 映像檔新增範本。
將從遠端顯示系統上可用的 ISO 映像檔。
OS
作業系統的名稱或發行套件的名稱。
版本
作業系統的版本或發行套件的版本。
大小
ISO 映像檔的大小。
若要從 ISO 映像檔建立範本,請從下列選項中選擇:
選取要用來建立範本的 ISO 映像檔,然後按一下從所選 ISO 建立範本。
選取全部以從每一個列出的 ISO 映像檔建立範本,然後按一下從所選 ISO 建立範本。
如要要使用的 ISO 映像檔未出現在掃描結果中,則可以從下列選項中選擇:
選取我想使用特定的 ISO 檔案以指定 ISO 映像檔的路徑。
按一下搜尋更多 ISO 以搜尋更多 ISO 映像檔。
================================================
FILE: ui/pages/i18n.json.tmpl
================================================
#*
* Project Kimchi
*
* Copyright IBM Corp, 2014-2017
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*#
#unicode UTF-8
#import gettext
#from wok.cachebust import href
#silent t = gettext.translation($lang.domain, $lang.localedir, languages=$lang.lang, fallback=True)
#silent _ = t.gettext
#silent _t = t.gettext
{
"Host": "$_("Host")",
"Guests": "$_("Guests")",
"Templates": "$_("Templates")",
"Storage": "$_("Storage")",
"Network": "$_("Network")",
"KCHAPI6003E": "$_("This is not a valid Linux path")",
"KCHAPI6008E": "$_("Unable to read file.")",
"KCHAPI6009E": "$_("Error while uploading file.")",
"KCHAPI6001M": "$_("Delete Confirmation")",
"KCHAPI6002M": "$_("OK")",
"KCHAPI6003M": "$_("Cancel")",
"KCHAPI6004M": "$_("Confirm")",
"KCHAPI6005M": "$_("Create")",
"KCHAPI6006M": "$_("Warning")",
"KCHAPI6007M": "$_("Save")",
"KCHAPI6008M": "$_("Creating...")",
"KCHAPI6009M": "$_("Cloning...")",
"KCHAPI6010M": "$_("Saving...")",
"KCHAPI6012M": "$_("Migrating...")",
"KCHTMPL6001W": "$_("No ISO found")",
"KCHTMPL6001M": "$_("Add Template")",
"KCHTMPL6002M": "$_("This may take a long time. Do you want to continue?")",
"KCHTMPL6003M": "$_("This will permanently delete the %1 template. Would you like to continue?")",
"KCHTMPL6004M": "$_("View Table")",
"KCHTMPL6005M": "$_("View Gallery")",
"KCHTMPL6006M": "$_("Not Available")",
"KCHTMPL6007M": "$_("Please check the invalid Storage Pools")",
"KCHTMPL6008M": "$_("Please check the invalid Storage Pools or Paths")",
"KCHTMPL6009M": "$_("macvtap")",
"KCHTMPL6010M": "$_("ovs")",
"KCHTMPL6011M": "$_("network")",
"KCHVM6001M": "$_("This will delete the %1 virtual machine and its virtual disks. This operation cannot be undone. Would you like to continue?")",
"KCHVM6002M": "$_("Power off Confirmation")",
"KCHVM6003M": "$_("This action may produce undesirable results, "
"for example unflushed disk cache in the %1 guest. "
"Would you like to continue?")",
"KCHVM6004M": "$_("Reset Confirmation")",
"KCHVM6005M": "$_("There is a risk of data loss caused by reset without"
" the %1 guest OS shutdown. Would you like to continue?")",
"KCHVM6006M": "$_("Shut Down Confirmation")",
"KCHVM6007M": "$_("Note the %1 guest OS may ignore this request. Would you like to continue?")",
"KCHVM6008M": "$_("Virtual Machine delete Confirmation")",
"KCHVM6009M": "$_("The %1 virtual machine is not persistent. Power Off will delete it. Continue?")",
"KCHVM6010M": "$_("Add Guest")",
"KCHVM0001E": "$_("Input is not a number")",
"KCHVM0002E": "$_("Memory value cannot be higher than Max Memory value")",
"KCHVM0003E": "$_("For better performance it is recommended a threads per core value not greater than %1.")",
"KCHVMCD6001M": "$_("This CDROM will be detached permanently and you can re-attach it. Continue to detach it?")",
"KCHVMCD6002M": "$_("Attach")",
"KCHVMCD6003M": "$_("Attaching...")",
"KCHVMCD6009M": "$_("This disk will be detached permanently and you can re-attach it. Continue to detach it?")",
"KCHVMED6001M": "$_("interface:")",
"KCHVMED6002M": "$_("address:")",
"KCHVMED6003M": "$_("link_type:")",
"KCHVMED6004M": "$_("block:")",
"KCHVMED6005M": "$_("drive_type:")",
"KCHVMED6006M": "$_("model:")",
"KCHVMED6007M": "$_("Affected devices:")",
"KCHVMED6008M": "$_("More")",
"KCHVMED6009M": "$_("Less")",
"KCHVMED6010M": "$_("Successfully attached device to VM")",
"KCHVMED6011M": "$_("Successfully detached device from VM")",
"KCHVMED6012M": "$_("Following devices will be affected, confirm?")",
"KCHVMED6013M": "$_("macvtap")",
"KCHVMED6014M": "$_("ovs")",
"KCHVMED6015M": "$_("network")",
"KCHVMED6016M": "$_("Bridge")",
"KCHVMED6017M": "$_("Vepa")",
"KCHVMED6018M": "$_("None")",
"KCHNET6001M": "$_("unavailable")",
"KCHNET6002M": "$_("This action will interrupt network connectivity for any virtual machine that depend on the %1 network.")",
"KCHNET6003M": "$_("Add Network")",
"KCHNET6004M": "$_("The %1 network is not persistent. Instead of stop, this action will permanently delete it. Would you like to continue?")",
"KCHNET6001W": "$_("The bridged VLAN tag may not work well with NetworkManager enabled. You should consider disabling it.")",
"KCHPOOL6001M": "$_("This will permanently delete the %1 storage pool. Would you like to continue?")",
"KCHPOOL6002M": "$_("This storage pool is empty.")",
"KCHPOOL6003M": "$_("It will format your disk and you will loose any data in there, are you sure to continue? ")",
"KCHPOOL6004M": "$_("SCSI Fibre Channel")",
"KCHPOOL6005M": "$_("No SCSI adapters found.")",
"KCHPOOL6006M": "$_("Loading iSCSI targets...")",
"KCHPOOL6007M": "$_("No iSCSI found. Please input one.")",
"KCHPOOL6008M": "$_("Failed to load iSCSI targets.")",
"KCHPOOL6009M": "$_("Would you like to continue?")",
"KCHPOOL6010M": "$_("This will permanently delete the following storage volumes: %1")",
"KCHPOOL6011M": "$_("No available partitions found.")",
"KCHPOOL6012M": "$_("The %1 storage pool is not persistent. Instead of deactivate, this action will permanently delete it. Would you like to continue?")",
"KCHPOOL6013M": "$_("Unable to retrieve partitions information.")",
"KCHPOOL6014M": "$_("In progress...")",
"KCHPOOL6015M": "$_("Failed!")",
"KCHPOOL6016M": "$_("No LVM found in the system.")",
"KCHPOOL6017M": "$_("This will permanently wipe the following storage volumes: %1")",
"KCHPOOL6018M": "$_("Wipe Confirmation")",
"KCHPOOL6019M": "$_("Select one or more partitions to be added to the logical pool %1:")",
"KCHPOOL6020M": "$_("Add Storage")",
"KCHPOOL6021M": "$_("DIR")",
"KCHPOOL6022M": "$_("NFS")",
"KCHPOOL6023M": "$_("iSCSI")",
"KCHPOOL6024M": "$_("LOGICAL")",
"KCHPOOL6025M": "$_("device")",
"KCHPOOL6026M": "$_("path")",
"KCHPOOL6027M": "$_("size (GiB)")",
"KCHPOOL6028M": "$_("free size (GiB)")",
"KCHPOOL6005E": "$_("Invalid NFS mount path.")",
"KCHPOOL6006E": "$_("No logical device selected.")",
"KCHPOOL6009E": "$_("This is not a valid Server Name or IP. Please, modify it.")",
"KCHVMSTOR0001E": "$_("CDROM path needs to be a valid local/remote path and cannot be blank.")",
"KCHVMSTOR0002E": "$_("Disk pool or volume cannot be blank.")",
"KCHVMSTOR0003E": "$_("Disk size or Format or Directory path cannot be blank and Directory path needs to be a valid local/remote path.")",
"KCHVMSTOR0004E": "$_("Disk path needs to be a valid local/remote path and cannot be blank.")",
"KCHVMSTOR0005E": "$_("Storage pool or Disk size or Format cannot be blank.")",
"KCHVMSTOR0001M": "$_("cdrom")",
"KCHVMSTOR0002M": "$_("disk")",
"KCHVMSTOR0003M": "$_("Pool")",
"KCHVMSTOR0004M": "$_("Path")",
"KCHVMSTOR0005M": "$_("qcow")",
"KCHVMSTOR0006M": "$_("qcow2")",
"KCHVMSTOR0007M": "$_("qed")",
"KCHVMSTOR0008M": "$_("raw")",
"KCHVMSTOR0009M": "$_("vmdk")",
"KCHVMSTOR0010M": "$_("vpc")"
}
================================================
FILE: ui/pages/network-add.html.tmpl
================================================
#*
* Project Kimchi
*
* Copyright IBM Corp, 2015-2017
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*#
#unicode UTF-8
#import gettext
#from wok.cachebust import href
#silent t = gettext.translation($lang.domain, $lang.localedir, languages=$lang.lang, fallback=True)
#silent _ = t.gettext
#silent _t = t.gettext
$_("Create a network")
$_("Name should not contain '/' and '\"'.")
================================================
FILE: ui/pages/network-edit.html.tmpl
================================================
#*
* Project Kimchi
*
* Copyright IBM Corp, 2016
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*#
#unicode UTF-8
#import gettext
#from wok.cachebust import href
#silent t = gettext.translation($lang.domain, $lang.localedir, languages=$lang.lang, fallback=True)
#silent _ = t.gettext
#silent _t = t.gettext
$_("Edit Network")
$_("Name should not contain '/' and '\"'.")
================================================
FILE: ui/pages/storagepool-add-volume.html.tmpl
================================================
#*
* Project Kimchi
*
* Copyright IBM Corp, 2014-2016
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*#
#unicode UTF-8
#import gettext
#from wok.cachebust import href
#silent t = gettext.translation($lang.domain, $lang.localedir, languages=$lang.lang, fallback=True)
#silent _ = t.gettext
#silent _t = t.gettext
================================================
FILE: ui/pages/storagepool-add.html.tmpl
================================================
#*
* Project Kimchi
*
* Copyright IBM Corp, 2013-2017
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*#
#unicode UTF-8
#import gettext
#silent t = gettext.translation($lang.domain, $lang.localedir, languages=$lang.lang, fallback=True)
#silent _ = t.gettext
#silent _t = t.gettext
$_("Define a New Storage Pool")
================================================
FILE: ui/pages/storagepool-resize-volume.html.tmpl
================================================
#*
* Project Kimchi
*
* Copyright IBM Corp, 2016
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*#
#unicode UTF-8
#import gettext
#from wok.cachebust import href
#silent t = gettext.translation($lang.domain, $lang.localedir, languages=$lang.lang, fallback=True)
#silent _ = t.gettext
#silent _t = t.gettext
================================================
FILE: ui/pages/tabs/Makefile.am
================================================
#
# Kimchi
#
# Copyright IBM Corp, 2013-2016
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
tabshtmldir = $(datadir)/wok/plugins/kimchi/ui/pages/tabs
dist_tabshtml_DATA = $(wildcard *.html.tmpl) $(NULL)
================================================
FILE: ui/pages/tabs/guests.html.tmpl
================================================
#*
* Project Kimchi
*
* Copyright IBM Corp, 2013-2017
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*#
#unicode UTF-8
#import gettext
#from Cheetah.Template import Template
#from wok.cachebust import href
#silent t = gettext.translation($lang.domain, $lang.localedir, languages=$lang.lang, fallback=True)
#silent _ = t.gettext
#silent _t = t.gettext
#silent ht = Template
$_("State")$_("Guest Name ID")$_("OS Type")$_("VNC/Spice")$_("Processors Utilization")$_("Memory Utilization")$_("Storage I/O")$_("Network I/O")$_("Actions")
$_("No guests found.")
$_("Loading...")
================================================
FILE: ui/pages/tabs/network.html.tmpl
================================================
#*
* Project Kimchi
*
* Copyright IBM Corp, 2013-2017
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*#
#unicode UTF-8
#import gettext
#from wok.cachebust import href
#silent t = gettext.translation($lang.domain, $lang.localedir, languages=$lang.lang, fallback=True)
#silent _ = t.gettext
#silent _t = t.gettext
================================================
FILE: ui/pages/tabs/storage.html.tmpl
================================================
#*
* Project Kimchi
*
* Copyright IBM Corp, 2013-2017
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*#
#unicode UTF-8
#import gettext
#silent t = gettext.translation($lang.domain, $lang.localedir, languages=$lang.lang, fallback=True)
#silent _ = t.gettext
#silent _t = t.gettext
================================================
FILE: ui/pages/tabs/templates.html.tmpl
================================================
#*
* Project Kimchi
*
* Copyright IBM Corp, 2013-2017
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*#
#unicode UTF-8
#import gettext
#from wok.cachebust import href
#silent t = gettext.translation($lang.domain, $lang.localedir, languages=$lang.lang, fallback=True)
#silent _ = t.gettext
#silent _t = t.gettext
$_("Template Name (ID)")$_("OS")$_("Version")$_("Current CPUs")$_("Memory")$_("Actions")
$_("No templates found.")
$_("Loading...")
================================================
FILE: ui/pages/template-add.html.tmpl
================================================
#*
* Project Kimchi
*
* Copyright IBM Corp, 2013-2017
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*#
#unicode UTF-8
#import gettext
#from wok.cachebust import href
#silent t = gettext.translation($lang.domain, $lang.localedir, languages=$lang.lang, fallback=True)
#silent _ = t.gettext
#silent _t = t.gettext
$_("Add Template")
$_("The name used to identify the template. If omitted, a name will be automatically chosen.")
$_("When selecting more than one Image Template, a name will be automatically chosen for each Image Template selected.")
$_("Where is the source media for this template? ")
$_("The following ISOs are available:")
$_("Loading...")
================================================
FILE: ui/pages/template-edit.html.tmpl
================================================
#*
* Project Kimchi
*
* Copyright IBM Corp, 2013-2017
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*#
#unicode UTF-8
#import gettext
#from wok.cachebust import href
#silent t = gettext.translation($lang.domain, $lang.localedir, languages=$lang.lang, fallback=True)
#silent _ = t.gettext
#silent _t = t.gettext
================================================
FILE: ui/robots.txt
================================================
User-agent: *
Disallow: /
================================================
FILE: ui/serial/Makefile.am
================================================
# Kimchi
#
# Copyright IBM Corp, 2016
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
SUBDIRS = html libs
serialdir = $(datadir)/wok/plugins/kimchi/ui/serial
================================================
FILE: ui/serial/html/Makefile.am
================================================
# Kimchi
#
# Copyright IBM Corp, 2016
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
serial_htmldir = $(datadir)/wok/plugins/kimchi/ui/serial/html
dist_serial_html_DATA = serial.html
================================================
FILE: ui/serial/html/serial.html
================================================
Kimchi Serial Console
================================================
FILE: ui/serial/libs/Makefile.am
================================================
# Kimchi
#
# Copyright IBM Corp, 2016
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
serial_libsdir = $(datadir)/wok/plugins/kimchi/ui/serial/libs
dist_serial_libs_DATA = term.js
================================================
FILE: ui/serial/libs/term.js
================================================
/**
* term.js - an xterm emulator
* Copyright (c) 2012-2013, Christopher Jeffrey (MIT License)
* https://github.com/chjj/term.js
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* Originally forked from (with the author's permission):
* Fabrice Bellard's javascript vt100 for jslinux:
* http://bellard.org/jslinux/
* Copyright (c) 2011 Fabrice Bellard
* The original design remains. The terminal itself
* has been extended to include xterm CSI codes, among
* other features.
*/
;(function() {
/**
* Terminal Emulation References:
* http://vt100.net/
* http://invisible-island.net/xterm/ctlseqs/ctlseqs.txt
* http://invisible-island.net/xterm/ctlseqs/ctlseqs.html
* http://invisible-island.net/vttest/
* http://www.inwap.com/pdp10/ansicode.txt
* http://linux.die.net/man/4/console_codes
* http://linux.die.net/man/7/urxvt
*/
'use strict';
/**
* Shared
*/
var window = this
, document = this.document;
/**
* EventEmitter
*/
function EventEmitter() {
this._events = this._events || {};
}
EventEmitter.prototype.addListener = function(type, listener) {
this._events[type] = this._events[type] || [];
this._events[type].push(listener);
};
EventEmitter.prototype.on = EventEmitter.prototype.addListener;
EventEmitter.prototype.removeListener = function(type, listener) {
if (!this._events[type]) return;
var obj = this._events[type]
, i = obj.length;
while (i--) {
if (obj[i] === listener || obj[i].listener === listener) {
obj.splice(i, 1);
return;
}
}
};
EventEmitter.prototype.off = EventEmitter.prototype.removeListener;
EventEmitter.prototype.removeAllListeners = function(type) {
if (this._events[type]) delete this._events[type];
};
EventEmitter.prototype.once = function(type, listener) {
function on() {
var args = Array.prototype.slice.call(arguments);
this.removeListener(type, on);
return listener.apply(this, args);
}
on.listener = listener;
return this.on(type, on);
};
EventEmitter.prototype.emit = function(type) {
if (!this._events[type]) return;
var args = Array.prototype.slice.call(arguments, 1)
, obj = this._events[type]
, l = obj.length
, i = 0;
for (; i < l; i++) {
obj[i].apply(this, args);
}
};
EventEmitter.prototype.listeners = function(type) {
return this._events[type] = this._events[type] || [];
};
/**
* Stream
*/
function Stream() {
EventEmitter.call(this);
}
inherits(Stream, EventEmitter);
Stream.prototype.pipe = function(dest, options) {
var src = this
, ondata
, onerror
, onend;
function unbind() {
src.removeListener('data', ondata);
src.removeListener('error', onerror);
src.removeListener('end', onend);
dest.removeListener('error', onerror);
dest.removeListener('close', unbind);
}
src.on('data', ondata = function(data) {
dest.write(data);
});
src.on('error', onerror = function(err) {
unbind();
if (!this.listeners('error').length) {
throw err;
}
});
src.on('end', onend = function() {
dest.end();
unbind();
});
dest.on('error', onerror);
dest.on('close', unbind);
dest.emit('pipe', src);
return dest;
};
/**
* States
*/
var normal = 0
, escaped = 1
, csi = 2
, osc = 3
, charset = 4
, dcs = 5
, ignore = 6
, UDK = { type: 'udk' };
/**
* Terminal
*/
function Terminal(options) {
var self = this;
if (!(this instanceof Terminal)) {
return new Terminal(arguments[0], arguments[1], arguments[2]);
}
Stream.call(this);
if (typeof options === 'number') {
options = {
cols: arguments[0],
rows: arguments[1],
handler: arguments[2]
};
}
options = options || {};
each(keys(Terminal.defaults), function(key) {
if (options[key] == null) {
options[key] = Terminal.options[key];
// Legacy:
if (Terminal[key] !== Terminal.defaults[key]) {
options[key] = Terminal[key];
}
}
self[key] = options[key];
});
if (options.colors.length === 8) {
options.colors = options.colors.concat(Terminal._colors.slice(8));
} else if (options.colors.length === 16) {
options.colors = options.colors.concat(Terminal._colors.slice(16));
} else if (options.colors.length === 10) {
options.colors = options.colors.slice(0, -2).concat(
Terminal._colors.slice(8, -2), options.colors.slice(-2));
} else if (options.colors.length === 18) {
options.colors = options.colors.slice(0, -2).concat(
Terminal._colors.slice(16, -2), options.colors.slice(-2));
}
this.colors = options.colors;
this.options = options;
// this.context = options.context || window;
// this.document = options.document || document;
this.parent = options.body || options.parent
|| (document ? document.getElementsByTagName('body')[0] : null);
this.cols = options.cols || options.geometry[0];
this.rows = options.rows || options.geometry[1];
// Act as though we are a node TTY stream:
this.setRawMode;
this.isTTY = true;
this.isRaw = true;
this.columns = this.cols;
this.rows = this.rows;
if (options.handler) {
this.on('data', options.handler);
}
this.ybase = 0;
this.ydisp = 0;
this.x = 0;
this.y = 0;
this.cursorState = 0;
this.cursorHidden = false;
this.convertEol;
this.state = 0;
this.queue = '';
this.scrollTop = 0;
this.scrollBottom = this.rows - 1;
// modes
this.applicationKeypad = false;
this.applicationCursor = false;
this.originMode = false;
this.insertMode = false;
this.wraparoundMode = false;
this.normal = null;
// select modes
this.prefixMode = false;
this.selectMode = false;
this.visualMode = false;
this.searchMode = false;
this.searchDown;
this.entry = '';
this.entryPrefix = 'Search: ';
this._real;
this._selected;
this._textarea;
// charset
this.charset = null;
this.gcharset = null;
this.glevel = 0;
this.charsets = [null];
// mouse properties
this.decLocator;
this.x10Mouse;
this.vt200Mouse;
this.vt300Mouse;
this.normalMouse;
this.mouseEvents;
this.sendFocus;
this.utfMouse;
this.sgrMouse;
this.urxvtMouse;
// misc
this.element;
this.children;
this.refreshStart;
this.refreshEnd;
this.savedX;
this.savedY;
this.savedCols;
// stream
this.readable = true;
this.writable = true;
this.defAttr = (0 << 18) | (257 << 9) | (256 << 0);
this.curAttr = this.defAttr;
this.params = [];
this.currentParam = 0;
this.prefix = '';
this.postfix = '';
this.lines = [];
var i = this.rows;
while (i--) {
this.lines.push(this.blankLine());
}
this.tabs;
this.setupStops();
}
inherits(Terminal, Stream);
/**
* Colors
*/
// Colors 0-15
Terminal.tangoColors = [
// dark:
'#2e3436',
'#cc0000',
'#4e9a06',
'#c4a000',
'#3465a4',
'#75507b',
'#06989a',
'#d3d7cf',
// bright:
'#555753',
'#ef2929',
'#8ae234',
'#fce94f',
'#729fcf',
'#ad7fa8',
'#34e2e2',
'#eeeeec'
];
Terminal.xtermColors = [
// dark:
'#000000', // black
'#cd0000', // red3
'#00cd00', // green3
'#cdcd00', // yellow3
'#0000ee', // blue2
'#cd00cd', // magenta3
'#00cdcd', // cyan3
'#e5e5e5', // gray90
// bright:
'#7f7f7f', // gray50
'#ff0000', // red
'#00ff00', // green
'#ffff00', // yellow
'#5c5cff', // rgb:5c/5c/ff
'#ff00ff', // magenta
'#00ffff', // cyan
'#ffffff' // white
];
// Colors 0-15 + 16-255
// Much thanks to TooTallNate for writing this.
Terminal.colors = (function() {
var colors = Terminal.tangoColors.slice()
, r = [0x00, 0x5f, 0x87, 0xaf, 0xd7, 0xff]
, i;
// 16-231
i = 0;
for (; i < 216; i++) {
out(r[(i / 36) % 6 | 0], r[(i / 6) % 6 | 0], r[i % 6]);
}
// 232-255 (grey)
i = 0;
for (; i < 24; i++) {
r = 8 + i * 10;
out(r, r, r);
}
function out(r, g, b) {
colors.push('#' + hex(r) + hex(g) + hex(b));
}
function hex(c) {
c = c.toString(16);
return c.length < 2 ? '0' + c : c;
}
return colors;
})();
// Default BG/FG
Terminal.colors[256] = '#000000';
Terminal.colors[257] = '#f0f0f0';
Terminal._colors = Terminal.colors.slice();
Terminal.vcolors = (function() {
var out = []
, colors = Terminal.colors
, i = 0
, color;
for (; i < 256; i++) {
color = parseInt(colors[i].substring(1), 16);
out.push([
(color >> 16) & 0xff,
(color >> 8) & 0xff,
color & 0xff
]);
}
return out;
})();
/**
* Options
*/
Terminal.defaults = {
colors: Terminal.colors,
convertEol: false,
termName: 'xterm',
geometry: [80, 24],
cursorBlink: true,
visualBell: false,
popOnBell: false,
scrollback: 1000,
screenKeys: false,
debug: false,
useStyle: false
// programFeatures: false,
// focusKeys: false,
};
Terminal.options = {};
each(keys(Terminal.defaults), function(key) {
Terminal[key] = Terminal.defaults[key];
Terminal.options[key] = Terminal.defaults[key];
});
/**
* Focused Terminal
*/
Terminal.focus = null;
Terminal.prototype.focus = function() {
if (Terminal.focus === this) return;
if (Terminal.focus) {
Terminal.focus.blur();
}
if (this.sendFocus) this.send('\x1b[I');
this.showCursor();
// try {
// this.element.focus();
// } catch (e) {
// ;
// }
// this.emit('focus');
Terminal.focus = this;
};
Terminal.prototype.blur = function() {
if (Terminal.focus !== this) return;
this.cursorState = 0;
this.refresh(this.y, this.y);
if (this.sendFocus) this.send('\x1b[O');
// try {
// this.element.blur();
// } catch (e) {
// ;
// }
// this.emit('blur');
Terminal.focus = null;
};
/**
* Initialize global behavior
*/
Terminal.prototype.initGlobal = function() {
var document = this.document;
Terminal._boundDocs = Terminal._boundDocs || [];
if (~indexOf(Terminal._boundDocs, document)) {
return;
}
Terminal._boundDocs.push(document);
Terminal.bindPaste(document);
Terminal.bindKeys(document);
Terminal.bindCopy(document);
if (this.isMobile) {
this.fixMobile(document);
}
if (this.useStyle) {
Terminal.insertStyle(document, this.colors[256], this.colors[257]);
}
};
/**
* Bind to paste event
*/
Terminal.bindPaste = function(document) {
// This seems to work well for ctrl-V and middle-click,
// even without the contentEditable workaround.
var window = document.defaultView;
on(window, 'paste', function(ev) {
var term = Terminal.focus;
if (!term) return;
if (ev.clipboardData) {
term.send(ev.clipboardData.getData('text/plain'));
} else if (term.context.clipboardData) {
term.send(term.context.clipboardData.getData('Text'));
}
// Not necessary. Do it anyway for good measure.
term.element.contentEditable = 'inherit';
return cancel(ev);
});
};
/**
* Global Events for key handling
*/
Terminal.bindKeys = function(document) {
// We should only need to check `target === body` below,
// but we can check everything for good measure.
on(document, 'keydown', function(ev) {
if (!Terminal.focus) return;
var target = ev.target || ev.srcElement;
if (!target) return;
if (target === Terminal.focus.element
|| target === Terminal.focus.context
|| target === Terminal.focus.document
|| target === Terminal.focus.body
|| target === Terminal._textarea
|| target === Terminal.focus.parent) {
return Terminal.focus.keyDown(ev);
}
}, true);
on(document, 'keypress', function(ev) {
if (!Terminal.focus) return;
var target = ev.target || ev.srcElement;
if (!target) return;
if (target === Terminal.focus.element
|| target === Terminal.focus.context
|| target === Terminal.focus.document
|| target === Terminal.focus.body
|| target === Terminal._textarea
|| target === Terminal.focus.parent) {
return Terminal.focus.keyPress(ev);
}
}, true);
// If we click somewhere other than a
// terminal, unfocus the terminal.
on(document, 'mousedown', function(ev) {
if (!Terminal.focus) return;
var el = ev.target || ev.srcElement;
if (!el) return;
do {
if (el === Terminal.focus.element) return;
} while (el = el.parentNode);
Terminal.focus.blur();
});
};
/**
* Copy Selection w/ Ctrl-C (Select Mode)
*/
Terminal.bindCopy = function(document) {
var window = document.defaultView;
// if (!('onbeforecopy' in document)) {
// // Copies to *only* the clipboard.
// on(window, 'copy', function fn(ev) {
// var term = Terminal.focus;
// if (!term) return;
// if (!term._selected) return;
// var text = term.grabText(
// term._selected.x1, term._selected.x2,
// term._selected.y1, term._selected.y2);
// term.emit('copy', text);
// ev.clipboardData.setData('text/plain', text);
// });
// return;
// }
// Copies to primary selection *and* clipboard.
// NOTE: This may work better on capture phase,
// or using the `beforecopy` event.
on(window, 'copy', function(ev) {
var term = Terminal.focus;
if (!term) return;
if (!term._selected) return;
var textarea = term.getCopyTextarea();
var text = term.grabText(
term._selected.x1, term._selected.x2,
term._selected.y1, term._selected.y2);
term.emit('copy', text);
textarea.focus();
textarea.textContent = text;
textarea.value = text;
textarea.setSelectionRange(0, text.length);
setTimeout(function() {
term.element.focus();
term.focus();
}, 1);
});
};
/**
* Fix Mobile
*/
Terminal.prototype.fixMobile = function(document) {
var self = this;
var textarea = document.createElement('textarea');
textarea.style.position = 'absolute';
textarea.style.left = '-32000px';
textarea.style.top = '-32000px';
textarea.style.width = '0px';
textarea.style.height = '0px';
textarea.style.opacity = '0';
textarea.style.backgroundColor = 'transparent';
textarea.style.borderStyle = 'none';
textarea.style.outlineStyle = 'none';
textarea.autocapitalize = 'none';
textarea.autocorrect = 'off';
document.getElementsByTagName('body')[0].appendChild(textarea);
Terminal._textarea = textarea;
setTimeout(function() {
textarea.focus();
}, 1000);
if (this.isAndroid) {
on(textarea, 'change', function() {
var value = textarea.textContent || textarea.value;
textarea.value = '';
textarea.textContent = '';
self.send(value + '\r');
});
}
};
/**
* Insert a default style
*/
Terminal.insertStyle = function(document, bg, fg) {
var style = document.getElementById('term-style');
if (style) return;
var head = document.getElementsByTagName('head')[0];
if (!head) return;
var style = document.createElement('style');
style.id = 'term-style';
// textContent doesn't work well with IE for