├── .docs-bot.yml
├── .gitignore
├── .gitlab-ci.yml
├── .gitmodules
├── .travis.yml
├── LICENSE-GPL3.txt
├── README.rst
├── doc
├── .gitignore
├── Makefile
├── README.rst
├── architecture.rst
├── autounattend.rst
├── bugs.rst
├── compatibility.rst
├── conf.py
├── goldimage.rst
├── index.rst
├── ipxe-image.rst
├── libusbredir-patching.rst
├── license.rst
├── misc.rst
├── quality_control.rst
├── screenshots
│ └── spice-disconnect-actions.png
├── security.rst
├── sftp-floppy-upload.rst
├── spice-disconnect-actions.rst
├── start-and-stop-management.rst
├── stateless_and_snapshot_features.rst
├── switching-virtual-rooms.rst
├── tc-vm-mapping.rst
├── thinclients.rst
├── virtesk-infrastructure-server.rst
├── virtesk-tc-connectspice.rst
├── virtesk-tc-kickstart.rst
├── virtesk-tc-tools.rst
├── virtesk-vm-rollout-config.rst
├── virtesk-vm-rollout-install.rst
├── virtesk-vm-rollout.rst
├── virtual_rooms.rst
└── visio
│ ├── Makefile
│ ├── virtesk-archidecture-overview-small.png
│ ├── virtesk-archidecture-overview.pdf
│ ├── virtesk-archidecture-overview.png
│ ├── virtesk-archidecture-overview.vsdx
│ ├── virtesk-sysadmin-features-small.png
│ ├── virtesk-sysadmin-features.pdf
│ ├── virtesk-sysadmin-features.png
│ ├── virtesk-sysadmin-features.vsdx
│ ├── virtesk-vdi-connection-setup-small.png
│ ├── virtesk-vdi-connection-setup.pdf
│ ├── virtesk-vdi-connection-setup.png
│ ├── virtesk-vdi-connection-setup.vsdx
│ ├── virtesk-vdi-tc-rollout-small.png
│ ├── virtesk-vdi-tc-rollout.pdf
│ ├── virtesk-vdi-tc-rollout.png
│ ├── virtesk-vdi-tc-rollout.vsdx
│ ├── virtesk-virtual-rooms-small.png
│ ├── virtesk-virtual-rooms.pdf
│ ├── virtesk-virtual-rooms.png
│ └── virtesk-virtual-rooms.vsdx
├── misc
└── vdsm-spice-disconnect-actions-backport
│ ├── README.txt
│ ├── vdsm-spice-disconnect-actions-backport.patch
│ └── vdsm.spec
├── requirements.txt
├── sample_config
├── Autounattend-production.xml.template
├── database-layout-update-001.sql
├── database-layout.sql
├── generatesql-statements.sh
├── tc_rollout.ks
├── virtesk-tc-tools.conf
└── virtesk-vm-rollout.conf
├── virtesk-tc-connectspice
├── Makefile
├── conftest.py
├── connect_spice_client.py
├── find_thinclient_identifier.py
├── find_thinclient_identifier_nmcli.py
├── spice_xpi_controller.py
├── test_find_thinclient_identifier_nmcli.py
├── test_mock_data
│ ├── active_connection
│ ├── hostnamectl_transient
│ ├── hostnamectl_transient_empty
│ ├── nmcli_con_show_adsy_eap
│ ├── nmcli_con_show_adsy_eap_empty
│ ├── nmcli_device_show
│ └── nmcli_device_show_single_line
├── virtesk-tc-connectspice-main
└── virtesk-tc-connectspice-shutdown-vm
├── virtesk-tc-tools
├── README.md
├── tc_rollout_kexec
├── tc_screenshot
├── tc_ssh
└── utils.sh
└── virtesk-vm-rollout
├── Makefile
├── constants.py
├── rhev.py
├── rhev_manager.py
├── utils.py
├── virtesk-virtroom-delete
├── virtesk-virtroom-reset
├── virtesk-virtroom-rollout
├── virtesk-virtroom-show
├── virtesk-virtroom-shutdown
└── virtesk-virtroom-start
/.docs-bot.yml:
--------------------------------------------------------------------------------
1 | docs:
2 | extract_to: /var/www/html/public/virtesk
3 | download_delay: 20
4 | stages:
5 | - docs
6 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.pyc
2 | *.swp
3 | site/
4 | .python-version
5 | .cache/
6 |
--------------------------------------------------------------------------------
/.gitlab-ci.yml:
--------------------------------------------------------------------------------
1 |
2 | before_script:
3 | - source /etc/profile
4 | - git submodule sync
5 | - git submodule update --init --recursive
6 | - pyenv local 2.7.11
7 | - pip install sphinx_rtd_theme
8 |
9 | stages:
10 | - docs
11 |
12 | make-docs:
13 | stage: docs
14 | script:
15 | - rm -rf html
16 | - rm -rf doc/_build
17 | - make html_adsy -C doc
18 | - cp -r doc/_build/html html
19 | artifacts:
20 | paths:
21 | - html/*
22 |
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "doc/adsy-sphinx-template.src"]
2 | path = doc/adsy-sphinx-template.src
3 | url = git@git.adfinis-sygroup.ch:ad-sy/adsy-sphinx-template.src
4 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: python
2 | # Python Version
3 | python:
4 | - "2.7"
5 | # Ignore submodules
6 | git:
7 | submodules: false
8 | # Install requirements
9 | install: "pip install -r requirements.txt"
10 | # Run pytests
11 | script: pytest
12 |
--------------------------------------------------------------------------------
/README.rst:
--------------------------------------------------------------------------------
1 | .. |br| raw:: html
2 |
3 |
4 |
5 |
6 | Virtesk-VDI
7 | ============
8 |
9 | .. image:: https://api.travis-ci.org/adfinis-sygroup/virtesk.svg?branch=master
10 |
11 | Virtesk-VDI is an Open Source VDI solution. It allows to run virtual desktops
12 | in a RHEV/Ovirt environment seamlessly. The virtual desktops are displayed on thin clients
13 | in physical rooms. You can manage both the virtual desktops and the physical thin clients
14 | efficiently using the well-aligned tool collection.
15 |
16 |
17 | It is well-suited to virtualize workplaces in educational environments.
18 |
19 | The technical building blocks are:
20 |
21 | * Red Hat Enterprise Virtualization (RHEV) / Ovirt Virtualization
22 | * Spice VDI protocol
23 | * RHEL / CentOS for infrastructure services
24 | * Fedora Linux for thin clients
25 | * Active Directory (or Samba4) for Windows domain services
26 | * Windows VDI desktops
27 |
28 |
29 | Documentation is available `here `__.
30 |
31 | Features
32 | ---------
33 |
34 | Thin client user experience
35 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~
36 |
37 | Thin clients are very easy to use:
38 |
39 | 1. Turn thin client on
40 | 2. Login directly on virtual Windows desktop
41 | 3. Work
42 | 4. Turn thin client off
43 |
44 | Features:
45 |
46 | * Virtual Windows desktop - feels like a native Windows desktop
47 | * USB redirect
48 | * Audio: headphones, loudspeakers, microphones
49 | * One single login - no need to enter credentials twice
50 | * Comfortable thin client devices - small and silent
51 |
52 | Thin client administration
53 | ~~~~~~~~~~~~~~~~~~~~~~~~~~
54 |
55 | Virtesk-VDI features a fully automated network rollout of thin clients.
56 |
57 | The following remote administration features for thin clients are available:
58 |
59 | * Remote control / remote scripting (Tool tc_ssh)
60 | * Screenshots (Tool tc_screenshot)
61 | * Unattended Upgrades / Re-Installations (Tool tc_rollout_kexec)
62 |
63 | Virtual Rooms
64 | ~~~~~~~~~~~~~~
65 | Virtesk-VDI features virtual Windows desktops organized in virtual rooms.
66 |
67 | Virtual rooms are useful for educational institutions - physical rooms are mapped to virtual rooms. This is useful when combined with 3rd party classroom management and monitoring software like iTalc, UCS\@School, MasterEye, ...
68 |
69 | Instant switching of virtual rooms is possible. For example, one set of VMs can be used for normal teaching, and a dedicated set of secure VMs can be assigned for exams.
70 |
71 | The 1:1-mapping from thin clients to desktop VMs is controlled through a postgres database.
72 |
73 |
74 | Application and desktop maintenance
75 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
76 | A master VM (the "gold image") is used for application installation and desktop configuration. This master VM can then be cloned as often as necessary.
77 |
78 | A set of tools (virtesk-virtroom-rollout and friends) helps to simplify and automate the necessary tasks. Scripting and automation features like automatic Windows domain join are available.
79 |
80 |
81 | Nightly desktop reset
82 | ~~~~~~~~~~~~~~~~~~~~~
83 |
84 | For situations where clearly-defined centrally managed workplaces are desired, the nightly desktop reset feature comes in handy:
85 |
86 | * A snapshot is created upon VM creation
87 | * Every night, the VMs is set back to snapshot state
88 |
89 | This is useful to reduce time and effort spent by your IT support team: Desktops are always in a well defined state, divergence of desktops is avoided, and leftovers from old user sessions are cleaned up.
90 |
91 |
92 | Requirements
93 | --------------
94 |
95 | * Virtualization hardware (~ 4GB Ram per workplace), shared storage attached through iscsi or FibreChannel
96 | * RHEV/oVirt 3.5.x
97 | * Active Directory (or Samba 4) for Windows domain features
98 | * A supported OS for virtual Desktops ( stable: Windows 7; Windows 10 support is underway)
99 | * Thin clients: Any linux compatible (x86 or x86_64, must be supported by Fedora Linux) hardware can be used. Usually, small, silent and low power thin client devices are used; However, it is also possible to re-use old desktop computers as thin clients
100 | * Infrastructure server VM (part of Virtesk-VDI)
101 |
102 | Bird's eye view of operation / installation
103 | -------------------------------------------
104 |
105 | The steps to introduce Virtesk-VDI are more or less:
106 |
107 | * Preparing RHEV/Ovirt for VDI operation
108 | * Thin clients: Seting up Virtesk-VDI infrastructure services, including a Fedora Linux mirror, a network rollout infrastructure, scripts for unattended Fedora installations based on Kickstart, and a postgres database for VM-to-thin-client-mapping.
109 | * Installing virtesk-tc-tools for thin client remote management
110 | * Installing a Windows 7 master VM ("gold image")
111 | * Setting up the Windows unattended setup process for VM creation and for automatic Windows domain join
112 | * Setting up virtesk-virtroom-tools for virtual room management
113 | * Creating a network concept, including naming standards and ip-address conventions
114 |
115 |
116 |
--------------------------------------------------------------------------------
/doc/.gitignore:
--------------------------------------------------------------------------------
1 | *~
2 | *.html
3 | /_build/
4 |
--------------------------------------------------------------------------------
/doc/Makefile:
--------------------------------------------------------------------------------
1 | # Makefile for Sphinx documentation
2 | #
3 |
4 | # You can set these variables from the command line.
5 | SPHINXOPTS =
6 | SPHINXBUILD = sphinx-build
7 | PAPER =
8 | BUILDDIR = _build
9 |
10 | # User-friendly check for sphinx-build
11 | ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1)
12 | $(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/)
13 | endif
14 |
15 | # Internal variables.
16 | PAPEROPT_a4 = -D latex_paper_size=a4
17 | PAPEROPT_letter = -D latex_paper_size=letter
18 | ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
19 | # the i18n builder cannot share the environment and doctrees with the others
20 | I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
21 |
22 | .PHONY: help
23 | help:
24 | @echo "Please use \`make ' where is one of"
25 | @echo " html to make standalone HTML files"
26 | @echo " html_adsy to make standalone HTML files using adsy theme"
27 | @echo " dirhtml to make HTML files named index.html in directories"
28 | @echo " singlehtml to make a single large HTML file"
29 | @echo " pickle to make pickle files"
30 | @echo " json to make JSON files"
31 | @echo " htmlhelp to make HTML files and a HTML help project"
32 | @echo " qthelp to make HTML files and a qthelp project"
33 | @echo " applehelp to make an Apple Help Book"
34 | @echo " devhelp to make HTML files and a Devhelp project"
35 | @echo " epub to make an epub"
36 | @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
37 | @echo " latexpdf to make LaTeX files and run them through pdflatex"
38 | @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx"
39 | @echo " text to make text files"
40 | @echo " man to make manual pages"
41 | @echo " texinfo to make Texinfo files"
42 | @echo " info to make Texinfo files and run them through makeinfo"
43 | @echo " gettext to make PO message catalogs"
44 | @echo " changes to make an overview of all changed/added/deprecated items"
45 | @echo " xml to make Docutils-native XML files"
46 | @echo " pseudoxml to make pseudoxml-XML files for display purposes"
47 | @echo " linkcheck to check all external links for integrity"
48 | @echo " doctest to run all doctests embedded in the documentation (if enabled)"
49 | @echo " coverage to run coverage check of the documentation (if enabled)"
50 |
51 | .PHONY: clean
52 | clean:
53 | rm -rf $(BUILDDIR)/*
54 |
55 | .PHONY: html
56 | html:
57 | $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
58 | @echo
59 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
60 |
61 | .PHONY: html_adsy
62 | html_adsy:
63 | $(SPHINXBUILD) -b html -D html_theme='adsy' $(ALLSPHINXOPTS) $(BUILDDIR)/html
64 | @echo
65 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
66 |
67 | .PHONY: dirhtml
68 | dirhtml:
69 | $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
70 | @echo
71 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
72 |
73 | .PHONY: singlehtml
74 | singlehtml:
75 | $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
76 | @echo
77 | @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
78 |
79 | .PHONY: pickle
80 | pickle:
81 | $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
82 | @echo
83 | @echo "Build finished; now you can process the pickle files."
84 |
85 | .PHONY: json
86 | json:
87 | $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
88 | @echo
89 | @echo "Build finished; now you can process the JSON files."
90 |
91 | .PHONY: htmlhelp
92 | htmlhelp:
93 | $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
94 | @echo
95 | @echo "Build finished; now you can run HTML Help Workshop with the" \
96 | ".hhp project file in $(BUILDDIR)/htmlhelp."
97 |
98 | .PHONY: qthelp
99 | qthelp:
100 | $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
101 | @echo
102 | @echo "Build finished; now you can run "qcollectiongenerator" with the" \
103 | ".qhcp project file in $(BUILDDIR)/qthelp, like this:"
104 | @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/amoothei.qhcp"
105 | @echo "To view the help file:"
106 | @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/amoothei.qhc"
107 |
108 | .PHONY: applehelp
109 | applehelp:
110 | $(SPHINXBUILD) -b applehelp $(ALLSPHINXOPTS) $(BUILDDIR)/applehelp
111 | @echo
112 | @echo "Build finished. The help book is in $(BUILDDIR)/applehelp."
113 | @echo "N.B. You won't be able to view it unless you put it in" \
114 | "~/Library/Documentation/Help or install it in your application" \
115 | "bundle."
116 |
117 | .PHONY: devhelp
118 | devhelp:
119 | $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
120 | @echo
121 | @echo "Build finished."
122 | @echo "To view the help file:"
123 | @echo "# mkdir -p $$HOME/.local/share/devhelp/amoothei"
124 | @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/amoothei"
125 | @echo "# devhelp"
126 |
127 | .PHONY: epub
128 | epub:
129 | $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
130 | @echo
131 | @echo "Build finished. The epub file is in $(BUILDDIR)/epub."
132 |
133 | .PHONY: latex
134 | latex:
135 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
136 | @echo
137 | @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
138 | @echo "Run \`make' in that directory to run these through (pdf)latex" \
139 | "(use \`make latexpdf' here to do that automatically)."
140 |
141 | .PHONY: latexpdf
142 | latexpdf:
143 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
144 | sed -i 's/pdflatex/xelatex/g' $(BUILDDIR)/latex/Makefile
145 | sed -i '/^\\DeclareUnicodeCharacter/d' $(BUILDDIR)/latex/*.tex
146 | sed -i '/\\usepackage{hyperref}/d' $(BUILDDIR)/latex/sphinxmanual.cls
147 | sed -i '/\\usepackage\[Bjarne\]{fncychap}/d' $(BUILDDIR)/latex/*.tex
148 |
149 | @echo "Running LaTeX files through pdflatex..."
150 | $(MAKE) -C $(BUILDDIR)/latex all-pdf
151 | @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
152 |
153 | .PHONY: latexpdfja
154 | latexpdfja:
155 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
156 | @echo "Running LaTeX files through platex and dvipdfmx..."
157 | $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja
158 | @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
159 |
160 | .PHONY: text
161 | text:
162 | $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
163 | @echo
164 | @echo "Build finished. The text files are in $(BUILDDIR)/text."
165 |
166 | .PHONY: man
167 | man:
168 | $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
169 | @echo
170 | @echo "Build finished. The manual pages are in $(BUILDDIR)/man."
171 |
172 | .PHONY: texinfo
173 | texinfo:
174 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
175 | @echo
176 | @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
177 | @echo "Run \`make' in that directory to run these through makeinfo" \
178 | "(use \`make info' here to do that automatically)."
179 |
180 | .PHONY: info
181 | info:
182 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
183 | @echo "Running Texinfo files through makeinfo..."
184 | make -C $(BUILDDIR)/texinfo info
185 | @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
186 |
187 | .PHONY: gettext
188 | gettext:
189 | $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
190 | @echo
191 | @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
192 |
193 | .PHONY: changes
194 | changes:
195 | $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
196 | @echo
197 | @echo "The overview file is in $(BUILDDIR)/changes."
198 |
199 | .PHONY: linkcheck
200 | linkcheck:
201 | $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
202 | @echo
203 | @echo "Link check complete; look for any errors in the above output " \
204 | "or in $(BUILDDIR)/linkcheck/output.txt."
205 |
206 | .PHONY: doctest
207 | doctest:
208 | $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
209 | @echo "Testing of doctests in the sources finished, look at the " \
210 | "results in $(BUILDDIR)/doctest/output.txt."
211 |
212 | .PHONY: coverage
213 | coverage:
214 | $(SPHINXBUILD) -b coverage $(ALLSPHINXOPTS) $(BUILDDIR)/coverage
215 | @echo "Testing of coverage in the sources finished, look at the " \
216 | "results in $(BUILDDIR)/coverage/python.txt."
217 |
218 | .PHONY: xml
219 | xml:
220 | $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml
221 | @echo
222 | @echo "Build finished. The XML files are in $(BUILDDIR)/xml."
223 |
224 | .PHONY: pseudoxml
225 | pseudoxml:
226 | $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml
227 | @echo
228 | @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml."
229 |
--------------------------------------------------------------------------------
/doc/README.rst:
--------------------------------------------------------------------------------
1 | ../README.rst
--------------------------------------------------------------------------------
/doc/architecture.rst:
--------------------------------------------------------------------------------
1 | Architecture
2 | =============
3 |
4 | Virtesk-VDI is a `Open Source `__ VDI solution based on
5 | Red Hat Enterprise Virtualization (or Ovirt Virtualization) and
6 | the Spice VDI protocol.
7 |
8 | Overview
9 | ----------
10 |
11 | Seemless user experience: Ready for work in just two steps
12 |
13 |
14 | .. image:: visio/virtesk-archidecture-overview-small.*
15 |
16 | :download:`Print version (PDF)`.
17 |
18 |
19 | Features for system administrators
20 | ----------------------------------
21 |
22 | Features that make the live of a system administrator easier:
23 |
24 |
25 | .. image:: visio/virtesk-sysadmin-features-small.*
26 |
27 | :download:`Print version (PDF)`.
28 |
29 |
30 | VDI concept: virtual rooms
31 | --------------------------
32 |
33 | Virtesk-VDI uses an 1:1-Mapping between virtual and physical rooms.
34 | This is well-suited for schools and other environments where existing
35 | software depends on the concept of a "classroom".
36 |
37 |
38 | .. image:: visio/virtesk-virtual-rooms-small.*
39 |
40 | :download:`Print version (PDF)`.
41 |
42 | Thinclient: Connection setup
43 | ----------------------------
44 |
45 | How thinclients connect to their assiged virtual machine:
46 |
47 |
48 | .. image:: visio/virtesk-vdi-connection-setup-small.*
49 |
50 | :download:`Print version (PDF)`.
51 |
52 |
53 | Thinclient: Kickstart rollout
54 | -----------------------------
55 |
56 | Automatic thinclient rollout using fully automated and unattended
57 | kickstart installation of fedora 22:
58 |
59 |
60 | .. image:: visio/virtesk-vdi-tc-rollout-small.*
61 |
62 | :download:`Print version (PDF)`.
63 |
64 |
65 |
66 |
67 |
--------------------------------------------------------------------------------
/doc/autounattend.rst:
--------------------------------------------------------------------------------
1 | Windows Unattended Setup
2 | ======================================
3 |
4 | Introduction
5 | ------------
6 |
7 | Virtesk-virtroom-rollout creates several hunderds VMs by cloneing a
8 | single `Goldimage VM `__.
9 |
10 | However, simply cloneing a windows VM usually isn't enough, it needs to
11 | be generalized/sysprepped and then it must run though the Windows
12 | Unattended Setup phase for setting ComputerName, ip-address and for
13 | joining into the Active Directory Domain.
14 |
15 | This article explains the XML-Configuration-File used to configure and
16 | automatize the Windows Unattended Setup phase.
17 |
18 | Please note: Windows Unattended Setup is not an easy topic. This article
19 | covers only the aspects important for virtesk-vdi.
20 |
21 | Mako Templating
22 | ---------------
23 |
24 | `Python-mako `__ is
25 | used for templating and variable substitution.
26 |
27 | Variables:
28 |
29 | - ``${ip}``
30 | - ``${netmask_as_suffix}``
31 | - ``${default_gw}``
32 | - ``${ComputerName}``
33 | - ``${scripttime}``
34 |
35 | In general, all keys available in the ``vmconfig``-python-dict can be
36 | used as mako template variables. They can be displayed using
37 | ``virtesk-virtroom-show``:
38 |
39 | ::
40 |
41 | $ virtesk-virtroom-show test01
42 | [...]
43 | 2016-03-03 15:55:08,231 - rhev_manager - DEBUG - {'ComputerName': 'test01-vd01', 'tc_user': '...', 'description': 'LehrerVM', 'rhev_vm_name': 'test01-vd01', 'ip': '...', 'default_gw': '...', 'cluster': 'Default', 'netmask_as_suffix': '21', 'snapshot_description': 'Automatic snapshot after virtesk-vmrollout, IP=${ip}/${netmask_as_suffix}, scripttime=${scripttime}', 'scripttime': '2016-03-03-1555', 'reset_startvm': 'Always', 'timezone': 'W. Europe Standard Time', 'network_name': '...', 'reset_to_snapshot_regex': <_sre.SRE_Pattern object at 0x201d2f0>, 'workaround_os': 'rhel_7x64', 'autounattend_templatefile': '/etc/virtesk-vdi/Autounattend-production.xml.template', 'usb_enabled': True, 'rollout_startvm': True, 'template': '...', 'memory': 4294967296, 'workaround_timezone': 'Etc/GMT', 'os': 'windows_7x64', 'stateless': False}
44 | [...]
45 |
46 | Sample Config File
47 | ------------------
48 |
49 | A sample config file is available here:
50 | ``sample_config/Autounattend-production.xml.template``. It was tested
51 | with Windows 7 Professional, German, SP1
52 | (``de_windows_7_professional_with_sp1_x64_dvd_u_676919.iso``).
53 |
54 | If your are using it with a different language (e.g. not German, not
55 | DE-CH, ...), then you'll have to make adjustments. For example, network
56 | adapters have different names in different languages.
57 |
58 | The sample config file **will not "just work"**. You'll have to adapt it
59 | to make it work in your environment.
60 |
61 | Important Config Sections
62 | -------------------------
63 |
64 | Network
65 | ~~~~~~~
66 |
67 | Works only for German Windows 7:
68 |
69 | ::
70 |
71 | LAN-Verbindung
72 |
73 | Setting IP and gateway...
74 |
75 | ::
76 |
77 |
78 |
79 | LAN-Verbindung
80 |
81 | false
82 | 10
83 | false
84 |
85 |
86 | ${ip}/${netmask_as_suffix}
87 |
88 |
89 |
90 | 0
91 | ${default_gw}
92 | 0.0.0.0/0
93 |
94 |
95 |
96 |
97 |
98 | **Adjust**: Setting DNS-Servers and DNS-Searchdomain...
99 |
100 | ::
101 |
102 |
103 |
104 | LAN-Verbindung
105 |
106 | 192.0.2.220
107 |
108 | false
109 | true
110 | your-dns-domain.tld
111 |
112 |
113 |
114 | **Adjust**: more DNS stuff...
115 |
116 | ::
117 |
118 |
120 |
121 |
122 |
123 | 192.0.2.220
124 |
125 | LAN-Verbindung
126 | 1
127 |
128 |
129 |
130 |
131 | Setting the computer name and timezone...
132 |
133 | ::
134 |
135 |
136 |
137 | 32
138 | 96
139 | 1920
140 | 75
141 | 1080
142 |
143 | ${ComputerName}
144 | W. Europe Standard Time
145 |
146 |
147 | **Adjust**: Syncing with timeserver (avoids timezone problems during
148 | Windows Domain Join)...
149 |
150 | ::
151 |
152 |
153 |
154 | w32tm /config /manualpeerlist:192.0.2.221 /syncfromflags:MANUAL
155 | 1
156 |
157 |
158 | w32tm /resync
159 | 2
160 |
161 |
162 | w32tm /query /peers
163 | 3
164 |
165 |
166 |
167 | **Adjust**: Windows Domain Join...
168 |
169 | ::
170 |
171 |
172 |
173 |
174 | YOUR-ACTIVEDIRECTORY-DOMAIN
175 | Administrator4Domainjoins
176 | PASSWORD
177 |
178 | YOUR-ACTIVEDIRECTORY-DOMAIN
179 |
180 |
181 |
182 | **Adjust**: Local Administrator Password, Account for
183 | FirstLogonCommands, ...
184 |
185 | ::
186 |
187 |
188 |
189 | PASSWORD
190 |
191 | Administrator
192 | true
193 | 1
194 |
195 |
196 |
197 | PASSWORD
198 | true
199 |
200 |
201 |
202 | **Adjust**: Run some custization commands as a last step in the Windows
203 | Unattended Setup...
204 |
205 | - see also: `Quality Control: Windows Unattended
206 | Setup `__.
207 |
208 | ::
209 |
210 |
211 |
212 | net use Y: \\someserver\scriptshare /persistent:no /user:username@windowsdomain password
213 | false
214 | 20
215 |
216 |
217 | cmd /c Y:\autounattend-firstlogon.cmd ${scripttime} ${ComputerName} 1> C:\autounattend-firstlogon.log 2>&1
218 | false
219 | 21
220 |
221 |
222 |
223 |
224 | shutdown /p
225 | false
226 | 50
227 |
228 |
229 |
230 | IMPORTANT: Last step: VM shutdown
231 | ---------------------------------
232 |
233 | It is very important, that after all Windows Unattened Setup tasks run
234 | trough, the VM will shut down. If VMs do not shutdown, then
235 | ``virtesk-virtroom-rollout`` will wait forever.
236 |
237 | ::
238 |
239 |
240 | shutdown /p
241 | false
242 | 50
243 |
244 |
--------------------------------------------------------------------------------
/doc/bugs.rst:
--------------------------------------------------------------------------------
1 | .. |br| raw:: html
2 |
3 |
4 |
5 | Known bugs
6 | ========================
7 |
8 |
9 | Harmless bugs
10 | -------------
11 |
12 | VMSnapshotCdroms object comparison caused infinite loop [uncritical]
13 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
14 |
15 | Error messages while rolling out a virtual room:
16 |
17 | ::
18 |
19 | 2016-01-20 19:27:14,186 - root - DEBUG - Creating a snapshot(description: Automatic snapshot after virtesk-vmrollout, IP=XXXXXXXXXXXX, scripttime=2016-01-20-1853) of vm test03-vd01... done
20 | 2016-01-20 19:27:15,141 - root - DEBUG - Creating a snapshot(description: Automatic snapshot after virtesk-vmrollout, IP=XXXXXXXXXXXX, scripttime=2016-01-20-1853) of vm test03-vd03... done
21 | VMSnapshotCdroms object comparison caused infinite loop.
22 | 2016-01-20 19:27:16,034 - root - DEBUG - Creating a snapshot(description: Automatic snapshot after virtesk-vmrollout, IP=XXXXXXXXXXXX, scripttime=2016-01-20-1853) of vm test03-vd05... done
23 | VMSnapshotCdroms object comparison caused infinite loop.
24 | VMSnapshotCdroms object comparison caused infinite loop.
25 | 2016-01-20 19:27:17,363 - root - DEBUG - Creating a snapshot(description: Automatic snapshot after virtesk-vmrollout, IP=XXXXXXXXXXXX, scripttime=2016-01-20-1853) of vm test03-vd07... done
26 | VMSnapshotCdroms object comparison caused infinite loop.
27 | VMSnapshotCdroms object comparison caused infinite loop.
28 | VMSnapshotCdroms object comparison caused infinite loop.
29 | 2016-01-20 19:27:18,254 - root - DEBUG - Creating a snapshot(description: Automatic snapshot after virtesk-vmrollout, IP=XXXXXXXXXXXX, scripttime=2016-01-20-1853) of vm test03-vd09... done
30 | VMSnapshotCdroms object comparison caused infinite loop.
31 | VMSnapshotCdroms object comparison caused infinite loop.
32 | VMSnapshotCdroms object comparison caused infinite loop.
33 | VMSnapshotCdroms object comparison caused infinite loop.
34 | 2016-01-20 19:27:19,231 - root - DEBUG - Creating a snapshot(description: Automatic snapshot after virtesk-vmrollout, IP=XXXXXXXXXXXX, scripttime=2016-01-20-1853) of vm test03-vd11... done
35 | VMSnapshotCdroms object comparison caused infinite loop.
36 | VMSnapshotCdroms object comparison caused infinite loop.
37 | VMSnapshotCdroms object comparison caused infinite loop.
38 | VMSnapshotCdroms object comparison caused infinite loop.
39 | VMSnapshotCdroms object comparison caused infinite loop.
40 | 2016-01-20 19:27:22,519 - root - DEBUG - Creating a snapshot(description: Automatic snapshot after virtesk-vmrollout, IP=XXXXXXXXXXXX, scripttime=2016-01-20-1853) of vm test03-vd15... done
41 |
42 | Cause: unknown. Maybe a python phaenomen related to recursive object
43 | structures, like described in
44 | https://mail.python.org/pipermail/python-dev/2003-October/039445.html?
45 |
46 | Impact: **none**, the VMs and the snapshots are created successfully.
47 |
--------------------------------------------------------------------------------
/doc/compatibility.rst:
--------------------------------------------------------------------------------
1 | Compatibility
2 | =============
3 |
4 | Current versions:
5 | -----------------
6 |
7 | The current versions of virtesk-vdi are tested in the following
8 | environment:
9 |
10 | - Virtualisation: Ovirt/RHEV 3.5.x
11 | - VMs: Windows 7 Professional
12 | - Thinclients: Fedora 22 x86\_64
13 | - VDI protocol: Spice
14 | - Virtualization storage: Block-Based, e.g. FibreChannel or iscsi
15 | - Virtualization hosts: based on RHEL 6.x / CentOS 6.x. A full Linux
16 | installation is needed, the RHEV-H image is not supported.
17 |
18 | Earlier versions:
19 | -----------------
20 |
21 | Earlier versions successfully run in the following environment:
22 |
23 | - RHEV 3.1 / 3.2 / 3.4
24 | - VMs: Windows 7 Professional
25 | - Thinclients: Fedora 20 x86 and x86\_64
26 | - VDI Protocol: Spice
27 | - Virtualization storage: block-based, e.g. FibreChannel or iscsi
28 | - Virtualization hosts: based on RHEL 6.x / CentOS 6.x.
29 |
--------------------------------------------------------------------------------
/doc/conf.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | #
3 | # Virtesk-VDI documentation build configuration file, created by
4 | # sphinx-quickstart2 on Thu Mar 31 12:24:51 2016.
5 | #
6 | # This file is execfile()d with the current directory set to its
7 | # containing dir.
8 | #
9 | # Note that not all possible configuration values are present in this
10 | # autogenerated file.
11 | #
12 | # All configuration values have a default; values that are commented out
13 | # serve to show the default.
14 |
15 | import sys
16 | import os
17 | import sphinx_rtd_theme
18 | # If extensions (or modules to document with autodoc) are in another directory,
19 | # add these directories to sys.path here. If the directory is relative to the
20 | # documentation root, use os.path.abspath to make it absolute, like shown here.
21 | #sys.path.insert(0, os.path.abspath('.'))
22 |
23 | # -- General configuration ------------------------------------------------
24 |
25 | # If your documentation needs a minimal Sphinx version, state it here.
26 | #needs_sphinx = '1.0'
27 |
28 | # Add any Sphinx extension module names here, as strings. They can be
29 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
30 | # ones.
31 | extensions = []
32 |
33 | # Add any paths that contain templates here, relative to this directory.
34 | templates_path = ['_templates']
35 |
36 | # The suffix(es) of source filenames.
37 | # You can specify multiple suffix as a list of string:
38 | # source_suffix = ['.rst', '.md']
39 | source_suffix = '.rst'
40 |
41 | # The encoding of source files.
42 | #source_encoding = 'utf-8-sig'
43 |
44 | # The master toctree document.
45 | master_doc = 'index'
46 |
47 | # General information about the project.
48 | project = u'Virtesk-VDI'
49 | copyright = u'2016, Adfinis SyGroup'
50 | author = u'Simon Neininger, Ueli Isch'
51 |
52 | # The version info for the project you're documenting, acts as replacement for
53 | # |version| and |release|, also used in various other places throughout the
54 | # built documents.
55 | #
56 | # The short X.Y version.
57 | version = u'1.0'
58 | # The full version, including alpha/beta/rc tags.
59 | release = u'1.0'
60 |
61 | # The language for content autogenerated by Sphinx. Refer to documentation
62 | # for a list of supported languages.
63 | #
64 | # This is also used if you do content translation via gettext catalogs.
65 | # Usually you set "language" from the command line for these cases.
66 | language = 'en'
67 |
68 | # There are two options for replacing |today|: either, you set today to some
69 | # non-false value, then it is used:
70 | #today = ''
71 | # Else, today_fmt is used as the format for a strftime call.
72 | #today_fmt = '%B %d, %Y'
73 |
74 | # List of patterns, relative to source directory, that match files and
75 | # directories to ignore when looking for source files.
76 | exclude_patterns = ['_build']
77 |
78 | # The reST default role (used for this markup: `text`) to use for all
79 | # documents.
80 | #default_role = None
81 |
82 | # If true, '()' will be appended to :func: etc. cross-reference text.
83 | #add_function_parentheses = True
84 |
85 | # If true, the current module name will be prepended to all description
86 | # unit titles (such as .. function::).
87 | #add_module_names = True
88 |
89 | # If true, sectionauthor and moduleauthor directives will be shown in the
90 | # output. They are ignored by default.
91 | #show_authors = False
92 |
93 | # The name of the Pygments (syntax highlighting) style to use.
94 | pygments_style = 'sphinx'
95 |
96 | # A list of ignored prefixes for module index sorting.
97 | #modindex_common_prefix = []
98 |
99 | # If true, keep warnings as "system message" paragraphs in the built documents.
100 | #keep_warnings = False
101 |
102 | # If true, `todo` and `todoList` produce output, else they produce nothing.
103 | todo_include_todos = True
104 |
105 |
106 | # -- Options for HTML output ----------------------------------------------
107 |
108 | # The theme to use for HTML and HTML Help pages. See the documentation for
109 | # a list of builtin themes.
110 |
111 | # The Theme MUST BE AN OPEN SOURCE SPHINX THEME. Contributors outside of
112 | # Adfinis SyGroup AG must be able to build the documentation.
113 | # Developers of Adfinis SyGroup AG can build the documentation using
114 | # make html_adsy
115 | # .. or ..
116 | # make SPHINXOPTS="-D html_theme='adsy'" html
117 | html_theme = 'adsy'
118 |
119 | # Theme options are theme-specific and customize the look and feel of a theme
120 | # further. For a list of options available for each theme, see the
121 | # documentation.
122 | #html_theme_options = {}
123 |
124 | # Add any paths that contain custom themes here, relative to this directory.
125 | html_theme_path = [ 'adsy-sphinx-template.src/html', sphinx_rtd_theme.get_html_theme_path()]
126 | # The name for this set of Sphinx documents. If None, it defaults to
127 | # " v documentation".
128 | #html_title = None
129 |
130 | # A shorter title for the navigation bar. Default is the same as html_title.
131 | #html_short_title = None
132 |
133 | # The name of an image file (relative to this directory) to place at the top
134 | # of the sidebar.
135 | #html_logo = None
136 |
137 | # The name of an image file (relative to this directory) to use as a favicon of
138 | # the docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
139 | # pixels large.
140 | #html_favicon = None
141 |
142 | # Add any paths that contain custom static files (such as style sheets) here,
143 | # relative to this directory. They are copied after the builtin static files,
144 | # so a file named "default.css" will overwrite the builtin "default.css".
145 | html_static_path = ['_static']
146 |
147 | # Add any extra paths that contain custom files (such as robots.txt or
148 | # .htaccess) here, relative to this directory. These files are copied
149 | # directly to the root of the documentation.
150 | #html_extra_path = []
151 |
152 | # If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
153 | # using the given strftime format.
154 | #html_last_updated_fmt = '%b %d, %Y'
155 |
156 | # If true, SmartyPants will be used to convert quotes and dashes to
157 | # typographically correct entities.
158 | #html_use_smartypants = True
159 |
160 | # Custom sidebar templates, maps document names to template names.
161 | #html_sidebars = {}
162 |
163 | # Additional templates that should be rendered to pages, maps page names to
164 | # template names.
165 | #html_additional_pages = {}
166 |
167 | # If false, no module index is generated.
168 | #html_domain_indices = True
169 |
170 | # If false, no index is generated.
171 | #html_use_index = True
172 |
173 | # If true, the index is split into individual pages for each letter.
174 | #html_split_index = False
175 |
176 | # If true, links to the reST sources are added to the pages.
177 | #html_show_sourcelink = True
178 |
179 | # If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
180 | #html_show_sphinx = True
181 |
182 | # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
183 | #html_show_copyright = True
184 |
185 | # If true, an OpenSearch description file will be output, and all pages will
186 | # contain a tag referring to it. The value of this option must be the
187 | # base URL from which the finished HTML is served.
188 | #html_use_opensearch = ''
189 |
190 | # This is the file name suffix for HTML files (e.g. ".xhtml").
191 | #html_file_suffix = None
192 |
193 | # Language to be used for generating the HTML full-text search index.
194 | # Sphinx supports the following languages:
195 | # 'da', 'de', 'en', 'es', 'fi', 'fr', 'hu', 'it', 'ja'
196 | # 'nl', 'no', 'pt', 'ro', 'ru', 'sv', 'tr'
197 | #html_search_language = 'en'
198 |
199 | # A dictionary with options for the search language support, empty by default.
200 | # Now only 'ja' uses this config value
201 | #html_search_options = {'type': 'default'}
202 |
203 | # The name of a javascript file (relative to the configuration directory) that
204 | # implements a search results scorer. If empty, the default will be used.
205 | #html_search_scorer = 'scorer.js'
206 |
207 | # Output file base name for HTML help builder.
208 | htmlhelp_basename = 'virtesk-vdi-doc'
209 |
210 | # -- Options for LaTeX output ---------------------------------------------
211 |
212 | latex_additional_files = [
213 | 'adsy-sphinx-template.src/latex/logo.png',
214 | 'adsy-sphinx-template.src/latex/sphinx.sty',
215 | 'adsy-sphinx-template.src/latex/adsy.sty'
216 | ]
217 |
218 |
219 | latex_elements = {
220 | # The paper size ('letterpaper' or 'a4paper').
221 | 'papersize': 'a4paper',
222 |
223 | # The font size ('10pt', '11pt' or '12pt').
224 | 'pointsize': '10pt',
225 |
226 | # Additional stuff for the LaTeX preamble.
227 | 'preamble' : r"""
228 |
229 | \usepackage{adsy}
230 |
231 |
232 | \renewcommand{\subtitle}{%s}
233 |
234 | """ % (project)
235 |
236 | }
237 |
238 | # Grouping the document tree into LaTeX files. List of tuples
239 | # (source start file, target name, title,
240 | # author, documentclass [howto, manual, or own class]).
241 | latex_documents = [
242 | (master_doc, 'virtesk-vdi.tex', u'Virtesk-VDI Documentation',
243 | u'Simon Neininger, Ueli Isch', 'manual'),
244 | ]
245 |
246 | # The name of an image file (relative to this directory) to place at the top of
247 | # the title page.
248 | #latex_logo = None
249 |
250 | # For "manual" documents, if this is true, then toplevel headings are parts,
251 | # not chapters.
252 | #latex_use_parts = False
253 |
254 | # If true, show page references after internal links.
255 | #latex_show_pagerefs = False
256 |
257 | # If true, show URL addresses after external links.
258 | #latex_show_urls = False
259 |
260 | # Documents to append as an appendix to all manuals.
261 | #latex_appendices = []
262 |
263 | # If false, no module index is generated.
264 | #latex_domain_indices = True
265 |
266 |
267 | # -- Options for manual page output ---------------------------------------
268 |
269 | # One entry per manual page. List of tuples
270 | # (source start file, name, description, authors, manual section).
271 | man_pages = [
272 | (master_doc, 'Virtesk-VDI', u'Virtesk-VDI Documentation',
273 | [author], 1)
274 | ]
275 |
276 | # If true, show URL addresses after external links.
277 | #man_show_urls = False
278 |
279 |
280 | # -- Options for Texinfo output -------------------------------------------
281 |
282 | # Grouping the document tree into Texinfo files. List of tuples
283 | # (source start file, target name, title, author,
284 | # dir menu entry, description, category)
285 | texinfo_documents = [
286 | (master_doc, 'virtesk-vdi', u'Virtesk-VDI Documentation',
287 | author, 'virtesk-vdi', 'Virtesk-VDI is a Open Source VDI solution based on Red Hat Enterprise Virtualization (or Ovirt Virtualization) and the Spice VDI protocol.',
288 | 'Miscellaneous'),
289 | ]
290 |
291 | # Documents to append as an appendix to all manuals.
292 | #texinfo_appendices = []
293 |
294 | # If false, no module index is generated.
295 | #texinfo_domain_indices = True
296 |
297 | # How to display URL addresses: 'footnote', 'no', or 'inline'.
298 | #texinfo_show_urls = 'footnote'
299 |
300 | # If true, do not generate a @detailmenu in the "Top" node's menu.
301 | #texinfo_no_detailmenu = False
302 |
--------------------------------------------------------------------------------
/doc/goldimage.rst:
--------------------------------------------------------------------------------
1 | Windows Goldimage
2 | ===============================
3 |
4 | How to create and seal a Windows Goldimage and use it as a RHEV/Ovirt
5 | VmTemplate.
6 |
7 | --------------
8 |
9 | Introduction
10 | ------------
11 |
12 | The goal is to use one master VM (the "Goldimage") as a blueprint for
13 | creating/cloneing alot of VMs.
14 |
15 | If a Windows 7 VM is simply cloned directly, all identifiers inside
16 | remain the same. This includes the Active Directory SID and GUID. Those
17 | identifiers should be unique - but cloneing violates the uniqueness
18 | property. Therefore, direct cloneing will cause problems in Active
19 | Directory environments. This can be avoided by using the
20 | Sysprep/Autounattend process described below.
21 |
22 | Prerequisites
23 | -------------
24 |
25 | This article covers Goldimages based on Windows 7 x64 Professional in an
26 | Active Directory (or Samba4) environment. The Professional Edition of
27 | Windows 7 is nessesary for usage in Active Directory (or Samba4)
28 | domains.
29 |
30 | Initial Goldimage
31 | -----------------
32 |
33 | Steps:
34 |
35 | - Create VM + Install Win7 x64 Professional
36 |
37 | - Using a thin-provisioned disk in RHEV/Ovirt is recommended
38 |
39 | - Install virtio + spice drivers, install guest agent
40 | - Install all Windows Updates
41 | - Configure as you like, install Programs
42 |
43 | Common Settings:
44 | ~~~~~~~~~~~~~~~~
45 |
46 | Registry Keys:
47 |
48 | ::
49 |
50 | rem Tell Windows where to find its Unattended Setup Config file. Common values include a:\sysprep.inf, a:\Autounattend.xml, a:\Unattend.xml. For virtesk-vdi, a:\sysprep.inf should be used.
51 | rem See also:
52 | rem * /etc/ovirt-engine/osinfo.conf.d/ on RHEV/Ovirt Manager
53 | rem os.windows_7.sysprepFileName.value = sysprep.inf
54 | rem os.windows_7x64.sysprepFileName.value = sysprep.inf
55 | reg add "HKEY_LOCAL_MACHINE\SYSTEM\SETUP" /v UnattendFile /t REG_SZ /d a:\sysprep.inf /f
56 |
57 | rem Disable TCP Task-Offloading.
58 | rem Useful to avoid problems with incorrect udp checksums regarding virtio-net + dhcp
59 | reg add "HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\TCPIP\Parameters" /v DisableTaskOffload /t REG_DWORD /d 1 /f
60 |
61 | Ovirt OS info settings
62 | ----------------------
63 |
64 | Virtesk-VDI puts the Unattend Setup Config file into the file
65 | ``a:\sysprep.inf`` on a `virtual floppy disk `__.
66 | To make sure windows finds the floppy there, setting the windows
67 | registry key as described above is sufficient. However, if you wanna use
68 | the same Goldimage VmTemplate for other purposes (Ovirt UserPortal /
69 | PowerUserPortal, manual creation of VMs, manual creation of Ovirt
70 | VmPools), then the following settings on your RHEV / Ovirt Manager are
71 | needed to make sure that RHEV / Ovirt will put their version of the
72 | Unattended Setup Config file into the right location:
73 |
74 | ::
75 |
76 | mkdir -p /etc/ovirt-engine/osinfo.conf.d/
77 | mkdir -p /etc/ovirt-engine/sysprep/
78 | cp /usr/share/ovirt-engine/conf/sysprep/sysprep.w7x64 /etc/ovirt-engine/sysprep/sysprep.w7x64
79 | vim /etc/ovirt-engine/sysprep/sysprep.w7x64 # adjust settings
80 |
81 | /etc/ovirt-engine/osinfo.conf.d/10-sysprep.properties
82 |
83 | ::
84 |
85 | os.windows_7x64.sysprepPath.value = /etc/ovirt-engine/sysprep/sysprep.w7x64
86 |
87 | ## Workaround for https://bugzilla.redhat.com/show_bug.cgi?id=1192495
88 | os.windows_7x64.sysprepFileName.value = sysprep.inf
89 |
90 | Restart ovirt-engine:
91 |
92 | ::
93 |
94 | service ovirt-engine restart
95 |
96 | Sysprep
97 | -------
98 |
99 | The following step will generalize your Goldimage VM. You will
100 | "partially loose" your Goldimage VM, so might wanna create a VM
101 | snapshot beforehand.
102 | Sysprep can be run as local Administrator or as a Domain
103 | Administrator. Please disconnect all network shares - they might cause
104 | problems when generalizing.
105 |
106 | Programm: ``C:\Windows\system32\sysprep\sysprep.exe``
107 |
108 | Please choose the following options:
109 |
110 | English:
111 |
112 | ::
113 |
114 | System Cleanup Action:
115 | Enter Out-of-Box-Experience (OOBE)
116 | [X] Generalize
117 | Shutdown Options:
118 | Shutdown
119 |
120 | German:
121 |
122 | ::
123 |
124 | Systembereinigungsaktion:
125 | Out-of-Box-Experience (OOBE) für System aktivieren
126 | [X] Veralgemeinern
127 | Optionen für Herunterfahren
128 | Herunterfahren
129 |
130 | Afterwards, the VM will be generalized and then turned off. Then the VM
131 | is ready to create a RHEV/Ovirt VmTemplate.
132 |
133 | RHEV/Ovirt VmTemplate
134 | ---------------------
135 |
136 | In RHEV/Ovirt WebAdmin, right-click on the VM and create a new
137 | VmTemplate. Then, adjust
138 | `virtesk-vm-rollout.conf `__
139 | to use the new template: ``template_name = myNewVmTemplate``.
140 |
141 | Rolling out virtual rooms
142 | -------------------------
143 |
144 | Now you can use the `tools for virtual rooms `__
145 | to create VMs based on this Goldimage.
146 |
147 | ``virtesk-vm-rollout`` will run `Windows Unattended
148 | Setup `__.
149 |
150 | Re-Use Goldimage
151 | ----------------
152 |
153 | To Re-Use your Goldimage VM, take the following steps:
154 |
155 | - Restore Goldimage VM to the snapshot that was created before sysprep
156 | - Install Updates, adjust configuration, install programs as you like
157 | - Create a fresh Snapshot
158 | - Run sysprep again to create a new RHEV/Ovirt VmTemplate
159 |
160 | Long snapshot chains should be avoided, delete old snapshots from time
161 | to time.
162 |
163 | Alternative approach:
164 |
165 | - Roll out a virtual room based on the last Goldimage
166 | - Take a VM out of this virtual room and use it as new Goldimage
167 | - Install Updates, adjust configuration, install programs as you like
168 | - Run sysprep again to create a new RHEV/Ovirt VmTemplate
169 | - Optional: Delete Goldimage VM
170 |
--------------------------------------------------------------------------------
/doc/index.rst:
--------------------------------------------------------------------------------
1 | .. Virtesk-VDI documentation master file, created by
2 | sphinx-quickstart2 on Thu Mar 31 12:24:51 2016.
3 | You can adapt this file completely to your liking, but it should at least
4 | contain the root `toctree` directive.
5 |
6 | Virtesk-VDI
7 | ============
8 |
9 | Contents:
10 |
11 | .. toctree::
12 | :maxdepth: 4
13 |
14 | README.rst
15 | architecture.rst
16 | virtual_rooms.rst
17 | thinclients.rst
18 | misc.rst
19 |
20 |
21 | Indices and tables
22 | ==================
23 |
24 | * :ref:`genindex`
25 | * :ref:`modindex`
26 | * :ref:`search`
27 |
28 |
--------------------------------------------------------------------------------
/doc/ipxe-image.rst:
--------------------------------------------------------------------------------
1 | .. |br| raw:: html
2 |
3 |
4 |
5 | iPXE image for cdroms and usb flash drives
6 | ========================================================
7 |
8 |
9 | Introduction
10 | ------------
11 |
12 | In some environments, it is not feasible to do a network install of thinclients using PXE. |br|
13 | For this cases, an iPXE image for cdroms / usb flash drives can be
14 | built.
15 |
16 | The iPXE image contains an embedded configuration file pointing to your infrastructure server. |br|
17 | It will chainload the network bootloader (pxelinux) configured on your infrastructure server using http.
18 |
19 | Creating an iPXE image:
20 | -----------------------
21 |
22 | Upstream documentation: http://ipxe.org/embed
23 |
24 | virtesk-vdi.ipxe:
25 |
26 | ::
27 |
28 | #!ipxe
29 |
30 | echo
31 | echo Virtesk-VDI thinclient rollout iPXE compatibility image
32 |
33 |
34 | echo
35 | echo Configuring DHCP...
36 | dhcp
37 |
38 | # Option 209 pxelinux.configfile
39 | # Specify the initial PXELINUX configuration file name,
40 | # which may be qualified or unqualified.
41 |
42 | # Option 210 pxelinux.pathprefix
43 | # Specify the PXELINUX common path prefix, instead of deriving
44 | # it from the boot file name. This almost certainly needs to
45 | # end in whatever character the TFTP server OS uses as a
46 | # pathname separator, e.g. slash (/) for Unix.
47 |
48 | # Path Prefix for PXELINUX:
49 | # set 210:string tftp://infrastructure-server/pxelinux/
50 | set 210:string http://infrastructure-server/tftpboot/pxelinux/
51 |
52 | echo
53 | prompt --key 0x02 --timeout 2000 Press Ctrl-B for the iPXE command line... && shell ||
54 |
55 | echo
56 | echo Chainloading pxelinux.0 ...
57 | chain http://infrastructure-server/tftpboot/pxelinux/pxelinux.0
58 |
59 | Fetching source and build the image:
60 |
61 | ::
62 |
63 | git clone git://git.ipxe.org/ipxe.git
64 | cd ipxe.git/src
65 | make bin/ipxe.usb EMBED=/path/to/virtesk-vdi.ipxe
66 | make bin/ipxe.iso EMBED=/path/to/virtesk-vdi.ipxe
67 |
68 | Afterwards, the images will be available at:
69 |
70 | ::
71 |
72 | ipxe.git/src/bin/ipxe.usb
73 | ipxe.git/src/bin/ipxe.iso
74 |
75 | Writing the images to cdrom / usb flash drive
76 | ---------------------------------------------
77 |
78 | Burning cdrom:
79 |
80 | ::
81 |
82 | wodim -dao ipxe.iso
83 |
84 | Writing image to usb flash drive
85 |
86 | ::
87 |
88 | dd if=ipxe.usb of=/dev/sdc bs=1M; sync
89 |
90 | Replace ``/dev/sdc`` with the device where the image shall be written
91 | to. Data on ``/dev/sdc`` will be destroyed.
92 |
93 | When using an usb flash drive to roll out thinclients, please make sure you remove it as soon as the pxelinux menu is displayed. Otherwise, the kickstart installation would overwrite your usb flash drive.
94 |
95 |
96 |
--------------------------------------------------------------------------------
/doc/libusbredir-patching.rst:
--------------------------------------------------------------------------------
1 | .. |br| raw:: html
2 |
3 |
4 |
5 | USB Redirect: avoiding USB reset
6 | ================================
7 |
8 | Solution to avoid problems that might occour when redirecting usb devices over Spice. |br|
9 | Only few devices are affected, most devices work without the patches below.
10 |
11 |
12 | Introduction
13 | ------------
14 |
15 | Spice used libusbredir to redirect usb devices.
16 |
17 | Normally, a reset command is issued to the device before it is redirected.
18 | This works fine for 99% of all avaiable usb devices. |br|
19 | However, some problematic devices have issues with usb resets. Redirect fails with the following error message:
20 |
21 | ::
22 |
23 | Could not redirect Electronics For Imaging, Inc. [hex]
24 | Device: error resetting device: LIBUSB_ERROR_NOT_FOUND.
25 |
26 | By adding those devices to an internal blacklist of libusbredir, we can prevent usb reset for them. This way, virtesk-vdi can successfully redirect those devices. However, libusbredir must be patched on all thinclients. The following steps explain how the patching is done.
27 |
28 |
29 | Setting up an rpm build environment
30 | -----------------------------------
31 |
32 | Build Machine: A test machine running the same fedora version as your
33 | thinclients.
34 |
35 | Installing build-tools:
36 |
37 | ::
38 |
39 | # dnf install rpm-build gcc make rpmdevtools rpmlint
40 |
41 | Installing build dependencies:
42 |
43 | ::
44 |
45 | # dnf install libusb1-devel
46 |
47 | Setting up rpm build environment
48 |
49 | ::
50 |
51 | $ mkdir -p ~/rpmbuild/{BUILD,RPMS,SOURCES,SPECS,SRPMS}
52 | $ echo '%_topdir %(echo $HOME)/rpmbuild' > ~/.rpmmacros
53 |
54 | Downloading usbredir sources:
55 |
56 | ::
57 |
58 | $ dnf download --enablerepo=fedora-source --source usbredir
59 |
60 | Unpacking sources into your local RPM Build environment:
61 |
62 | ::
63 |
64 | $ rpm -i usbredir-0.7-3.fc22.src.rpm
65 |
66 | The rpm command above will unpack the following files into your rpm
67 | build environment:
68 |
69 | - ~/rpmbuild/SOURCES/usbredir-0.7.tar.bz2
70 | - ~/rpmbuild/SPECS/usbredir.spec
71 |
72 |
73 | Patching libusbredir
74 | --------------------
75 |
76 | First, we add a patch file, then we tell rpmbuild to apply our patch
77 | before building the package.
78 |
79 | ~/rpmbuild/SOURCES/usbredir-blacklist.patch
80 |
81 | ::
82 |
83 | diff -urN usbredir-0.7/usbredirhost/usbredirhost.c foo/usbredirhost/usbredirhost.c
84 | --- usbredir-0.7/usbredirhost/usbredirhost.c 2013-11-19 13:52:36.000000000 +0100
85 | +++ foo/usbredirhost/usbredirhost.c 2015-12-21 15:19:16.277973330 +0100
86 | @@ -139,6 +139,7 @@
87 |
88 | static const struct usbredirhost_dev_ids usbredirhost_reset_blacklist[] = {
89 | { 0x1210, 0x001c },
90 | + { 0x2650, 0x1311 },
91 | { -1, -1 } /* Terminating Entry */
92 | };
93 |
94 | In the Spec-File ``~/rpmbuild/SPECS/usbredir.spec`` we have to add the
95 | following line to make sure that rpmbuild will knows about our patch:
96 |
97 | ::
98 |
99 | Patch0: usbredir-blacklist.patch
100 |
101 | Context / location in file:
102 |
103 | ::
104 |
105 | URL: http://spice-space.org/page/UsbRedir
106 | Source0: http://spice-space.org/download/%{name}/%{name}-%{version}.tar.bz2
107 | Patch0: usbredir-blacklist.patch
108 | BuildRequires: libusb1-devel >= 1.0.9
109 |
110 | In the Spec-File ``~/rpmbuild/SPECS/usbredir.spec`` we have to add the
111 | following line to make sure that rpmbuild will apply patches:
112 |
113 | ::
114 |
115 | %patch0 -p1
116 |
117 | Context / location in file:
118 |
119 | ::
120 |
121 | %prep
122 | %setup -q
123 |
124 | %patch0 -p1
125 |
126 | %build
127 | %configure --disable-static
128 | make %{?_smp_mflags} V=1
129 |
130 | Changing the package version: change the spec-file from
131 |
132 | ::
133 |
134 | Name: usbredir
135 | Version: 0.7
136 | Release: 3%{?dist}
137 |
138 | To:
139 |
140 | ::
141 |
142 | Name: usbredir
143 | Version: 0.7
144 | Release: 99mypackage3%{?dist}
145 |
146 |
147 |
148 | Building the RPM package:
149 | -------------------------
150 |
151 | ::
152 |
153 | rpmbuild -ba ~/rpmbuild/SPECS/usbredir.spec
154 |
155 | Afterwards, the RPMs will be available at:
156 |
157 | ::
158 |
159 | ~/rpmbuild/RPMS/x86_64/
160 |
161 | Testing: Installing RPM manually:
162 | ---------------------------------
163 |
164 | On a thinclient, run the following command:
165 |
166 | ::
167 |
168 | # dnf install usbredir-0.7-99mypackage3.fc22.x86_64.rpm
169 |
170 | Now the thinclient should be able to redirect the device.
171 |
--------------------------------------------------------------------------------
/doc/misc.rst:
--------------------------------------------------------------------------------
1 | Misc
2 | ====
3 |
4 | .. toctree::
5 | :maxdepth: 3
6 |
7 | compatibility.rst
8 | sftp-floppy-upload.rst
9 | spice-disconnect-actions.rst
10 | bugs.rst
11 | security.rst
12 | license.rst
13 |
--------------------------------------------------------------------------------
/doc/quality_control.rst:
--------------------------------------------------------------------------------
1 | Quality Control of virtual rooms
2 | ==============================================
3 |
4 | Introduction
5 | ------------
6 |
7 | A lot of problems can occour during Windows Unattended Setup:
8 |
9 | - Network, DNS, DHCP, Firewall-Problems
10 | - Network adapter: wrong name, wrong Windows-Firewall-Zone, ...
11 | - Problems with Active Directory SRV-Records
12 | - Problems with Windows Domain Join
13 | - Infrastructure overload can occour if many VMs get joined at the same
14 | time or many CIFS-Shares are accessed at once.
15 | - ...
16 |
17 | It is important to detect those problems early, so that a solution can
18 | be found before users are affected.
19 | A system administrator has to deal with alot of VMs, therefore an
20 | efficient way for quality control is necessary.
21 |
22 | Windows Unattended Setup: Copying logfiles
23 | ------------------------------------------
24 |
25 | First, we wanna introduce a ``autounattend-firstlogon.cmd``-Script
26 | that will be run inside every Win7-VM that is rolled out.
27 | The script is running in the *Firstlogon-Phase* in Windows Unattended
28 | Setup. It will be used for mounting shares, copying logfiles, ...
29 |
30 | Parameters
31 | ~~~~~~~~~~
32 |
33 | - **someserver**: CIFS-Server (Windows or Samba) containing two
34 | CIFS-Shares:
35 |
36 | - **scriptshare**: CIFS-Share, where ``autounattend-firstlogon.cmd``
37 | is located.
38 | - **logfileshare**: CIFS-Share for putting logfiles.
39 | - **username@windowsdomain** and **password**: Credentials to
40 | access those CIFS-Shares
41 |
42 | Autounattend-production.xml.template
43 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
44 |
45 | We need to make sure that our new ``autounattend-firstlogon.cmd``-Script
46 | will be called at the right time:
47 |
48 | ::
49 |
50 | ...
51 |
52 |
53 |
54 | net use Y: \\someserver\scriptshare /persistent:no /user:username@windowsdomain password
55 | false
56 | 20
57 |
58 |
59 | cmd /c Y:\autounattend-firstlogon.cmd ${scripttime} ${ComputerName} 1> C:\autounattend-firstlogon.log 2>&1
60 | false
61 | 21
62 |
63 |
64 | shutdown /p
65 | false
66 | 50
67 |
68 |
69 |
70 | ...
71 |
72 | ``autounattend-firstlogon.cmd`` will be called with two parameters,
73 | the *scripttime* and the *ComputerName*. They will be used later for
74 | storing the logfiles in a well-organized folder structure.
75 | Output will be redirected to ``C:\autounattend-firstlogon.log``.
76 |
77 |
78 | autounattend-firstlogon.cmd
79 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~
80 |
81 | Location: ``\\someserver\scriptshare\autounattend-firstlogon.cmd``
82 |
83 | ::
84 |
85 | rem Parameters passed by Autounattend.xml:
86 | set DATETIME=%1
87 | set OWSNAME=%2
88 |
89 | net use R: \\someserver\report
90 |
91 | mkdir R:\%DATETIME%-%OWSNAME%
92 |
93 |
94 | xcopy C:\windows\Panther\*.* R:\%DATETIME%-%OWSNAME% /K /E /I /H /Y
95 |
96 | copy C:\Windows\debug\NetSetup.LOG R:\%DATETIME%-%OWSNAME%
97 |
98 | copy C:\Windows\Temp\Domainjoin.log R:\%DATETIME%-%OWSNAME%
99 | copy C:\Windows\Temp\Domainjoin.log.2 R:\%DATETIME%-%OWSNAME%
100 |
101 | echo %COMPUTERNAME% > R:\%DATETIME%-%OWSNAME%\_SELF-FQDN-%OWSNAME%
102 |
103 | copy C:\autounattend-firstlogon.log R:\%DATETIME%-%OWSNAME%
104 |
105 | net use R: /delete /yes
106 |
107 | **Remark:** ``net use R: ...`` is the second time a CIFS-Share is mounted.
108 | Windows stores Credentials, this is why we do not need to pass
109 | username/password.
110 |
111 | Analyzing Logfiles
112 | ~~~~~~~~~~~~~~~~~~
113 |
114 | Windows Domain Join
115 | ^^^^^^^^^^^^^^^^^^^
116 |
117 | Logfile: ``C:\\Windows\panther\UnattendGC\setupact.log``
118 |
119 | Search terms:
120 |
121 | ::
122 |
123 | DJOIN
124 | 0x54a
125 | Unattended Join: NetJoinDomain succeeded
126 |
127 | Checking alot of logfiles: commands to analyze windows domain joins using the logfiles
128 | archived on the *logfile*-CIFS-Share:
129 |
130 | Coarse overview:
131 |
132 | ::
133 |
134 | grep -c "Unattended Join: NetJoinDomain succeeded" 2014-08-04-*/UnattendGC/setupact.log
135 |
136 | Result: 1 if joined successfully, 0 otherwise.
137 |
138 | How many times did the windows client try to join into the domain?
139 |
140 | ::
141 |
142 | grep -c 0x54a 2014-08-04-*/UnattendGC/setupact.log
143 |
144 | In infrastructure overload situations, the windows client retries 80-85
145 | times and then gives up.
146 |
147 | Details for a single windows client:
148 |
149 | ::
150 |
151 | grep DJOIN 2014-08-04-1216-test05-vd01/UnattendGC/setupact.log
152 |
--------------------------------------------------------------------------------
/doc/screenshots/spice-disconnect-actions.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adfinis/virtesk/2a9f9fcb705172663efbff996df675f511a49f3f/doc/screenshots/spice-disconnect-actions.png
--------------------------------------------------------------------------------
/doc/security.rst:
--------------------------------------------------------------------------------
1 | .. |br| raw:: html
2 |
3 |
4 |
5 | Security considerations
6 | =====================================
7 |
8 |
9 | Virtual machine isolation
10 | -------------------------
11 |
12 | Virtual machines can be isolated by putting them into different Ovirt
13 | networks and by applying the usual network security principles.
14 |
15 | Thinclients
16 | -----------
17 |
18 | **Ovirt REST-API**: ``Thinclient ---> Ovirt Manager (tcp/443)``
19 |
20 | - HTTPs connection; Server certificate is verified. Ovirt AAA is used
21 | to authenticate the technical user ``ovirt.thinclient@domain`` used
22 | by thinclients.
23 | - Used to get access parameters to assigned VM. Only VDI-VMs can be
24 | accessed by thinclients, other VMs are protected by Ovirt access
25 | control rules.
26 |
27 | **Spice**: ``Thinclient ---> qemu-kvm (tcp/5900-6100)``
28 |
29 | - SSL connections; Certificate fingerprint is retrieved using REST-API,
30 | fingerprint is verified. **Spice Ticketing** is used by ``qemu-kvm``
31 | to determine if the client may access.
32 |
33 | **Postgres Database**:
34 | ``Thinclient ---> infrastructure server (tcp/5432)``
35 |
36 | - SSL connection, client verifies server certificate if configured to
37 | do so.
38 | - Server verifies client identity using username/password.
39 | - Thinclients have only limited, read only database access.
40 |
41 | **Remote logging**: ``Thinclient ---> infrastructure server (tcp/512)``
42 |
43 | - Remote logging is not secure. All logging is sent in plain-text over
44 | the network.
45 | - No authentication and no encryption is done.
46 | - The thinclients are logging sensitive data over the network.
47 | - Mitigation strategies:
48 |
49 | - Put thinclients in a protected network (see below).
50 | - Disable remote logging. Thinclients work fine with local logging
51 | only - however, remote logging is useful for problem analysis.
52 |
53 | Thinclients do need to store credentials. If those credentials leak, the security concept will break down. The thinclients themself won't leak their credentials (exception: remote logging). However, common network boot techiques usually require all code and configuration to be accessible unauthenticated, where an attacker might retrieve them - see below.
54 |
55 |
56 | PXE Rollout
57 | -----------
58 |
59 | .. note:: PXE is insecure.
60 |
61 | Network booting is very convinient. However, PXE is completely insecure.
62 |
63 | Recommendations for situations where both security and PXE are needed:
64 |
65 | - **Physical network protection:** The network hardware (switches,
66 | servers, ...) should be physically protected. Only trusted persons
67 | should be allowed to administrate switches or to plug cables into
68 | switches.
69 | - **Dedicated rollout network:** A dedicated rollout network is used
70 | for rollout. System administrators need to switch VLANs (or cables)
71 | for rollouts. Only devices in the rollout network are allowed to
72 | access sensitive data on the infrastructure server.
73 | - **Mixed network, locked-down:** A mixed (trusted and untrusted
74 | devices, some switch ports accessible by users) is used for both
75 | daily operation and for rollout. Techiques like private VLANs,
76 | MAC-to-Swichport binding, physical protection of cables and
77 | switchports used by thinclients, static ARP table entries and static
78 | IP adresses are used for network protection. Then, access to the
79 | infrastructure server (PXE, kickstart) can be granted based on IP
80 | access rules.
81 |
82 | Kexec Rollout
83 | -------------
84 |
85 | In the current implementation of ``tc_kexec``, many mechanisms used for
86 | PXE boot are re-used. Therefore, ``tc_kexec`` is affected by the same
87 | security problems.
88 |
89 | A secure variant of ``tc_kexec`` could be engineered upon request. The
90 | kernel and initramfs can be transported in a secure way; the kickstart
91 | file, GnuPG keys and SSL CA certificates can be appended to the
92 | initramfs.
93 |
94 | Multiple thinclient environments
95 | --------------------------------
96 |
97 | If only some, but not all thinclients need to be protected, then the
98 | security recommendations listed above can be applied only for those
99 | thinclients. Please make sure that for this usecase, a dedicated
100 | technical user ``ovirt.secure-thinclients@domain`` is used for the
101 | thinclients that need protection.
102 |
--------------------------------------------------------------------------------
/doc/start-and-stop-management.rst:
--------------------------------------------------------------------------------
1 | Start and Stop management of virtual rooms
2 | ========================================================
3 |
4 | Introduction
5 | ------------
6 |
7 | Running VMs do consume ressources, in particular memory. This article
8 | describes start/stop behavior and ways to save ressources by shutting
9 | down unused VMs.
10 |
11 | This article was written with Ovirt 3.4/3.5 in mind.
12 |
13 | Ovirt 3.6 introduces new features for shutting down VMs upon spice disconnect.
14 | Those features can be used as an alternative to the approach described
15 | here.
16 |
17 | There is a `backport `__ of the spice disconnect action features for Ovirt 3.5.
18 |
19 | Start/Stop behaviour
20 | --------------------
21 |
22 | Thinclients startup: VM auto-launch
23 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
24 |
25 | Whenever a TC is started, it checks if the assigned VM is already
26 | running. If not, it is started automatically.
27 |
28 | No configuration is necessary.
29 |
30 | Thinclient shutdown: VM auto-shutdown
31 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
32 |
33 | When a TC shuts down, it will also shutdown the assigned VM.
34 |
35 | This can be configured individually for each TC in the database table
36 | ``timed_thinclient_to_vm_mapping``.
37 |
38 | When a TC reboots, nothing special happens to the assigned VM. No
39 | shutdown or reboot signal is sent to the assigned VM. It is implemented
40 | this way because a TC reboot usually is alot faster than a VM reboot.
41 |
42 | Thinclient auto-shutdown
43 | ~~~~~~~~~~~~~~~~~~~~~~~~
44 |
45 | Unimplemented: When there is no mouse/keyboard interaction for some
46 | time, the thinclient will automatically shut down. This feature isn't
47 | available yet, but can be implemented upon request. A more advanced
48 | solution would also contain a shutdown-inhibit-feature, to avoid
49 | shutdowns when watching movies or when presenting slides.
50 |
51 | Tools for start and shutdown
52 | ----------------------------
53 |
54 | Virtual rooms: startup and shutdown
55 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
56 |
57 | Whole virtual rooms can be started and shut down using
58 | ``virtesk-virtroom-start`` and ``virtesk-virtroom-shutdown``.
59 |
60 | Those tools are well-suited for unattended use in cronjobs. Cronjobs can
61 | be configured similary to
62 | `vm-reset-cronjobs `__.
63 |
64 | Virtual rooms: startup after rollout and after reset
65 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
66 |
67 | The startup behavior after rollout and after reset can be configured
68 | using the config directives ``rollout_startvm`` and ``reset_startvm`` as
69 | described
70 | `here `__.
71 |
72 | Thinclient remote-startup using Wake-On-LAN
73 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
74 |
75 | Thinclient remote-startup is supported using Ethernet Wake-On-Lan if the
76 | hardware supports it and if BIOS and network are configured properly.
77 |
78 | Standard wake-up-tools (e.g. ``ether-wake``, ``wol``, ...) can be used
79 | to trigger a thinclient startup.
80 |
81 | Thinclient remote-shutdown
82 | ~~~~~~~~~~~~~~~~~~~~~~~~~~
83 |
84 | Thinclient remote-shutdown is supported using
85 | `virtesk-tc-tools `__.
86 |
87 | Suggestions for start and stop management
88 | -----------------------------------------
89 |
90 | Workplaces used often
91 | ~~~~~~~~~~~~~~~~~~~~~
92 |
93 | Configuration:
94 |
95 | - VM shutdown upon TC shutdown: disabled
96 | - VM startup after reset: ``reset_startvm = Auto``
97 | - Every Friday night: shutdown VMs using ``virtesk-virtroom-shutdown``
98 |
99 | Effect:
100 |
101 | - VMs will always be running ===> TC startup very fast (except monday
102 | morning)
103 | - Resource consumption / memory usage: mostly constant
104 | - Doesn't consume resources for unused workplaces
105 | - Electricity savings on weekends
106 |
107 | Workplaces for Power-Users
108 | ~~~~~~~~~~~~~~~~~~~~~~~~~~
109 |
110 | Same as above, but without or with less resets. Because the VM will be
111 | up the whole week, power users can leave their programms running during
112 | the week.
113 |
114 | Workplaces used infrequently
115 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
116 |
117 | Configuration:
118 |
119 | - VM shutdown upon TC shutdown: enabled
120 | - VM startup after reset: ``reset_startvm = Never``
121 |
122 | Effect:
123 |
124 | - Unused TCs won't consume any resources
125 | - Less resources used on average
126 | - Less electricity used on average
127 | - TC startup is slower (VM has to be started first)
128 | - More dynamic scenario. Requires carefull monitoring of RHEV/Ovirt
129 | events and resources.
130 | - Resource reserves are needed for peak situations
131 |
--------------------------------------------------------------------------------
/doc/stateless_and_snapshot_features.rst:
--------------------------------------------------------------------------------
1 | Stateless and snapshot features
2 | =============================================
3 |
4 | Features to reset virtual rooms to a well-defined, known state
5 |
6 | --------------
7 |
8 | Introduction
9 | ------------
10 |
11 | Situation:
12 |
13 | - Large number of clearly-defined managed workplaces
14 | - Users and programs might modify workplaces and leave some debris
15 | after work
16 | - Workplace modifications and debris shall be avoided
17 | - Divergence of workplaces shall be avoided
18 |
19 | Virtesk-VDI provides two solutions:
20 |
21 | - Snapshots: A snapshot will be created for every VM after initial
22 | rollout. A cronjob resets the virtual rooms to the snapshot state
23 | every night.
24 | - Stateless VMs: A snapshot will be created at VM startup; The VM will
25 | be reset to snapshot state after shutdown.
26 |
27 | The approach using snapshots is the preferred solution.
28 |
29 | Snapshots
30 | ---------
31 |
32 | How it works:
33 |
34 | - Virtual rooms are created using virtesk-virtroom-rollout. After
35 | rollout, virtesk-virtroom-rollout automatically creates a snapshot
36 | for every VM.
37 | - Every night, virtesk-virtroom-reset is run by cronjob. This tool
38 | will stop the VMs, reset them back to the snapshot that was created
39 | by virtesk-virtroom-rollout, and starts the VMs again. During the
40 | reset phase at night, the VMs / Workplaces are unavailable.
41 | - VMs are statefull, but they will be reset every night
42 |
43 | Background: Snapshot operations are expensive, in particular when doing
44 | alot of snapshot operations at once. Snaphosts in RHEV/Ovirt also
45 | sometimes were buggy and problematic in the past. During snapshot
46 | operations, the VM cannot be used, that is, the user has to wait for the
47 | operations to complete.
48 |
49 | This solutions avoids those problems:
50 |
51 | - Snapshot creation is only done once, after initial rollout. By
52 | inserting short breaks where necessary, the tools do avoid situations
53 | where RHEV/Ovirt is overloaded by to many parallel snapshot
54 | operations.
55 | - Reset to snapshot date is done during the night, when workplaces are
56 | unused.
57 | - No snapshot operations are done during daytime. Therefore, the users
58 | do not have to wait for snapshot operations. Statefull VMs start alot
59 | faster than stateless VMs, and they are also more reliable and less
60 | ressource-consuming.
61 | - VM startup is fast, even in peak situations in a classroom where 20
62 | VMs might start at once.
63 |
64 | Configuration: ``virtesk-vm-rollout.conf``:
65 |
66 | ::
67 |
68 | [room room01]
69 | [[student_vms]]
70 | # The snapshot and stateless features are mutually exclusive and cannot be used together.
71 | stateless = False
72 |
73 | # Used for snapshot creation after initial rollout
74 | snapshot_description = "Automatic snapshot after virtesk-vmrollout, IP=${ip}/${netmask_as_suffix}, scripttime=${scripttime}"
75 |
76 | # Used for reset
77 | reset_to_snapshot_regex = "Automatic snapshot after virtesk-vmrollout, .*"
78 |
79 | # Shall VMs be started after reset?
80 | reset_startvm = Auto
81 |
82 | To use the snapshot feature, ``snapshot_description`` and
83 | ``reset_to_snapshot_regex`` must be configured. The first parameter is
84 | used during rollout of virtual rooms, the second is used to identify the
85 | snapshot the VMs to.
86 |
87 | ``reset_startvm = Always/Auto/Never`` determines if VMs shall be started
88 | after reset. When set to ``Auto``, the VMs will be started if they were
89 | running before reset.
90 |
91 | To disable the snapshot feature, set ``snapshot_description = ""`` and
92 | deactivate the reset cronjob.
93 |
94 | Automatic reset every night
95 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~
96 |
97 | Cronjob: ``/etc/cron.d/virtesk-vdi-reset-virtrooms``: Runs reset script
98 | at 01:00 AM every night:
99 |
100 | ::
101 |
102 | SHELL=/bin/sh
103 | PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/opt/virtesk-vdi.src/virtesk-vm-rollout/
104 | # m h dom mon dow command
105 | 00 01 * * * root /etc/virtesk-vdi/reset-virtrooms-every-night.sh > /dev/zero
106 |
107 | Please make sure to add your virtesk installation directory to
108 | ``$PATH``, like ``/opt/virtesk-vdi.src/virtesk-vm-rollout/`` above.
109 |
110 | See also: ``man 5 crontab``.
111 |
112 | Reset-Script: ``/etc/virtesk-vdi/reset-virtrooms-every-night.sh``:
113 |
114 | ::
115 |
116 | #!/bin/bash
117 | # Reset virtual rooms to snapshots
118 |
119 | virtesk-virtroom-reset test01
120 | virtesk-virtroom-reset test02
121 | virtesk-virtroom-reset test03
122 | virtesk-virtroom-reset test04
123 |
124 | Please add ``virtesk-virtroom-reset `` for every virtual room
125 | that shall be reset.
126 |
127 | Making it executable:
128 | ``chmod +x /etc/virtesk-vdi/reset-virtrooms-every-night.sh``.
129 |
130 | Stateless
131 | ---------
132 |
133 | Stateless VMs are a built-in feature of RHEV/Ovirt: Before starting a
134 | stateless VM, a snapshot is created. After VM shutdown, the snapshot is
135 | discarded, e.g. the VM is reset to the state before launch.
136 |
137 | Virtesk-vdi supports stateless VMs by setting the stateless flag after
138 | rollout. Afterwards, RHEV/Ovirt is responsible for snapshot management.
139 |
140 | Advantages:
141 |
142 | - Builtin feature of RHEV/Ovirt
143 |
144 | Drawbacks:
145 |
146 | - VM are starting slower (50-80 seconds until a spice session can be
147 | opened, compared to 15-30 seconds for statefull VMs)
148 | - Consumes more resources
149 | - Somewhat error prone (Bugs in snapshot implementation of RHEV/Ovirt)
150 | - Other virtesk-vdi code (Thinclients, Start/Stop - Management, ...)
151 | handle stateless VMs like statefull VMs. No special error handling is
152 | implemented for stateless VMs. This might be necessary in the
153 | following areas: VM launch time, virtesk-virtroom-delete,
154 | virtesk-virtroom-start, virtesk-virtroom-shutdown, VM startup upon
155 | TC startup, VM shutdown upon TC shutdown. In general, stateless VMs
156 | should run fine, but problems might occour when starting/stopping
157 | stateless VMs too fast or too often in a row.
158 | - Peak situations: When starting or stopping alot of stateless VMs at
159 | once, then RHEV/Ovirt might handle some operations sequentially. For
160 | example in a classroom situation, if the teacher tells the whole
161 | class to start their thinclients, startup might take longer than when
162 | starting a single thinclient.
163 |
164 | Configuration: ``virtesk-vm-rollout.conf``:
165 |
166 | ::
167 |
168 | [room room01]
169 | [[student_vms]]
170 | stateless = True
171 |
172 | # The snapshot and stateless features are mutually exclusive and cannot be used together.
173 | snapshot_description = ""
174 |
--------------------------------------------------------------------------------
/doc/switching-virtual-rooms.rst:
--------------------------------------------------------------------------------
1 | Switching virtual rooms
2 | =====================================
3 |
4 |
5 |
6 | Introduction
7 | ------------
8 |
9 | Switching the virtual room assigned to a physical set of thinclient (the physical room) is an important feature of virtesk-vdi.
10 |
11 | Uses:
12 |
13 | - **Quality control**: virtual rooms can be tested before assignement
14 | to physical rooms.
15 | - **Dedicated VMs for exams**
16 | - **Dedicated VMs for special applications**
17 | - **Win7 Desktops for one lesson, Linux Desktops for next lessons**
18 |
19 | - Thinclients can dispaly Linux VMs, however, no rollout tools for
20 | Linux desktops have been implemented in virtesk-vdi so far.
21 |
22 | - ...
23 |
24 | Database
25 | --------
26 |
27 | Switching virtual rooms is implemented using the postgres database.
28 |
29 | Documentation:
30 |
31 | - `Database layout `__
32 | - `Database Installation + DB
33 | Access `__
34 | - `Defining virtual
35 | rooms `__
36 |
37 | How to switch virtual rooms
38 | ---------------------------
39 |
40 | How to switch virtual rooms: simple cases
41 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
42 |
43 | For a single TC, the assigned VM can be changed like this:
44 |
45 | ::
46 |
47 | psql -U vdi-dbadmin -h localhost vdi -c "
48 | UPDATE timed_thinclient_to_vm_mapping \
49 | SET vm='test01-vd01' WHERE thinclient='test01-tc01' \
50 | AND start_date IS NULL AND end_date IS NULL;"
51 |
52 | Output:
53 |
54 | ::
55 |
56 | UPDATE 1
57 |
58 | It might be convinient to use an SQL-File for this:
59 |
60 | update.sql:
61 |
62 | ::
63 |
64 | UPDATE timed_thinclient_to_vm_mapping SET vm='test01-vd01' WHERE thinclient='test01-tc01' AND start_date IS NULL AND end_date IS NULL;
65 | UPDATE timed_thinclient_to_vm_mapping SET vm='test01-vd02' WHERE thinclient='test01-tc02' AND start_date IS NULL AND end_date IS NULL;
66 | UPDATE timed_thinclient_to_vm_mapping SET vm='test01-vd03' WHERE thinclient='test01-tc03' AND start_date IS NULL AND end_date IS NULL;
67 |
68 | Executing update.sql:
69 |
70 | ::
71 |
72 | psql -U vdi-dbadmin -h localhost vdi < room.sql
73 | UPDATE 1
74 | UPDATE 1
75 | UPDATE 1
76 |
77 | If you want to assign the VMs ``test02-vd*`` instead of ``test01-vd*``,
78 | then you can use ``vim`` or ``sed`` for changeing update.sql:
79 |
80 | Using vim:
81 |
82 | ::
83 |
84 | vim update.sql # Open file with vim
85 | :%s/test01-vd/test02-vd/ # Apply regex over whole file
86 | :wq # Write file, quit
87 |
88 | Using sed:
89 |
90 | ::
91 |
92 | sed -i 's/test01-vd/test02-vd/' update.sql
93 |
94 | The exact regexes needed for your environment do depend on your naming
95 | schema; In general, switching virtual rooms is alot easier when
96 | systematic naming is used.
97 |
98 | Please note that all examples only update records where
99 | ``start_date``/``end_date`` are ``NULL``. This is useful for most cases, but it
100 | might need adjustment for special cases.
101 |
102 | How to switch virtual rooms: advanced examples
103 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
104 |
105 | When changeing the assigned VMs for 300 thinclients (10 physical rooms
106 | with up to 30 thinclients each), then bash comes handy to generate the
107 | SQL statements:
108 |
109 | generatesql-statements.sh (available in ``sample_config/``):
110 |
111 | ::
112 |
113 | #!/bin/bash
114 |
115 | ROOMS="test01 test02 test03 test04 test05 test06 test07 test08 test09 test10"
116 |
117 | for ROOM in $ROOMS; do
118 | IDs=$(seq 1 30)
119 | echo "# Room ${ROOM}"
120 | for ID in ${IDs}; do
121 | ID_TWODIGIT=$(printf "%02d" ${ID})
122 | TC_NAME="${ROOM}-tc${ID_TWODIGIT}"
123 | VM_NAME="${ROOM}-vd${ID_TWODIGIT}"
124 | cat <<-ENDofSQL
125 | UPDATE timed_thinclient_to_vm_mapping
126 | SET vm='${VM_NAME}' WHERE thinclient='${TC_NAME}'
127 | AND start_date IS NULL AND end_date IS NULL;
128 |
129 | ENDofSQL
130 | done
131 | echo
132 | done
133 |
134 | Please adjust ``ROOMS="test01 test02 ..."`` and ``TC_NAME="${ROOM}-tc${ID_TWODIGIT}"`` and
135 | ``VM_NAME="${ROOM}-vd${ID_TWODIGIT}"`` according to your naming scheme,
136 | and ``IDs=$(seq 1 30)`` according to the number of TCs in your rooms.
137 | Some rooms might have less than 30 thinclients - however, the generated
138 | SQL statements for the non-existing TCs won't hurt, and its easier
139 | to process all rooms in an uniform way.
140 |
141 | Running it directly:
142 |
143 | ::
144 |
145 | bash generatesql-statements.sh | psql -U vdi-dbadmin -h localhost vdi
146 |
147 | Putting SQL commands into a file first, and run them afterwards:
148 |
149 | ::
150 |
151 | bash generatesql-statements.sh > update.sql # Generate SQL statements
152 | less update.sql # Control SQL statements
153 | psql -U vdi-dbadmin -h localhost vdi < update.sql # Execute SQL statements
154 |
155 | The same bash script can be used to generate the mapping for new
156 | thinclients - only the SQL statement needs to be replaced:
157 |
158 | ::
159 |
160 | INSERT INTO timed_thinclient_to_vm_mapping (vm, thinclient)
161 | VALUES ('${VM_NAME}', '${TC_NAME}');
162 |
--------------------------------------------------------------------------------
/doc/tc-vm-mapping.rst:
--------------------------------------------------------------------------------
1 | .. |br| raw:: html
2 |
3 |
4 |
5 | Assigning VMs to thinclients: Database layout
6 | =============================================
7 |
8 |
9 | Introduction
10 | ------------
11 |
12 | Thinclients use a postgres database to determine the virtual machine
13 | that shall be displayed.
14 |
15 | The database determines:
16 |
17 | - The VM shall be determined on a TC
18 | - When shall it be displayed (to display different VMs for different
19 | courses, ...)
20 | - If the VM shall `shut down `__ when the
21 | TC is shutting down
22 |
23 | Accessing the database is documented
24 | `here `__,
25 | database setup is documented
26 | `there `__,
27 | and switching virtual rooms is documented
28 | `here `__
29 |
30 | 1:1-Mapping between TCs and VMs
31 | -------------------------------
32 |
33 | Any any given point in time, there shall be a 1:1-mapping between TCs
34 | and VMs: A thinclient needs to uniquely determine the virtual machine
35 | assigned to it, and on the other hand, one VM can only be displayed on
36 | one TC at a time.
37 |
38 | However, it makes also sense to talk about a **1:2-mapping** (or
39 | 1:3-mapping, ...). One VM is mapped to the thinclient. The other VMs can
40 | be maintained (fresh rollout of virtual rooms, ...) without impacting
41 | users. This is also interesting for having dedicated VMs for special
42 | courses (exam VMs, VMs with special software, VMs with different
43 | operating systems, ...).
44 |
45 | This mapping is mandatory. Other VDI concepts, like pools of VMs,
46 | on-the-fly creation of VMs, per-User-VMs, or user-choosen VMs are not
47 | supported.
48 |
49 | Thinclient perspective: SQL Query
50 | ---------------------------------
51 |
52 | The following SQL Query is executed on a thinclient whenever virtesk-tc-connectspice wants to determine the virtual machine assigned to the thinclient, e.g. on thinclient startup, when re-connecting, and on thinclient shutdown, for shutting down the assined virtual machine if configured to do so.
53 |
54 | ::
55 |
56 | cur.execute("SELECT vm, thinclient, prio, id, shutdown_vm FROM thinclient_everything_view WHERE dhcp_hostname = ANY (%s) OR systemuuid = ANY (%s);", (dhcp_hostnames, sys_uuids))
57 |
58 | There is only one database view that is accessed by thinclients:
59 | ``thinclient_everything_view``. This allows to adapt the database layout
60 | to individual needs, the only mandatory aspect is the view
61 | ``thinclient_everything_view`` which must be compatible with the query
62 | above.
63 |
64 | Thinclient identification criteria
65 | ----------------------------------
66 |
67 | It is necessary to define a mapping from thinclients to virtual
68 | machines. For this mapping, some kind of thinclient identification is
69 | necessary.
70 |
71 | Virtesk-tc-connectspice supports two identifiers to uniquely identify
72 | the thinclient it is running on:
73 |
74 | **dhcp\_hostname**:
75 |
76 | - Determined by parsing the dhcp-leasefile on the thinclient. The
77 | leasefile is found by looking at the ``-lf`` Parameter of
78 | ``dhclient``.
79 | - Usefull to identify a workplace, independent of the thinclient device
80 | at that workplace. If the device needs replacement, the system
81 | administrator can simply adjust the dhcp configuration (new MAC
82 | adress). The system administrator does not need to adjust the
83 | thinclient-to-vm mapping, because the dhcp\_hostname will stay the
84 | same.
85 |
86 | **systemuuid**:
87 |
88 | - Determined by parsing the output of ``dmidecode -t1`` on the
89 | thinclient.
90 | - Usefull for uniquely identifying the thinclient device. It doesn't
91 | matter where or in what network the thinclient is located. The
92 | thinclient is able to connect to its assigned virtual machine, as
93 | long as it is able to connect to the postgres database and the
94 | virtualization manager/hosts.
95 |
96 | Sample database layout
97 | ----------------------
98 |
99 | A sample database layout is provided in
100 | ``sample_config/database-layout.sql``. Instructions for loading the file
101 | are provided
102 | `here `__.
103 |
104 | Thinclient DNS Domain
105 | ---------------------
106 |
107 | Depending on the DHCP server software used, **dhcp\_hostname** can be a
108 | simple hostname or a fully qualified domain name.
109 |
110 | Often it is handy to define the mapping from the
111 | *thinclient*-database-key to the dhcp\_hostname automatically. This is
112 | done in the view ``dhcphostname_to_thinclient_auto_mapping``. If FQDNs
113 | are used, then you need to adapt the dns domain in the definition of the
114 | view:
115 |
116 | ::
117 |
118 | (((timed_thinclient_to_vm_mapping.thinclient)::text || '.thinclients.yourdomain.site'::text))::character
119 |
120 | You can also change the view later, for example using pgadmin3.
121 |
122 | Important tables and views
123 | --------------------------
124 |
125 | Table timed\_thinclient\_to\_vm\_mapping
126 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
127 |
128 | Defines the mapping between thinclients and VMs.
129 |
130 | +---------------+-------------+------------+---------------------------------------------+
131 | | start\_date | end\_date | priority | comment |
132 | +===============+=============+============+=============================================+
133 | | NULL | NULL | low | useful for permanent mapping |
134 | +---------------+-------------+------------+---------------------------------------------+
135 | | defined | NULL | medium | switch to new VMs on start\_darte |
136 | +---------------+-------------+------------+---------------------------------------------+
137 | | defined | defined | high | override assignment for a period of time. |
138 | +---------------+-------------+------------+---------------------------------------------+
139 |
140 | The column ``shutdown_vm`` determines if the VM shall be shut down upon
141 | TC shutdown.
142 |
143 | The column ``thinclient`` is any arbitrary name to identify the thinclient. It does not need to be equal to the local host name or the dhcp host name. However, it is usefull if this database key and the dhcp hostname are equal, see `Thinclient DNS Domain <#thinclient-dns-domain>`__ and `dhcphostname\_to\_thinclient\_auto\_mapping <#view-dhcphostname-to-thinclient-auto-mapping>`__
144 |
145 | Table dhcphostname\_to\_thinclient\_mapping
146 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
147 |
148 | Manual mapping from dhcp hostname to thinclient. Use this table to deal
149 | with apart thinclients that do not adhere to any naming convention.
150 |
151 | See also:
152 | `dhcphostname\_to\_thinclient\_auto\_mapping <#view-dhcphostname-to-thinclient-auto-mapping>`__
153 |
154 | Table systemuuid\_to\_thinclient\_mapping
155 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
156 |
157 | Mapping from System UUID to thinclient database identifier:
158 |
159 | ::
160 |
161 | vdi=> select * from systemuuid_to_thinclient_mapping;
162 | systemuuid | thinclient
163 | --------------------------------------+-------------
164 | C7E99E73-5ADB-48B3-8B03-30FDF9E4B238 | test01-tc04
165 | (1 row)
166 |
167 | For every thinclient that you wanna identify by System UUID, one row
168 | needs to be added.
169 |
170 | View current\_thinclient\_to\_vm\_mapping
171 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
172 |
173 | Helping View. Used to filter and prioritize the entries in
174 | ``timed_thinclient_to_vm_mapping`` based on ``start_date`` and
175 | ``end_date``.
176 |
177 | View dhcphostname\_to\_thinclient\_auto\_mapping
178 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
179 |
180 | Helping View. Automatically creates a mapping
181 | ``myTC.thinclients.yourdomain.site ---> myTC`` for every myTC listed in
182 | ``timed_thinclient_to_vm_mapping``.
183 |
184 | See also: `Thinclient DNS Domain <#thinclient-dns-domain>`__.
185 |
186 | View sysinfo\_to\_thinclient\_mapping
187 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
188 |
189 | Helping View. Union of dhcphostname\_to\_thinclient\_auto\_mapping,
190 | dhcphostname\_to\_thinclient\_mapping, and
191 | systemuuid\_to\_thinclient\_mapping, with defined priorities.
192 |
193 | View thinclient\_everything\_view
194 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
195 |
196 | *"One view to rule them all, one view to find them,
197 | one view to connect them all and using Spice to bind them."*
198 |
199 | All information in the other tables and views is condensed in this one
200 | big view, ready for use by `virtesk-tc-connectspice `__.
201 |
202 | See also: `Thinclient perspective: SQL
203 | Query <#thinclient-perspective-sql-query>`__
204 |
--------------------------------------------------------------------------------
/doc/thinclients.rst:
--------------------------------------------------------------------------------
1 | Thinclients
2 | ===========
3 |
4 | .. toctree::
5 | :maxdepth: 3
6 |
7 | virtesk-infrastructure-server.rst
8 | virtesk-tc-kickstart.rst
9 | ipxe-image.rst
10 | virtesk-tc-tools.rst
11 | virtesk-tc-connectspice.rst
12 | libusbredir-patching.rst
13 | tc-vm-mapping.rst
14 |
--------------------------------------------------------------------------------
/doc/virtesk-tc-connectspice.rst:
--------------------------------------------------------------------------------
1 | .. |br| raw:: html
2 |
3 |
4 |
5 | VDI Software running on thinclients
6 | ===================================
7 |
8 |
9 | Introduction
10 | ------------
11 |
12 | Virtesk-tc-connectspice is the software running on thinclients.
13 |
14 | It connects to the postgres database, determines the assigned VM, starts
15 | it if necessary, determines spice connection parameters, starts a
16 | spice-client (``remote-viewer``), and passes the connection parameters
17 | to the spice client using a unix domain socket (remote-control of
18 | spice-clients using SPICE-XPI API).
19 |
20 | Virtesk-tc-connectspice is not designed to run standalone. It needs to
21 | be run on properly configured thinclients. All necessary configuration
22 | is done when rolling out a thinclient using kickstart.
23 |
24 | It features a minimalistic GUI, based on gxmessage. The language is
25 | German, other languages are not available.
26 |
27 | The former name was ``connect_spice_client``.
28 |
29 | Virtesk-tc-connectspice consists of two programs:
30 |
31 | - **virtesk-tc-connectspice-main**: Main program as described above.
32 | - **virtesk-tc-connectspice-shutdown-vm**: Called by systemd on
33 | thinclient `shutdown `__. Will shutdown
34 | the VM asssigned to the thinclient if configured to do so.
35 |
36 | Configuration
37 | -------------
38 |
39 | Main config file
40 | ~~~~~~~~~~~~~~~~
41 |
42 | /etc/connect\_spice\_client/connect\_spice\_client.conf
43 |
44 | ::
45 |
46 | [general]
47 | log_config_file = connect_spice_client_logging.conf
48 | shutdown_command=/bin/sh -c "sudo shutdown -h now"
49 | reboot_command=/bin/sh -c "sudo shutdown -r now"
50 |
51 | # Postgres DB connection string
52 | # ADJUST
53 | postgres_db_connect=host=infrastructure-server sslmode=require connect_timeout=1 dbname=vdi user=vdi-readonly password=PASSWORD
54 |
55 | # Desktop notifications
56 | notify_cmd_waiting_for_dhcplease = notify-send -t 3000 -i /usr/share/icons/gnome/48x48/status/network-wired-disconnected.png "Waiting for network..."
57 | notify_cmd_waiting_for_db_connection = notify-send -t 3000 -i /usr/share/icons/gnome/48x48/status/network-wired-disconnected.png "Waiting for database..."
58 | notify_cmd_waiting_for_vm_launch = notify-send --hint string:transient:true -t 3000 -i /usr/share/icons/gnome/48x48/apps/preferences-desktop-remote-desktop.png "starting VM... please wait..."
59 |
60 | # GUI
61 | dialog_command_with_retry = gxmessage -buttons "neu verbinden:101,Thinclient herunterfahren:102,Thinclient neu starten:103,Support:104" -center -title "Nachricht" -default "neu verbinden" -ontop -noescape -wrap
62 | dialog_command_without_retry = gxmessage -buttons "Thinclient herunterfahren:102,Thinclient neu starten:103,Support:104" -center -title "Nachricht" -ontop -noescape -wrap
63 | dialog_command_support = gxmessage -center -name "Support Informationen" -title "Support Informationen" -wrap -buttons OK:0 -default OK
64 |
65 | support_message_file = support_message.txt
66 |
67 | config_tags_user_query=ovirt.thinclient*
68 |
69 | [connect]
70 | # ADJUST
71 | url=https://your-ovirt-manager.fqdn/api
72 |
73 | # ADJUST
74 | username=ovirt.thinclient@your-ovirt-authentication-domain
75 | # ADJUST
76 | password=PASSWORD
77 | ca_file=ovirt-manager.crt
78 |
79 |
80 | #insecure=True
81 | #filter=True
82 | #filter=False
83 |
84 | [spice]
85 | spice_ca_file=ovirt-manager.crt
86 | socket=/tmp/adsy-rhev-tools-spice-control-socket
87 | spice_client_command=/usr/bin/remote-viewer --spice-controller
88 |
89 | Technical user for accessing Ovirt REST API
90 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
91 |
92 | A technical user, ``ovirt.thinclient@your-ovirt-authentication-domain``,
93 | with appropriate permissions, is needed for accessing the Ovirt
94 | REST-API.
95 |
96 | Because of REST API limitations regarding unprivileged users, we grant
97 | minimalistic adminstrator permissions to our technical user. However, he
98 | only will be able to access VDI VMs and no other VMs.
99 |
100 | New Ovirt Role ``MinimalAdmin``:
101 |
102 | ::
103 |
104 | Navigation: Ovirt Webadmin ---> top right corner ---> configure ---> Roles ---> New
105 |
106 | Name: MinimalAdmin
107 | Description: Minimalistic Administrator Role
108 | Account Type: Admin
109 |
110 | Check Boxes: leave them all unchecked
111 |
112 | For adding new user ``ovirt.thinclient@your-ovirt-authentication-domain`` to Ovirt, it
113 | first needs to be created in ``your-ovirt-authentication-domain``. |br|
114 | Then, grant him the role ``MinimalAdmin`` using
115 | ``Ovirt Webadmin ---> top right corner ---> configure ---> System Permissions --> Add``.
116 |
117 | New Ovirt Role ``UserRoleWithReconnect``:
118 |
119 | ::
120 |
121 | Navigation: Ovirt Webadmin ---> top right corner ---> configure ---> Roles ---> New
122 |
123 | Name: UserRoleWithReconnect
124 | Description: Required for Ovirt VDI Thinclients
125 | Account Type: User
126 |
127 | Checkboxes:
128 | [X] Login Permissions (System --> Configure System)
129 | [X] Basic Operations (VM --> Basic Operations)
130 | [X] Remote Log In (VM --> Basic Operations)
131 | [X] Override opened console session (VM --> Administrative Operations)
132 |
133 | Virtesk-virtroom-rollout will grant ``UserRoleWithReconnect`` to
134 | ``ovirt.thinclient@your-ovirt-authentication-domain`` on freshly created
135 | VMs.
136 |
137 | See also: config-option ``tc_user`` in
138 | `virtesk-vm-rollout.conf `__.
139 |
140 | Ovirt REST API: SSL CA
141 | ~~~~~~~~~~~~~~~~~~~~~~
142 |
143 | The Ovirt SSL certificate authority needs to be configured for secure
144 | SSL communication.
145 |
146 | Fetch the CA file from http://your-ovirt-manager.fqdn/ca.crt, and put it
147 | into ``ovirt-manager.crt``:
148 |
149 | /etc/connect\_spice\_client/ovirt-manager.crt
150 |
151 | ::
152 |
153 | -----BEGIN CERTIFICATE-----
154 | # ADJUST
155 | ...
156 | -----END CERTIFICATE-----
157 |
158 | /etc/connect\_spice\_client/connect\_spice\_client\_logging.conf
159 |
160 | ::
161 |
162 | [formatters]
163 | keys=simpleFormatter,logFileFormatter
164 |
165 | [loggers]
166 | keys=root
167 |
168 | [handlers]
169 | #keys=consoleHandler,timedRotatingFileHandler,syslogDebugHandler
170 | keys=consoleHandler,timedRotatingFileHandler,syslogHandler
171 |
172 | [logger_root]
173 | level=DEBUG
174 | handlers=consoleHandler,timedRotatingFileHandler,syslogHandler
175 |
176 | [handler_consoleHandler]
177 | class=StreamHandler
178 | level=DEBUG
179 | formatter=simpleFormatter
180 | args=(sys.stderr,)
181 |
182 | [handler_syslogHandler]
183 | class=handlers.SysLogHandler
184 | level=DEBUG
185 | formatter=simpleFormatter
186 | args=('/dev/log',)
187 |
188 | # [handler_syslogDebugHandler]
189 | # class=connect_spice_client.syslog_debug_handler
190 | # level=DEBUG
191 | # formatter=simpleFormatter
192 | # args=('/dev/log',)
193 | #
194 |
195 | [handler_timedRotatingFileHandler]
196 | class=handlers.TimedRotatingFileHandler
197 | level=DEBUG
198 | formatter=logFileFormatter
199 | args=(os.path.expanduser('~/logs/connect_spice_client.log'), 'D', 1, 30)
200 |
201 | [formatter_simpleFormatter]
202 | format=%(asctime)s - %(levelname)s - %(message)s
203 | datefmt=
204 |
205 | [formatter_logFileFormatter]
206 | format=%(asctime)s - %(levelname)s - %(message)s
207 | datefmt=
208 |
209 | Support message
210 | ~~~~~~~~~~~~~~~
211 |
212 | The following message is displayed whenever a user clicks on the the support-button on a thinclient:
213 |
214 | /etc/connect\_spice\_client/support\_message.txt
215 |
216 | ::
217 |
218 | ===========================================================
219 | Support
220 | ===========================================================
221 |
222 | For support, please call ...
223 |
224 | In addition, some system debug information will be displayed.
225 |
--------------------------------------------------------------------------------
/doc/virtesk-tc-kickstart.rst:
--------------------------------------------------------------------------------
1 | .. |br| raw:: html
2 |
3 |
4 |
5 | Thinclient-Rollout using Kickstart
6 | ==================================
7 |
8 |
9 | **Goal - perfect rollout experience**
10 |
11 |
12 | #. Start a thinclient, boot from network
13 | #. Choose what you wanna do in a small graphical boot loader menu
14 | (optional)
15 | #. The thinclient installation will run completely unattended.
16 | #. After 10 minutes (30 minutes on very old hardware) the installation
17 | and configuration is completed
18 | #. The thinclient reboots itself
19 | #. The thinclient connects to the virtual machine
20 | `assigned `__ to it
21 | #. The thinclient is ready, users can work
22 |
23 | The amount of data transferred over the network is quite small (1000M - 2000M, estimated value), so its perfectly possible to roll out several hundred thinclients at a time over a single gigabit uplink. |br|
24 | Everything is completely scripted (no disk images!), therefore, the rollout process and the thinclient system can be flexible adapted for new needs and new features. |br|
25 | Experienced system administrators dont need to be on-site for thinclient rollout, remote rollout using Wake-On-Lan is possible. Instead of PXE network booting, thinclients can also be re-installed using ssh and `kexec `__.
26 |
27 |
28 | .. warning:: WARNING: DATA LOSS |br| The provided sample kickstart file will ERASE everything on all hard drives and on all usb drives on any computer where a thinclient rollout is attempted. This is indented this way (thinclients dont contain any data, so it's ok).
29 |
30 | Background
31 | ----------
32 |
33 | There are several techiques for fully automated installation of an
34 | operating system:
35 |
36 | - **Unattended Setup** for Microsoft Windows
37 | - **Preseed** for Debian GNU/Linux
38 | - **Kickstart** for Red Hat Enterprise Linux, CentOS, Fedora, ...
39 |
40 | They all use a configuration file for scripting the installation process. Normally, the goal is to make sure the operating system gets installed without any user or sysadmin interaction. |br|
41 | In virtesk-vdi, a network-based kickstart-installation of Fedora 22 is used to deploy and configure thinclients. |br|
42 | The kickstart script file contains a very large post-section, written in bash. It contains all thinclient configuration files (inlined using bash-here-documents). It also makes sure the minimalistic desktop interface is completely locked down, to make sure that students cannot do anything else besides accessing the assigned virtual machine.
43 |
44 |
45 | PXE-Setup, Network Boot, Fedora Mirror, ...
46 | -------------------------------------------
47 |
48 | Documented `here `__.
49 |
50 | Sample Kickstart File
51 | ---------------------
52 |
53 | Located at: ``sample_config/tc_rollout.ks``
54 |
55 | Alot of adjustment needs to be done to make the kickstart file work in a new environment. |br|
56 | The sections needing adjustmend are marked with ``# ADJUST``.
57 |
58 | All references to ``infrastructure-server`` need to be replaced with the
59 | actual FQDN of your infrastructure server.
60 |
61 | The thinclient software, *virtesk-tc-connectspice*, needs to be
62 | configured as described `here `__.
63 |
64 | Adapting the sample kickstart file isn't easy, and if you are completely new to kickstart, it is actually quite hard. Don't give up, everyone can learn PXE / network installation / kickstart! |br|
65 | For analyzing kickstart problems, remote logging is useful. On a properly configured `infrastructure server `__, logfiles are available at ``/var/log/remote``. However, not everything is logged, because remote logging is only done in stage 2 of the Fedora installer.
66 |
67 | Kickstart literature
68 | --------------------
69 |
70 | Red Hat provides alot of documentation for Red Hat Enterprise Linux
71 | `here `__.
72 |
73 | The *Installation Guide*, the *System Administrator's Guide*, *Networking Guide* provide alot of information about network boot, network installation, systemd, etc. |br|
74 | Most of the documentation for RHEL7 is also valid for Fedora 22/23.
75 |
76 | Kickstart documentation is available
77 | `here `__.
78 |
79 | Kickstart boot options are documented
80 | `here `__.
81 |
--------------------------------------------------------------------------------
/doc/virtesk-vm-rollout-install.rst:
--------------------------------------------------------------------------------
1 | Installing VM rollout tools
2 | =========================================
3 |
4 | Overview
5 | --------
6 |
7 | To run virtesk-vm-rollout, the system must be prepared first:
8 |
9 | - Installing virtesk-vm-rollout
10 | - Minimal configuration
11 | - Setting up `payload injection mechanism `__
12 | - Configuring virtual rooms
13 |
14 | Installation
15 | ------------
16 |
17 | Installation has been tested on CentOS 7. Fedora >= 20 should work as
18 | well. RHEL 6 / CentOS 6 might not work (Code requires python 2.7)
19 |
20 | Dependencies:
21 |
22 | ::
23 |
24 | yum install ovirt-engine-sdk-python python-mako mtools
25 |
26 | Cloneing git repository:
27 |
28 | ::
29 |
30 | cd /opt
31 | git clone http://path.to.git.repository/virtesk-vdi.src.git
32 |
33 | .. raw:: html
34 |
35 |
38 |
39 | Bash search path: ``/etc/profile.d/virtesk-vm-rollout.sh``
40 |
41 | ::
42 |
43 | pathmunge /opt/virtesk-vdi.src/virtesk-vm-rollout after
44 |
45 | Minimal configuration
46 | ---------------------
47 |
48 | ::
49 |
50 | mkdir /etc/virtesk-vdi/
51 | mkdir /var/log/virtesk-vdi/
52 |
53 | # SSL Certificyte of Ovirt engine Certificate Authority
54 | vim /etc/virtesk-vdi/ca.crt
55 | # Template File for Windows Unattended Setup configuration file
56 | vim /etc/virtesk-vdi/Autounattend-production.xml.template
57 | # Logging settings
58 | vim /etc/virtesk-vdi/logging.conf
59 | # Definitions of virtual rooms:
60 | vim /etc/virtesk-vdi/virtesk-vm-rollout.conf
61 |
62 | Details are documented `here `__.
63 |
64 | Setting up payload injection mechanism
65 | --------------------------------------
66 |
67 | For rolling out virtual rooms, a payload injection is necessary.
68 |
69 | Payload injection is done by creating floppy images containing
70 | ``a:\sysprep.inf``, uploading them using SFTP, and attaching them to
71 | RHEV/Ovirt VMs using vdsm-hook-floppy.
72 |
73 | The initial setup is quite complicated, but it has to be done only once,
74 | afterwards it will "just work".
75 |
76 | Detailed instructions can be found `here `__.
77 |
78 | Testing
79 | -------
80 |
81 | After initial installation and after the configuration of at least one
82 | virtual room, run the following command to check if the config is valid
83 | and if tools do work in general:
84 |
85 | ::
86 |
87 | virtesk-virtroom-show room01
88 |
--------------------------------------------------------------------------------
/doc/virtesk-vm-rollout.rst:
--------------------------------------------------------------------------------
1 | Rollout tools for virtual rooms
2 | =============================================
3 |
4 | Tools for creating and manageing VDI VMs, grouped into virtual rooms.
5 |
6 | --------------
7 |
8 | Introduction
9 | ------------
10 |
11 | virtesk-virtroom-\* is a set of tools for creating/cloneing a lot of windows 7 virtual machines.
12 | Those win7 VMs can then be assigned to and displayed on thinclients.
13 |
14 | The script creates new VMs based on an existing Ovirt VM Template, and
15 | assings hostname, static IP address, ... to it and makes sure the new VM
16 | is joined into an Active Directory (or Samba4) domain.
17 |
18 | The process is based on Windows Sysprep / Unattended.xml technologies.
19 |
20 | See also: `Compatibility `__
21 |
22 | --------------
23 |
24 | Tools
25 | -----
26 |
27 | virtesk-virtroom-show
28 | ~~~~~~~~~~~~~~~~~~~~~~
29 |
30 | Parses and validates the room configuration, checks if the VMs exists,
31 | and lists their snapshosts.
32 |
33 | virtesk-virtroom-rollout
34 | ~~~~~~~~~~~~~~~~~~~~~~~~~
35 |
36 | Roll out a virtual room.
37 |
38 | Prerequisites:
39 |
40 | - VMs of the virtual room shall not exist
41 |
42 | How it works:
43 |
44 | #. Configuration parsing and validation
45 | #. Create VMs from Ovirt Template
46 | #. Attach Network to VM
47 | #. Create individual ``Autounattend.xml`` using a template mechanism
48 | #. Generate payload floppy, containing individual ``Autounattend.xml``
49 | (filename: ``A:\sysprep.inf``)
50 | #. Run VM with payload attached. This configures Windows according to
51 | the settings in ``Autounattend.xml``
52 | #. Wait until all VMs of a virtual room are shut down
53 | #. Postprocess VMs (USB settings, stateless feature, add permissions for
54 | technical vdi accounts, create snapshots, ...)
55 | #. Start VMs
56 |
57 | virtesk-virtroom-delete
58 | ~~~~~~~~~~~~~~~~~~~~~~~~
59 |
60 | Deletes all VMs of a virtual room.
61 |
62 | virtesk-virtroom-reset
63 | ~~~~~~~~~~~~~~~~~~~~~~~
64 |
65 | Reset VMs of a virtual room to a snapshot state.
66 |
67 | How it works:
68 |
69 | #. Configuration parsing and validation
70 | #. Stop VMs if they are running
71 | #. Restore state to snapshot
72 | #. Optional: Start VMs again
73 |
74 | Reset to snapshot state is not supported for stateless VMs.
75 |
76 | virtesk-virtroom-start
77 | ~~~~~~~~~~~~~~~~~~~~~~~
78 |
79 | Starts all VMs in a virtual room.
80 |
81 | Details:
82 |
83 | - Ignores already running VMs
84 | - No validation is done - returns as soon as the start signal has been
85 | sent to all VMs. Does not wait for the VMs to launch.
86 |
87 | virtesk-virtroom-shutdown
88 | ~~~~~~~~~~~~~~~~~~~~~~~~~~
89 |
90 | Shut down all VMs in a virtual room.
91 |
92 | Details:
93 |
94 | - Clean shutdown: A signal (ACPI shutdown or guest agent shutdown) is
95 | sent to the operating system of the VM.
96 | Assumes that ACPI daemon and/or guest agent is properly configured
97 | inside the VM and that the VM does a clean shutdown when told to do
98 | so.
99 | - Ignores already stopped VMs
100 | - No validation is done - returns as soon as the shutdown signal has
101 | been sent to all VMs. Does not wait for the VMs to shut down.
102 |
103 | Usage
104 | -----
105 |
106 | .. code:: bash
107 |
108 | virtesk-virtroom-show [--config CONFIG] myroom
109 | virtesk-virtroom-rollout [--config CONFIG] myroom
110 | virtesk-virtroom-delete [--config CONFIG] myroom
111 | virtesk-virtroom-reset [--config CONFIG] myroom
112 |
113 | ``myroom`` is the virtual room to act on, e.g. the room to
114 | show/rollout/delete/reset.
115 |
116 | The following config file locations are used, first match wins:
117 |
118 | - Command line argument
119 | (``--config /path/to/virtesk-vm-rollout.conf``)
120 | - ``~/.config/virtesk-vdi/virtesk-vm-rollout.conf``
121 | - ``/etc/virtesk-vdi/virtesk-vm-rollout.conf``
122 |
123 | Many virtual rooms
124 | ------------------
125 |
126 | When manageing alot of virtual rooms, bash features can be handy:
127 |
128 | ::
129 |
130 | for room in room{01..10}; do virtesk-virtroom-show $room; done
131 | for room in room01 room02 room03; do virtesk-virtroom-show $room; done
132 | for room in $(cat room-list.txt); do virtesk-virtroom-show $room; done
133 |
134 | See also
135 | --------
136 |
137 | - `Installing virtesk-vm-rollout `__
138 | - `Defining and configuring virtual
139 | rooms `__
140 | - `Windows Goldimage `__
141 | - `Windows Unattended Setup `__
142 | - `Quality control after rollout `__
143 |
--------------------------------------------------------------------------------
/doc/virtual_rooms.rst:
--------------------------------------------------------------------------------
1 | Virtual Rooms
2 | =============
3 |
4 | .. toctree::
5 | :maxdepth: 3
6 |
7 | virtesk-vm-rollout.rst
8 | virtesk-vm-rollout-install.rst
9 | virtesk-vm-rollout-config.rst
10 | switching-virtual-rooms.rst
11 | stateless_and_snapshot_features.rst
12 | quality_control.rst
13 | autounattend.rst
14 | goldimage.rst
15 | start-and-stop-management.rst
16 |
--------------------------------------------------------------------------------
/doc/visio/Makefile:
--------------------------------------------------------------------------------
1 | all:
2 | bash -c 'for i in *.pdf; do { convert -density 600 -alpha deactivate $$i $$(basename $$i .pdf).png; convert -resize 800x565 $$(basename $$i .pdf).png $$(basename $$i .pdf)-small.png; } & done; echo -n "Waiting for childs..."; wait; echo done.'
3 |
--------------------------------------------------------------------------------
/doc/visio/virtesk-archidecture-overview-small.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adfinis/virtesk/2a9f9fcb705172663efbff996df675f511a49f3f/doc/visio/virtesk-archidecture-overview-small.png
--------------------------------------------------------------------------------
/doc/visio/virtesk-archidecture-overview.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adfinis/virtesk/2a9f9fcb705172663efbff996df675f511a49f3f/doc/visio/virtesk-archidecture-overview.pdf
--------------------------------------------------------------------------------
/doc/visio/virtesk-archidecture-overview.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adfinis/virtesk/2a9f9fcb705172663efbff996df675f511a49f3f/doc/visio/virtesk-archidecture-overview.png
--------------------------------------------------------------------------------
/doc/visio/virtesk-archidecture-overview.vsdx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adfinis/virtesk/2a9f9fcb705172663efbff996df675f511a49f3f/doc/visio/virtesk-archidecture-overview.vsdx
--------------------------------------------------------------------------------
/doc/visio/virtesk-sysadmin-features-small.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adfinis/virtesk/2a9f9fcb705172663efbff996df675f511a49f3f/doc/visio/virtesk-sysadmin-features-small.png
--------------------------------------------------------------------------------
/doc/visio/virtesk-sysadmin-features.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adfinis/virtesk/2a9f9fcb705172663efbff996df675f511a49f3f/doc/visio/virtesk-sysadmin-features.pdf
--------------------------------------------------------------------------------
/doc/visio/virtesk-sysadmin-features.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adfinis/virtesk/2a9f9fcb705172663efbff996df675f511a49f3f/doc/visio/virtesk-sysadmin-features.png
--------------------------------------------------------------------------------
/doc/visio/virtesk-sysadmin-features.vsdx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adfinis/virtesk/2a9f9fcb705172663efbff996df675f511a49f3f/doc/visio/virtesk-sysadmin-features.vsdx
--------------------------------------------------------------------------------
/doc/visio/virtesk-vdi-connection-setup-small.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adfinis/virtesk/2a9f9fcb705172663efbff996df675f511a49f3f/doc/visio/virtesk-vdi-connection-setup-small.png
--------------------------------------------------------------------------------
/doc/visio/virtesk-vdi-connection-setup.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adfinis/virtesk/2a9f9fcb705172663efbff996df675f511a49f3f/doc/visio/virtesk-vdi-connection-setup.pdf
--------------------------------------------------------------------------------
/doc/visio/virtesk-vdi-connection-setup.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adfinis/virtesk/2a9f9fcb705172663efbff996df675f511a49f3f/doc/visio/virtesk-vdi-connection-setup.png
--------------------------------------------------------------------------------
/doc/visio/virtesk-vdi-connection-setup.vsdx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adfinis/virtesk/2a9f9fcb705172663efbff996df675f511a49f3f/doc/visio/virtesk-vdi-connection-setup.vsdx
--------------------------------------------------------------------------------
/doc/visio/virtesk-vdi-tc-rollout-small.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adfinis/virtesk/2a9f9fcb705172663efbff996df675f511a49f3f/doc/visio/virtesk-vdi-tc-rollout-small.png
--------------------------------------------------------------------------------
/doc/visio/virtesk-vdi-tc-rollout.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adfinis/virtesk/2a9f9fcb705172663efbff996df675f511a49f3f/doc/visio/virtesk-vdi-tc-rollout.pdf
--------------------------------------------------------------------------------
/doc/visio/virtesk-vdi-tc-rollout.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adfinis/virtesk/2a9f9fcb705172663efbff996df675f511a49f3f/doc/visio/virtesk-vdi-tc-rollout.png
--------------------------------------------------------------------------------
/doc/visio/virtesk-vdi-tc-rollout.vsdx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adfinis/virtesk/2a9f9fcb705172663efbff996df675f511a49f3f/doc/visio/virtesk-vdi-tc-rollout.vsdx
--------------------------------------------------------------------------------
/doc/visio/virtesk-virtual-rooms-small.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adfinis/virtesk/2a9f9fcb705172663efbff996df675f511a49f3f/doc/visio/virtesk-virtual-rooms-small.png
--------------------------------------------------------------------------------
/doc/visio/virtesk-virtual-rooms.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adfinis/virtesk/2a9f9fcb705172663efbff996df675f511a49f3f/doc/visio/virtesk-virtual-rooms.pdf
--------------------------------------------------------------------------------
/doc/visio/virtesk-virtual-rooms.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adfinis/virtesk/2a9f9fcb705172663efbff996df675f511a49f3f/doc/visio/virtesk-virtual-rooms.png
--------------------------------------------------------------------------------
/doc/visio/virtesk-virtual-rooms.vsdx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adfinis/virtesk/2a9f9fcb705172663efbff996df675f511a49f3f/doc/visio/virtesk-virtual-rooms.vsdx
--------------------------------------------------------------------------------
/misc/vdsm-spice-disconnect-actions-backport/README.txt:
--------------------------------------------------------------------------------
1 | Documentation is avaliable in:
2 | ../../doc/spice-disconnect-actions.rst
3 |
--------------------------------------------------------------------------------
/misc/vdsm-spice-disconnect-actions-backport/vdsm-spice-disconnect-actions-backport.patch:
--------------------------------------------------------------------------------
1 | diff -pru vdsm-4.16.30/vdsm/clientIF.py vdsm-4.16.30-vdsm-spice-disconnect-actions-backport/vdsm/clientIF.py
2 | --- vdsm-4.16.30/vdsm/clientIF.py 2015-11-23 16:01:24.000000000 +0100
3 | +++ vdsm-4.16.30-vdsm-spice-disconnect-actions-backport/vdsm/clientIF.py 2016-04-05 11:45:16.000000000 +0200
4 | @@ -556,9 +556,10 @@ class clientIF(object):
5 | 'authScheme %s subject %s',
6 | phase, localAddr, remoteAddr, authScheme, subject)
7 | if phase == libvirt.VIR_DOMAIN_EVENT_GRAPHICS_INITIALIZE:
8 | - v.onConnect(remoteAddr['node'])
9 | + v.onConnect(remoteAddr['node'], remoteAddr['service'])
10 | elif phase == libvirt.VIR_DOMAIN_EVENT_GRAPHICS_DISCONNECT:
11 | - v.onDisconnect()
12 | + v.onDisconnect(clientIp=remoteAddr['node'],
13 | + clientPort=remoteAddr['service'])
14 | elif eventid == libvirt.VIR_DOMAIN_EVENT_ID_WATCHDOG:
15 | action, = args[:-1]
16 | v._onWatchdogEvent(action)
17 | diff -pru vdsm-4.16.30/vdsm/virt/vm.py vdsm-4.16.30-vdsm-spice-disconnect-actions-backport/vdsm/virt/vm.py
18 | --- vdsm-4.16.30/vdsm/virt/vm.py 2015-11-23 16:01:24.000000000 +0100
19 | +++ vdsm-4.16.30-vdsm-spice-disconnect-actions-backport/vdsm/virt/vm.py 2016-04-05 11:43:31.000000000 +0200
20 | @@ -1960,6 +1960,7 @@ class Vm(object):
21 | self._powerDownEvent = threading.Event()
22 | self._liveMergeCleanupThreads = {}
23 | self._shutdownReason = None
24 | + self._clientPort = ''
25 |
26 | def _get_lastStatus(self):
27 | # note that we don't use _statusLock here. One of the reasons is the
28 | @@ -2471,15 +2472,51 @@ class Vm(object):
29 | except Exception:
30 | self.log.error("Reboot event failed", exc_info=True)
31 |
32 | - def onConnect(self, clientIp=''):
33 | + def onConnect(self, clientIp='', clientPort=''):
34 | if clientIp:
35 | self.conf['clientIp'] = clientIp
36 | + self._clientPort = clientPort
37 |
38 | def _timedDesktopLock(self):
39 | - if not self.conf.get('clientIp', ''):
40 | - self.guestAgent.desktopLock()
41 | + # This is not a definite fix, we're aware that there is still the
42 | + # possibility of a race condition, however this covers more cases
43 | + # than before and a quick gain
44 | +
45 | + if not self.conf.get('clientIp', '') and not self.destroyed:
46 | + delay = config.get('vars', 'user_shutdown_timeout')
47 | + timeout = config.getint('vars', 'sys_shutdown_timeout')
48 | + daction = 'undef'
49 | +
50 | + if 'spice_disconnect_action' in self.conf['custom']:
51 | + daction = (
52 | + self.conf['custom']['spice_disconnect_action'].lower()
53 | + )
54 | +
55 | + if daction == 'lock' or daction == 'undef':
56 | + self.guestAgent.desktopLock()
57 | + elif daction == 'logoff':
58 | + self.guestAgent.desktopLogoff(True)
59 | + elif daction == 'reboot':
60 | + self.shutdown(delay=delay, reboot=True, timeout=timeout,
61 | + message='Scheduled reboot on disconnect',
62 | + force=True)
63 | + elif daction == 'shutdown':
64 | + self.shutdown(delay=delay, reboot=False, timeout=timeout,
65 | + message='Scheduled shutdown on disconnect',
66 | + force=True)
67 | + elif daction == 'noop':
68 | + pass
69 | + else:
70 | + self.guestAgent.desktopLock()
71 | +
72 | + def onDisconnect(self, detail=None, clientIp='', clientPort=''):
73 | + if self.conf['clientIp'] != clientIp:
74 | + self.log.debug('Ignoring disconnect event because ip differs')
75 | + return
76 | + if self._clientPort and self._clientPort != clientPort:
77 | + self.log.debug('Ignoring disconnect event because ports differ')
78 | + return
79 |
80 | - def onDisconnect(self, detail=None):
81 | self.conf['clientIp'] = ''
82 | # This is a hack to mitigate the issue of spice-gtk not respecting the
83 | # configured secure channels. Spice-gtk is always connecting first to
84 | @@ -2494,6 +2531,22 @@ class Vm(object):
85 | # Multiple desktopLock calls won't matter if we're really disconnected
86 | # It is not harmful. And the threads will exit after 2 seconds anyway.
87 | _DESKTOP_LOCK_TIMEOUT = 2
88 | +
89 | + if 'spice_disconnect_waittime_seconds' in self.conf['custom']:
90 | + try:
91 | + _DESKTOP_LOCK_TIMEOUT = int(
92 | + self.conf['custom']['spice_disconnect_waittime_seconds']
93 | + )
94 | + except ValueError:
95 | + self.log.error(
96 | + "Cannot convert spice_disconnect_waittime_seconds={0} to "
97 | + "int. Proceeding with default value.".format(
98 | + self.conf['custom'][
99 | + 'spice_disconnect_waittime_seconds'
100 | + ]
101 | + ),
102 | + exc_info=True)
103 | +
104 | timer = threading.Timer(_DESKTOP_LOCK_TIMEOUT, self._timedDesktopLock)
105 | timer.start()
106 |
107 |
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | pytest-mock
2 |
--------------------------------------------------------------------------------
/sample_config/database-layout-update-001.sql:
--------------------------------------------------------------------------------
1 | --
2 | -- Update database layout from previous version
3 | --
4 |
5 | ALTER TABLE timed_thinclient_to_vm_mapping ADD resolution character varying NULL;
6 |
7 | DROP VIEW current_thinclient_to_vm_mapping;
8 | CREATE VIEW current_thinclient_to_vm_mapping AS
9 | SELECT
10 | f.id,
11 | f.thinclient,
12 | f.vm,
13 | f.resolution,
14 | f.start_date,
15 | f.end_date,
16 | f.prio,
17 | f.shutdown_vm
18 | FROM (
19 | SELECT
20 | timed_thinclient_to_vm_mapping.id,
21 | timed_thinclient_to_vm_mapping.thinclient,
22 | timed_thinclient_to_vm_mapping.vm,
23 | timed_thinclient_to_vm_mapping.resolution,
24 | timed_thinclient_to_vm_mapping.start_date,
25 | timed_thinclient_to_vm_mapping.end_date,
26 | 0 AS prio,
27 | timed_thinclient_to_vm_mapping.shutdown_vm
28 | FROM
29 | timed_thinclient_to_vm_mapping
30 | WHERE (
31 | (timed_thinclient_to_vm_mapping.start_date IS NULL)
32 | AND
33 | (timed_thinclient_to_vm_mapping.end_date IS NULL)
34 | )
35 | UNION SELECT
36 | timed_thinclient_to_vm_mapping.id,
37 | timed_thinclient_to_vm_mapping.thinclient,
38 | timed_thinclient_to_vm_mapping.vm,
39 | timed_thinclient_to_vm_mapping.resolution,
40 | timed_thinclient_to_vm_mapping.start_date,
41 | timed_thinclient_to_vm_mapping.end_date,
42 | 1 AS prio,
43 | timed_thinclient_to_vm_mapping.shutdown_vm
44 | FROM
45 | timed_thinclient_to_vm_mapping
46 | WHERE (
47 | (timed_thinclient_to_vm_mapping.start_date <= now())
48 | AND
49 | (timed_thinclient_to_vm_mapping.end_date IS NULL))
50 | UNION SELECT
51 | timed_thinclient_to_vm_mapping.id,
52 | timed_thinclient_to_vm_mapping.thinclient,
53 | timed_thinclient_to_vm_mapping.vm,
54 | timed_thinclient_to_vm_mapping.resolution,
55 | timed_thinclient_to_vm_mapping.start_date,
56 | timed_thinclient_to_vm_mapping.end_date,
57 | 2 AS prio,
58 | timed_thinclient_to_vm_mapping.shutdown_vm
59 | FROM
60 | timed_thinclient_to_vm_mapping
61 | WHERE (
62 | (now() >= timed_thinclient_to_vm_mapping.start_date)
63 | AND
64 | (now() <= timed_thinclient_to_vm_mapping.end_date)
65 | )
66 | ) f
67 | ORDER BY
68 | f.prio DESC,
69 | f.start_date,
70 | f.id;
71 |
72 |
73 | ALTER TABLE public.current_thinclient_to_vm_mapping OWNER TO "vdi-dbadmin";
74 |
75 | DROP VIEW thinclient_everything_view;
76 | SELECT DISTINCT
77 | s.thinclient,
78 | c.vm,
79 | c.resolution,
80 | s.dhcp_hostname,
81 | s.systemuuid,
82 | c.id,
83 | c.start_date,
84 | c.end_date,
85 | c.prio,
86 | c.shutdown_vm
87 | FROM (
88 | sysinfo_to_thinclient_mapping s
89 | LEFT JOIN current_thinclient_to_vm_mapping c ON (((s.thinclient)::text = (c.thinclient)::text))
90 | )
91 | ORDER BY
92 | c.prio DESC,
93 | c.start_date,
94 | c.id;
95 |
--------------------------------------------------------------------------------
/sample_config/database-layout.sql:
--------------------------------------------------------------------------------
1 | --
2 | -- This is the main table containing configuration of thin clients
3 | --
4 |
5 | CREATE TABLE timed_thinclient_to_vm_mapping (
6 | vm character varying NOT NULL,
7 | thinclient character varying NOT NULL,
8 | resolution character varying NULL,
9 | start_date TIMESTAMP WITH TIME ZONE,
10 | end_date TIMESTAMP WITH TIME ZONE,
11 | id bigint NOT NULL,
12 | shutdown_vm boolean DEFAULT FALSE NOT NULL
13 | );
14 |
15 |
16 | --
17 | -- mapping between thinclient and vm depending
18 | -- on start time and priority
19 | --
20 |
21 | CREATE VIEW current_thinclient_to_vm_mapping AS
22 | SELECT
23 | f.id,
24 | f.thinclient,
25 | f.vm,
26 | f.resolution,
27 | f.start_date,
28 | f.end_date,
29 | f.prio,
30 | f.shutdown_vm
31 | FROM (
32 | SELECT
33 | timed_thinclient_to_vm_mapping.id,
34 | timed_thinclient_to_vm_mapping.thinclient,
35 | timed_thinclient_to_vm_mapping.vm,
36 | timed_thinclient_to_vm_mapping.resolution,
37 | timed_thinclient_to_vm_mapping.start_date,
38 | timed_thinclient_to_vm_mapping.end_date,
39 | 0 AS prio,
40 | timed_thinclient_to_vm_mapping.shutdown_vm
41 | FROM
42 | timed_thinclient_to_vm_mapping
43 | WHERE (
44 | (timed_thinclient_to_vm_mapping.start_date IS NULL)
45 | AND
46 | (timed_thinclient_to_vm_mapping.end_date IS NULL)
47 | )
48 | UNION SELECT
49 | timed_thinclient_to_vm_mapping.id,
50 | timed_thinclient_to_vm_mapping.thinclient,
51 | timed_thinclient_to_vm_mapping.vm,
52 | timed_thinclient_to_vm_mapping.resolution,
53 | timed_thinclient_to_vm_mapping.start_date,
54 | timed_thinclient_to_vm_mapping.end_date,
55 | 1 AS prio,
56 | timed_thinclient_to_vm_mapping.shutdown_vm
57 | FROM
58 | timed_thinclient_to_vm_mapping
59 | WHERE (
60 | (timed_thinclient_to_vm_mapping.start_date <= now())
61 | AND
62 | (timed_thinclient_to_vm_mapping.end_date IS NULL))
63 | UNION SELECT
64 | timed_thinclient_to_vm_mapping.id,
65 | timed_thinclient_to_vm_mapping.thinclient,
66 | timed_thinclient_to_vm_mapping.vm,
67 | timed_thinclient_to_vm_mapping.resolution,
68 | timed_thinclient_to_vm_mapping.start_date,
69 | timed_thinclient_to_vm_mapping.end_date,
70 | 2 AS prio,
71 | timed_thinclient_to_vm_mapping.shutdown_vm
72 | FROM
73 | timed_thinclient_to_vm_mapping
74 | WHERE (
75 | (now() >= timed_thinclient_to_vm_mapping.start_date)
76 | AND
77 | (now() <= timed_thinclient_to_vm_mapping.end_date)
78 | )
79 | ) f
80 | ORDER BY
81 | f.prio DESC,
82 | f.start_date,
83 | f.id;
84 |
85 | --
86 | -- add domain to thinclient dhcp hostname
87 | --
88 |
89 | CREATE VIEW dhcphostname_to_thinclient_auto_mapping AS
90 | SELECT DISTINCT
91 | (((timed_thinclient_to_vm_mapping.thinclient)::text || '.thinclients.yourdomain.site'::text))::character varying AS dhcp_hostname,
92 | timed_thinclient_to_vm_mapping.thinclient
93 | FROM
94 | timed_thinclient_to_vm_mapping
95 | UNION SELECT DISTINCT
96 | timed_thinclient_to_vm_mapping.thinclient AS dhcp_hostname,
97 | timed_thinclient_to_vm_mapping.thinclient
98 | FROM
99 | timed_thinclient_to_vm_mapping;
100 |
101 | --
102 | -- assign dhcp hostname to thinclient
103 | --
104 |
105 | CREATE TABLE dhcphostname_to_thinclient_mapping (
106 | dhcp_hostname character varying NOT NULL,
107 | thinclient character varying NOT NULL
108 | );
109 |
110 | --
111 | -- assign systemuid to thinclient
112 | --
113 |
114 | CREATE TABLE systemuuid_to_thinclient_mapping (
115 | systemuuid character varying NOT NULL,
116 | thinclient character varying NOT NULL
117 | );
118 |
119 | --
120 | -- view combining dhcp host, system id and thinclient
121 | --
122 |
123 | CREATE VIEW sysinfo_to_thinclient_mapping AS
124 | SELECT
125 | f.dhcp_hostname,
126 | f.systemuuid,
127 | f.thinclient,
128 | f.prio
129 | FROM (
130 | SELECT
131 | dhcphostname_to_thinclient_auto_mapping.dhcp_hostname,
132 | NULL::character varying AS systemuuid,
133 | dhcphostname_to_thinclient_auto_mapping.thinclient,
134 | 100 AS prio
135 | FROM
136 | dhcphostname_to_thinclient_auto_mapping
137 | UNION SELECT
138 | dhcphostname_to_thinclient_mapping.dhcp_hostname,
139 | NULL::character varying AS systemuuid,
140 | dhcphostname_to_thinclient_mapping.thinclient,
141 | 200 AS prio
142 | FROM
143 | dhcphostname_to_thinclient_mapping
144 | UNION SELECT
145 | NULL::character varying AS dhcp_hostname,
146 | systemuuid_to_thinclient_mapping.systemuuid,
147 | systemuuid_to_thinclient_mapping.thinclient,
148 | 300 AS prio
149 | FROM
150 | systemuuid_to_thinclient_mapping
151 | ) f
152 | ORDER BY
153 | f.prio DESC;
154 |
155 | --
156 | -- View combining all tables concerning thin client
157 | --
158 |
159 | CREATE VIEW thinclient_everything_view AS
160 | SELECT DISTINCT
161 | s.thinclient,
162 | c.vm,
163 | c.resolution,
164 | s.dhcp_hostname,
165 | s.systemuuid,
166 | c.id,
167 | c.start_date,
168 | c.end_date,
169 | c.prio,
170 | c.shutdown_vm
171 | FROM (
172 | sysinfo_to_thinclient_mapping s
173 | LEFT JOIN current_thinclient_to_vm_mapping c ON (((s.thinclient)::text = (c.thinclient)::text))
174 | )
175 | ORDER BY
176 | c.prio DESC,
177 | c.start_date,
178 | c.id;
179 |
180 | CREATE SEQUENCE timed_thinclient_to_vm_mapping_id_seq
181 | START WITH 1 INCREMENT BY 1 NO MINVALUE NO MAXVALUE CACHE 1;
182 |
183 | ALTER TABLE ONLY timed_thinclient_to_vm_mapping
184 | ALTER COLUMN id
185 | SET DEFAULT nextval('timed_thinclient_to_vm_mapping_id_seq'::regclass);
186 |
187 | ALTER TABLE ONLY dhcphostname_to_thinclient_mapping
188 | ADD CONSTRAINT dhcphostname_to_thinclient_mapping_pkey PRIMARY KEY (dhcp_hostname);
189 |
190 | ALTER TABLE ONLY systemuuid_to_thinclient_mapping
191 | ADD CONSTRAINT systemuuid_to_thinclient_mapping_pkey PRIMARY KEY (systemuuid);
192 |
193 | ALTER TABLE ONLY timed_thinclient_to_vm_mapping
194 | ADD CONSTRAINT timed_thinclient_to_vm_mapping_pkey PRIMARY KEY (id);
195 |
--------------------------------------------------------------------------------
/sample_config/generatesql-statements.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | ROOMS="test01 test02 test03 test04 test05 test06 test07 test08 test09 test10"
4 |
5 | for ROOM in $ROOMS; do
6 | IDs=$(seq 1 30)
7 | echo "# Room ${ROOM}"
8 | for ID in ${IDs}; do
9 | ID_TWODIGIT=$(printf "%02d" ${ID})
10 | TC_NAME="${ROOM}-tc${ID_TWODIGIT}"
11 | VM_NAME="${ROOM}-vd${ID_TWODIGIT}"
12 | cat <<-ENDofSQL
13 | UPDATE timed_thinclient_to_vm_mapping
14 | SET vm='${VM_NAME}' WHERE thinclient='${TC_NAME}'
15 | AND start_date IS NULL AND end_date IS NULL;
16 |
17 | ENDofSQL
18 | done
19 | echo
20 | done
21 |
22 |
--------------------------------------------------------------------------------
/sample_config/virtesk-tc-tools.conf:
--------------------------------------------------------------------------------
1 | # Configuration for virtesk-tc-tools.
2 |
3 | # Documentation:
4 | # * see doc/virtesk-tc-tools.rst
5 |
6 | # DEVELOPER_MODE=0 =====> quiet mode
7 | # DEVELOPER_MODE=1 =====> verbose debug messages
8 | DEVELOPER_MODE=0
9 |
10 | # Domain appended to thinclient short names
11 | TC_DOMAIN=myorganization.mydomain
12 |
13 | # SSH options for tc_ssh
14 | SSH_GLOBAL_OPTS="-q -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o ConnectTimeout=4 -i /etc/virtesk-vdi/virtesk-thinclient-ssh-private-key-id_rsa"
15 |
16 | # Commands to run on a thinclient in order
17 | # to re-install itself using kexec and kickstart
18 | # Please adjust the URLs to point to the correct locations
19 | # on your infrastructure server.
20 | # Kernel commandline should be the same as when doing PXE rollout.
21 | ROLLOUT_CMDLINE='rm vmlinuz; rm initrd.img; wget http://infrastructure-server/tftpboot/fedora22-x86_64-pxeboot/vmlinuz; wget http://infrastructure-server/tftpboot/fedora22-x86_64-pxeboot/initrd.img; kexec -l vmlinuz --initrd=initrd.img --reset-vga --append="net.ifnames=0 enforcing=0 inst.ks=http://infrastructure-server/mirror/private/thinclients/kickstart/tc_rollout.ks"; shutdown -r now'
22 |
23 | # Commands to run on a thinclient in order to generate a screenshot
24 | # and to write it to standart output.
25 | SCREENSHOT_CMDLINE="DISPLAY=:0 xwd -root | convert - png:-"
26 |
27 | # Directory where screenshots shall be stored.
28 | SCREENSHOT_DIR=/screenshot
29 |
30 |
--------------------------------------------------------------------------------
/sample_config/virtesk-vm-rollout.conf:
--------------------------------------------------------------------------------
1 | # Section holding general settings
2 | [general]
3 | # ADJUST: sftp-server
4 | sftp_floppy_upload_cmd = "(echo put {0}; echo chmod 666 {1}; echo ls -l {1}) | sftp sftp-floppy-upload@sftp-server:/floppy/"
5 | # ADJUST: sftp-server
6 | sftp_floppy_cleanup_cmd = "echo rm {0} | sftp sftp-floppy-upload@sftp-server:/floppy/"
7 | # ADJUST: nfs-mount-point
8 | ovirt_worker_floppy_prefix = "/rhev/data-center/mnt/nfs-mount-point/floppy"
9 | [[connect]]
10 | # ADJUST: ovirt-manager hostname
11 | url = "https://ovirt-manager/api"
12 | # ADJUST: Username (any admin account is fine)
13 | username = "admin@internal"
14 | # ADJUST: Password
15 | password = "PASSWORD"
16 | ca_file = "ca.crt"
17 | persistent_auth = True
18 | renew_session = True
19 |
20 | [logging]
21 | config_file=logging.conf
22 | log_file=/var/log/virtesk-vdi/virtesk-virtroom.log
23 |
24 | # ADJUST: everything.
25 | [room test01]
26 | [[teacher_vms]]
27 | ids = "[1]"
28 | names = "${roomname}-vd${id}"
29 | ip_addresses_suffix = 2
30 | ip_addresses = "192.0.2.$suffix"
31 | template_name = "vdi-teachers-010"
32 | description = "LehrerVM"
33 | tc_user = "ovirt.thinclient@mydomain.site"
34 | memory = 4 * 1024 * 1024 * 1024
35 | cluster = Default
36 | workaround_os="rhel_7x64"
37 | workaround_timezone="Etc/GMT"
38 | os="windows_7x64"
39 | timezone="W. Europe Standard Time"
40 | autounattend_templatefile = "Autounattend-production.xml.template"
41 | netmask_suffix=24
42 | network_name="mynetwork"
43 | default_gateway=192.0.2.1
44 | usb = enabled
45 | rollout_startvm = True
46 | reset_startvm = Always
47 | snapshot_description = "Automatic snapshot after virtesk-vmrollout, IP=${ip}/${netmask_as_suffix}, scripttime=${scripttime}"
48 | reset_to_snapshot_regex = "Automatic snapshot after virtesk-vmrollout, .*"
49 | stateless = False
50 |
51 | [[student_vms]]
52 | ids = "range(2,4+1)"
53 | names = "${roomname}-vd${id}"
54 | ip_addresses_suffix = 2
55 | ip_addresses = "192.0.2.$suffix"
56 | template_name = "vdi-students-010"
57 | description = "SchuelerVM"
58 | tc_user = "ovirt.thinclient@mydomain.site"
59 | memory = 4 * 1024 * 1024 * 1024
60 | cluster = Default
61 | workaround_os="rhel_7x64"
62 | workaround_timezone="Etc/GMT"
63 | os="windows_7x64"
64 | timezone="W. Europe Standard Time"
65 | autounattend_templatefile = "Autounattend-production.xml.template"
66 | netmask_suffix=21
67 | network_name="mynetwork"
68 | default_gateway=192.0.2.1
69 | usb = enabled
70 | rollout_startvm = True
71 | reset_startvm = Auto
72 | snapshot_description = "Automatic snapshot after virtesk-vmrollout, IP=${ip}/${netmask_as_suffix}, scripttime=${scripttime}"
73 | reset_to_snapshot_regex = "Automatic snapshot after virtesk-vmrollout, .*"
74 | stateless = False
75 |
76 |
--------------------------------------------------------------------------------
/virtesk-tc-connectspice/Makefile:
--------------------------------------------------------------------------------
1 | all:
2 | echo no default make target...
3 |
4 | clean:
5 | rm -f *.pyc
6 |
7 | #release: clean
8 | # tar -C /root -czf /var/www/mirror/private/thinclients/thinclient-software/connect_spice_client-new.tar.gz connect_spice_client
9 | # mv -f /var/www/mirror/private/thinclients/thinclient-software/connect_spice_client-new.tar.gz /var/www/mirror/private/thinclients/thinclient-software/connect_spice_client-dev.tar.gz
10 |
11 | release: clean
12 | tar --transform 's,^,virtesk-tc-connectspice/,S' -czf /var/www/mirror/private/thinclients/thinclient-software/connect_spice_client-new.tar.gz *.py virtesk-tc-connectspice-shutdown-vm virtesk-tc-connectspice-main
13 | echo mv -f /var/www/mirror/private/thinclients/thinclient-software/connect_spice_client-new.tar.gz /var/www/mirror/private/thinclients/thinclient-software/connect_spice_client-dev.tar.gz
14 |
15 | flake8:
16 | flake8 --doctests -j auto --ignore=E221,E222,E251,E272,E241,E203 *.py virtesk-tc-connectspice-*
17 | flake8-strict:
18 | flake8 --doctests -j auto *.py virtesk-tc-connectspice-*
19 | indention_report:
20 | autopep8 . --recursive --select=E101,E121 --diff
21 | indention_fix:
22 | autopep8 . --recursive --select=E101,E121 --in-place
23 | autopep8_report:
24 | autopep8 . --recursive --diff
25 |
26 |
27 |
--------------------------------------------------------------------------------
/virtesk-tc-connectspice/conftest.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: UTF-8 -*-
3 | # vim: autoindent expandtab tabstop=4 sw=4 sts=4 filetype=python
4 |
5 | # Copyright (c) 2013-2016, Adfinis SyGroup AG
6 | #
7 | # This file is part of Virtesk VDI.
8 | #
9 | # Virtesk VDI is free software: you can redistribute it and/or modify
10 | # it under the terms of the GNU General Public License as published by
11 | # the Free Software Foundation, either version 3 of the License, or
12 | # (at your option) any later version.
13 | #
14 | # Virtesk VDI is distributed in the hope that it will be useful,
15 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
16 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 | # GNU General Public License for more details.
18 | #
19 | # You should have received a copy of the GNU General Public License
20 | # along with Virtesk VDI. If not, see .
21 |
22 | # System Imports
23 | import pytest
24 | import os.path
25 |
26 |
27 | MOCK_DATA_PATH = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'test_mock_data')
28 |
29 |
30 | @pytest.yield_fixture(scope='module')
31 | def active_connection():
32 | yield readfile('active_connection')
33 |
34 |
35 | @pytest.yield_fixture(scope='module')
36 | def nmcli_con_show_empty():
37 | yield readfile('nmcli_con_show_adsy_eap_empty')
38 |
39 |
40 | @pytest.yield_fixture(scope='module')
41 | def nmcli_con_show():
42 | yield readfile('nmcli_con_show_adsy_eap')
43 |
44 |
45 | @pytest.yield_fixture(scope='module')
46 | def nmcli_device_show_single_line():
47 | yield readfile('nmcli_device_show_single_line')
48 |
49 |
50 | @pytest.yield_fixture(scope='module')
51 | def nmcli_device_show():
52 | yield readfile('nmcli_device_show')
53 |
54 |
55 | @pytest.yield_fixture(scope='module')
56 | def hostnamectl_transient():
57 | yield readfile('hostnamectl_transient')
58 |
59 | @pytest.yield_fixture(scope='module')
60 | def hostnamectl_transient_empty():
61 | yield readfile('hostnamectl_transient_empty')
62 |
63 | def readfile(filename):
64 | with open(os.path.join(MOCK_DATA_PATH, filename), 'r') as f:
65 | return f.read()
66 |
--------------------------------------------------------------------------------
/virtesk-tc-connectspice/find_thinclient_identifier.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: UTF-8 -*-
3 | # vim: autoindent expandtab tabstop=4 sw=4 sts=4 filetype=python
4 |
5 | # Copyright (c) 2013-2016, Adfinis SyGroup AG
6 | #
7 | # This file is part of Virtesk VDI.
8 | #
9 | # Virtesk VDI is free software: you can redistribute it and/or modify
10 | # it under the terms of the GNU General Public License as published by
11 | # the Free Software Foundation, either version 3 of the License, or
12 | # (at your option) any later version.
13 | #
14 | # Virtesk VDI is distributed in the hope that it will be useful,
15 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
16 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 | # GNU General Public License for more details.
18 | #
19 | # You should have received a copy of the GNU General Public License
20 | # along with Virtesk VDI. If not, see .
21 |
22 | # System Imports
23 | import os
24 | import re
25 | import logging
26 | import subprocess
27 | from find_thinclient_identifier_nmcli import extract_identifiers_from_nmcli
28 |
29 |
30 | def get_dmidecode_sysuuid():
31 | result = []
32 |
33 | dmi = subprocess.check_output("sudo dmidecode -t1", shell=True)
34 | for line in dmi.splitlines():
35 | match_uuid = re.search('UUID:\s+([0-9A-Za-z_-]+)', line)
36 | if match_uuid:
37 | result.append(match_uuid.group(1).upper())
38 | return result
39 |
40 |
41 | def process_ip(ip):
42 | # RHEV-tags cannot contain dots in their names.
43 | # so we replace dots by hyphens.
44 | return ip.replace('.', '-')
45 |
46 |
47 | def get_thinclient_identifiers():
48 | (hostnames, fixedips) = extract_identifiers_from_nmcli()
49 | identifiers = (["thinclient-hostname-%s" % x for x in hostnames] +
50 | ["thinc*ient-hostname-%s" % x for x in hostnames] +
51 | ["thinclient-ip-%s" % process_ip(x) for x in fixedips] +
52 | ["thinc*ient-ip-%s" % process_ip(x) for x in fixedips])
53 | logging.debug("Found the following thinclient identifiers: %s",
54 | ", ".join(identifiers))
55 | return identifiers
56 |
57 |
58 | def get_dhcp_hostnames():
59 | hostnames, _ = extract_identifiers_from_nmcli()
60 | return hostnames
61 |
62 |
63 | def main():
64 | print get_thinclient_identifiers()
65 |
66 | if __name__ == "__main__":
67 | main()
68 |
--------------------------------------------------------------------------------
/virtesk-tc-connectspice/find_thinclient_identifier_nmcli.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: UTF-8 -*-
3 | # vim: autoindent expandtab tabstop=4 sw=4 sts=4 filetype=python
4 |
5 | # Copyright (c) 2013-2016, Adfinis SyGroup AG
6 | #
7 | # This file is part of Virtesk VDI.
8 | #
9 | # Virtesk VDI is free software: you can redistribute it and/or modify
10 | # it under the terms of the GNU General Public License as published by
11 | # the Free Software Foundation, either version 3 of the License, or
12 | # (at your option) any later version.
13 | #
14 | # Virtesk VDI is distributed in the hope that it will be useful,
15 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
16 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 | # GNU General Public License for more details.
18 | #
19 | # You should have received a copy of the GNU General Public License
20 | # along with Virtesk VDI. If not, see .
21 |
22 | # System Imports
23 | import subprocess
24 | import re
25 |
26 |
27 | def extract_identifiers_from_nmcli():
28 | fixedips = []
29 | hostnames = []
30 | nmcli_output = subprocess.check_output(['nmcli', 'device', 'show'], env={'LC_ALL': 'C'})
31 | for line in nmcli_output.splitlines():
32 | if re.match('^IP4\.ADDRESS.', line):
33 | key, value = get_line_key_value(line)
34 | value = value[:value.index("/")].strip()
35 | fixedips.append(value)
36 | elif re.match('^GENERAL\.CONNECTION.', line):
37 | key, value = get_line_key_value(line)
38 | dhcp_hostname = get_dhcp_hostname_from_connection(value)
39 | if dhcp_hostname:
40 | hostnames.append(dhcp_hostname)
41 | hostnamectl_hostname = extract_hostname_from_hostnamectl()
42 | if hostnamectl_hostname and hostnamectl_hostname not in hostnames:
43 | hostnames.append(hostnamectl_hostname)
44 | return (hostnames, fixedips)
45 |
46 |
47 | def extract_hostname_from_hostnamectl():
48 | hostnamectl_output = subprocess.check_output(['hostnamectl'], env={'LC_ALL': 'C'})
49 | for line in hostnamectl_output.splitlines():
50 | if re.match('^Transient', line):
51 | key, value = get_line_key_value(line)
52 | return value
53 |
54 |
55 | def get_dhcp_hostname_from_connection(name):
56 | if name and name != '--':
57 | nmcli_output = subprocess.check_output(['nmcli', 'con', 'show', name], env={'LC_ALL': 'C'})
58 | for line in nmcli_output.splitlines():
59 | if re.match('^ipv4\.dhcp-hostname.', line):
60 | key, value = get_line_key_value(line)
61 | if value != '--':
62 | return value
63 |
64 |
65 | def get_line_key_value(line):
66 | if line:
67 | values = str(line).split(':')
68 | if len(values) == 2:
69 | key, value = values
70 | value = value.strip()
71 | return (key, value)
72 |
73 |
74 | def get_active_connections():
75 | nmcli_output = subprocess.check_output(['nmcli', '-t', '-f', 'state', 'con', 'show', '--active'], env={'LC_ALL': 'C'})
76 | return len(nmcli_output.splitlines())
77 |
78 | def main():
79 | print(extract_identifiers_from_nmcli())
80 |
81 |
82 | if __name__ == "__main__":
83 | main()
84 |
--------------------------------------------------------------------------------
/virtesk-tc-connectspice/spice_xpi_controller.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: UTF-8 -*-
3 | # vim: autoindent expandtab tabstop=4 sw=4 sts=4 filetype=python
4 |
5 | """
6 | Implements the binary protocol [0] over a unix domain socket necessary for
7 | parameter passing, configuration and controlling a spice client.
8 |
9 | Tested with remote-viewer.
10 |
11 | Only the sending side is implemented.
12 | The receiving side has been omitted, because it wasn't necessary.
13 |
14 | Please be aware that the specification [0] contains many errors, so for real
15 | hacking, you might want to consult the source code of spice-xpi:
16 | git clone git://anongit.freedesktop.org/spice/spice-xpi
17 |
18 | [0]: http://spice-space.org/page/Whiteboard/ControllerProtocol
19 | """
20 |
21 | # Copyright (c) 2013-2016, Adfinis SyGroup AG
22 | #
23 | # This file is part of Virtesk VDI
24 | #
25 | # Virtesk VDI is free software: you can redistribute it and/or modify
26 | # it under the terms of the GNU General Public License as published by
27 | # the Free Software Foundation, either version 3 of the License, or
28 | # (at your option) any later version.
29 | #
30 | # Virtesk VDI is distributed in the hope that it will be useful,
31 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
32 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
33 | # GNU General Public License for more details.
34 | #
35 | # You should have received a copy of the GNU General Public License
36 | # along with Virtesk VDI. If not, see .
37 |
38 |
39 | import socket
40 | import struct
41 | import logging
42 |
43 |
44 | CONTROLLER_HOST = 1
45 | CONTROLLER_PORT = 2
46 | CONTROLLER_SPORT = 3
47 | CONTROLLER_PASSWORD = 4
48 |
49 | CONTROLLER_SECURE_CHANNELS = 5
50 | CONTROLLER_DISABLE_CHANNELS = 6
51 |
52 | CONTROLLER_TLS_CIPHERS = 7
53 | CONTROLLER_CA_FILE = 8
54 | CONTROLLER_HOST_SUBJECT = 9
55 |
56 | CONTROLLER_FULL_SCREEN = 10
57 | CONTROLLER_SET_TITLE = 11
58 |
59 | CONTROLLER_CREATE_MENU = 12
60 | CONTROLLER_DELETE_MENU = 13
61 |
62 | CONTROLLER_HOTKEYS = 14
63 | CONTROLLER_SEND_CAD = 15
64 |
65 | CONTROLLER_CONNECT = 16
66 | CONTROLLER_SHOW = 17
67 | CONTROLLER_HIDE = 18
68 |
69 | CONTROLLER_ENABLE_SMARTCARD = 19
70 |
71 | CONTROLLER_COLOR_DEPTH = 20
72 | CONTROLLER_DISABLE_EFFECTS = 21
73 |
74 | CONTROLLER_ENABLE_USB = 22
75 | CONTROLLER_ENABLE_USB_AUTOSHARE = 23
76 | CONTROLLER_USB_FILTER = 24
77 |
78 |
79 | def ControllerValue(message_id, arg):
80 | result = struct.pack("=III", message_id, 12, arg)
81 | logging.debug("INT: message_id: %s, ARG: %s, STRUCT: %s" %
82 | (message_id, arg, result))
83 | return result
84 |
85 |
86 | def ControllerValueBoolean(message_id, arg):
87 | arg_boolean = 1 if arg else 0
88 | result = struct.pack("=III", message_id, 12, arg_boolean)
89 | logging.debug("Bool: message_id: %s, ARG: %s, STRUCT: %s" %
90 | (message_id, arg, result))
91 | return result
92 |
93 |
94 | def ControllerDataString(message_id, arg):
95 | argplusnull = arg + '\0'
96 | b = argplusnull.encode('ascii')
97 | fmt = "=II%ds" % len(b)
98 | size = len(b) + 8
99 |
100 | result = struct.pack(fmt, message_id, size, argplusnull)
101 | logging.debug("STRING: message_id: %s, ARG: %s, LEN: %d/%d, STRUCT: %s" %
102 | (message_id, arg, size, len(result), result))
103 | return result
104 |
105 |
106 | def ControllerMsg(message_id):
107 | result = struct.pack("=II", message_id, 8)
108 | return result
109 |
110 |
111 | def connect(
112 | socket_filename, host, port, secport, ticket, spice_ca_file,
113 | secure_channels=None, disable_channels=None, tls_ciphers=None,
114 | host_subject=None, window_title=None, hotkeys=None,
115 | disable_effects=None, ctrl_alt_delete=None, enable_usb=None,
116 | enable_usb_autoshare=None, usb_filter=None, **rest
117 | ):
118 | s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
119 | s.connect(socket_filename)
120 |
121 | # send CONTROLLER_INIT
122 |
123 | magic = 0x4C525443
124 | version = 1
125 | size = 24
126 |
127 | credentials = 0
128 | flags = 1
129 |
130 | s.send(struct.pack("=IIIQI", magic, version, size, credentials, flags))
131 |
132 | # send CONTROLLER_HOST
133 | s.send(ControllerDataString(CONTROLLER_HOST, host))
134 |
135 | # send CONTROLLER_PORT
136 | if port is not None:
137 | s.send(ControllerValue(CONTROLLER_PORT, port))
138 |
139 | # send CONTROLLER_SPORT
140 | if secport is not None:
141 | s.send(ControllerValue(CONTROLLER_SPORT, secport))
142 |
143 | # send CONTROLLER_PASSWORD
144 | s.send(ControllerDataString(CONTROLLER_PASSWORD, ticket))
145 |
146 | # send CONTROLLER_FULL_SCREEN
147 | s.send(ControllerValue(CONTROLLER_FULL_SCREEN, 1))
148 |
149 | # CA_FILE
150 | s.send(ControllerDataString(CONTROLLER_CA_FILE, spice_ca_file))
151 |
152 | # CONTROLLER_HOST_SUBJECT
153 | if host_subject is not None:
154 | s.send(ControllerDataString(CONTROLLER_HOST_SUBJECT, host_subject))
155 |
156 | # TLS_CIPHERS
157 | if tls_ciphers is not None:
158 | s.send(ControllerDataString(CONTROLLER_TLS_CIPHERS, tls_ciphers))
159 |
160 | # SECURE_CHANNELS
161 | if secure_channels is not None:
162 | s.send(ControllerDataString(
163 | CONTROLLER_SECURE_CHANNELS, secure_channels))
164 |
165 | if disable_channels is not None:
166 | s.send(ControllerDataString(
167 | CONTROLLER_DISABLE_CHANNELS, disable_channels))
168 |
169 | # CONTROLLER_SET_TITLE
170 | if window_title is not None:
171 | s.send(ControllerDataString(CONTROLLER_SET_TITLE, window_title))
172 |
173 | if hotkeys is not None:
174 | s.send(ControllerDataString(CONTROLLER_HOTKEYS, hotkeys))
175 |
176 | if ctrl_alt_delete is not None:
177 | s.send(ControllerValueBoolean(CONTROLLER_SEND_CAD, ctrl_alt_delete))
178 |
179 | if disable_effects is not None:
180 | s.send(ControllerDataString(
181 | CONTROLLER_DISABLE_EFFECTS, disable_effects))
182 |
183 | if enable_usb is not None:
184 | s.send(ControllerValueBoolean(CONTROLLER_ENABLE_USB, enable_usb))
185 |
186 | if enable_usb_autoshare is not None:
187 | s.send(ControllerValueBoolean(
188 | CONTROLLER_ENABLE_USB_AUTOSHARE, enable_usb_autoshare))
189 |
190 | if usb_filter is not None:
191 | s.send(ControllerDataString(CONTROLLER_USB_FILTER, usb_filter))
192 |
193 | # CONNECT
194 | s.send(ControllerMsg(CONTROLLER_CONNECT))
195 |
196 | s.send(ControllerMsg(CONTROLLER_SHOW))
197 |
198 | s.close()
199 |
--------------------------------------------------------------------------------
/virtesk-tc-connectspice/test_find_thinclient_identifier_nmcli.py:
--------------------------------------------------------------------------------
1 | import find_thinclient_identifier_nmcli as find_nmcli
2 |
3 |
4 | def test_extract_identifiers_from_nmcli(mock, nmcli_device_show, nmcli_con_show, nmcli_con_show_empty, hostnamectl_transient):
5 | def my_check_output(cmd, **kwargs):
6 | if cmd[:4] == ['nmcli', 'con', 'show', 'ADSY-EAP']:
7 | return nmcli_con_show
8 | elif cmd[:3] == ['nmcli', 'con', 'show']:
9 | return nmcli_con_show_empty
10 | elif cmd[:3] == ['nmcli', 'device', 'show']:
11 | return nmcli_device_show
12 | elif cmd[:1] == ['hostnamectl']:
13 | return hostnamectl_transient
14 | mock.patch('find_thinclient_identifier_nmcli.subprocess.check_output', my_check_output)
15 | return_value = find_nmcli.extract_identifiers_from_nmcli()
16 |
17 | assert return_value == (['a-hostname-appeared', 'transient-hostname'], ['172.17.0.1', '10.9.5.185', '127.0.0.1'])
18 |
19 |
20 | def test_get_dhcp_hostname_from_connection(mock, nmcli_con_show):
21 | patched_check_output = mock.patch('find_thinclient_identifier_nmcli.subprocess.check_output')
22 | patched_check_output.return_value = nmcli_con_show
23 | return_value = find_nmcli.get_dhcp_hostname_from_connection('SOME-NAME')
24 | assert return_value == 'a-hostname-appeared'
25 |
26 |
27 | def test_get_dhcp_hostname_from_connection_empty(mock, nmcli_con_show_empty):
28 | patched_check_output = mock.patch('find_thinclient_identifier_nmcli.subprocess.check_output')
29 | patched_check_output.return_value = nmcli_con_show_empty
30 | return_value = find_nmcli.get_dhcp_hostname_from_connection('SOME-NAME')
31 | assert return_value is None
32 |
33 |
34 | def test_get_line_key_value(nmcli_device_show_single_line):
35 | return_value = find_nmcli.get_line_key_value(nmcli_device_show_single_line)
36 | key, value = return_value
37 | assert key == 'IP4.ADDRESS[1]'
38 | assert value == '10.9.5.185/16'
39 |
40 |
41 | def test_get_line_key_value_none():
42 | return_value = find_nmcli.get_line_key_value('')
43 | assert return_value is None
44 |
45 |
46 | def test_get_active_connections(mock, active_connection):
47 | patched_check_output = mock.patch('find_thinclient_identifier_nmcli.subprocess.check_output')
48 | patched_check_output.return_value = active_connection
49 | return_value = find_nmcli.get_active_connections()
50 | assert return_value == 2
51 |
52 |
53 | def test_get_hostname_from_hostnamectl(mock, hostnamectl_transient):
54 | patched_check_output = mock.patch('find_thinclient_identifier_nmcli.subprocess.check_output')
55 | patched_check_output.return_value = hostnamectl_transient
56 | return_value = find_nmcli.extract_hostname_from_hostnamectl()
57 | assert return_value == 'transient-hostname'
58 |
59 |
60 | def test_get_hostname_from_hostnamectl_empty(mock, hostnamectl_transient_empty):
61 | patched_check_output = mock.patch('find_thinclient_identifier_nmcli.subprocess.check_output')
62 | patched_check_output.return_value = hostnamectl_transient_empty
63 | return_value = find_nmcli.extract_hostname_from_hostnamectl()
64 | assert return_value == None
65 |
--------------------------------------------------------------------------------
/virtesk-tc-connectspice/test_mock_data/active_connection:
--------------------------------------------------------------------------------
1 | activated
2 | activated
3 |
--------------------------------------------------------------------------------
/virtesk-tc-connectspice/test_mock_data/hostnamectl_transient:
--------------------------------------------------------------------------------
1 | Static hostname: static-hostname
2 | Transient hostname: transient-hostname
3 | Icon name: computer-laptop
4 | Chassis: laptop
5 | Machine ID: 11111111111111111111111111111111
6 | Boot ID: 11111111111111111111111111111111
7 | Operating System: Ubuntu
8 | Kernel: Linux 4.4.0-53-generic
9 | Architecture: x86-64
10 |
--------------------------------------------------------------------------------
/virtesk-tc-connectspice/test_mock_data/hostnamectl_transient_empty:
--------------------------------------------------------------------------------
1 | Static hostname: static-hostname
2 | Icon name: computer-laptop
3 | Chassis: laptop
4 | Machine ID: 11111111111111111111111111111111
5 | Boot ID: 11111111111111111111111111111111
6 | Operating System: Ubuntu
7 | Kernel: Linux 4.4.0-53-generic
8 | Architecture: x86-64
9 |
--------------------------------------------------------------------------------
/virtesk-tc-connectspice/test_mock_data/nmcli_con_show_adsy_eap:
--------------------------------------------------------------------------------
1 | connection.id: ADSY-EAP
2 | connection.uuid: f3008792-bd40-4bbe-9b4d-106eac03c9f9
3 | connection.interface-name: --
4 | connection.type: 802-11-wireless
5 | connection.autoconnect: yes
6 | connection.autoconnect-priority: 0
7 | connection.timestamp: 1481184404
8 | connection.read-only: no
9 | connection.permissions: user:john
10 | connection.zone: --
11 | connection.master: --
12 | connection.slave-type: --
13 | connection.autoconnect-slaves: -1 (default)
14 | connection.secondaries:
15 | connection.gateway-ping-timeout: 0
16 | connection.metered: unknown
17 | connection.lldp: -1 (default)
18 | 802-1x.eap: ttls
19 | 802-1x.identity: johnw
20 | 802-1x.anonymous-identity: --
21 | 802-1x.pac-file: --
22 | 802-1x.ca-cert: --
23 | 802-1x.ca-path: --
24 | 802-1x.subject-match: --
25 | 802-1x.altsubject-matches:
26 | 802-1x.domain-suffix-match: --
27 | 802-1x.client-cert: --
28 | 802-1x.phase1-peapver: --
29 | 802-1x.phase1-peaplabel: --
30 | 802-1x.phase1-fast-provisioning: --
31 | 802-1x.phase2-auth: mschapv2
32 | 802-1x.phase2-autheap: --
33 | 802-1x.phase2-ca-cert: --
34 | 802-1x.phase2-ca-path: --
35 | 802-1x.phase2-subject-match: --
36 | 802-1x.phase2-altsubject-matches:
37 | 802-1x.phase2-domain-suffix-match: --
38 | 802-1x.phase2-client-cert: --
39 | 802-1x.password:
40 | 802-1x.password-flags: 1 (agent-owned)
41 | 802-1x.password-raw:
42 | 802-1x.password-raw-flags: 0 (none)
43 | 802-1x.private-key: --
44 | 802-1x.private-key-password:
45 | 802-1x.private-key-password-flags: 0 (none)
46 | 802-1x.phase2-private-key: --
47 | 802-1x.phase2-private-key-password:
48 | 802-1x.phase2-private-key-password-flags:0 (none)
49 | 802-1x.pin:
50 | 802-1x.pin-flags: 0 (none)
51 | 802-1x.system-ca-certs: no
52 | 802-11-wireless.ssid: ADSY-EAP
53 | 802-11-wireless.mode: infrastructure
54 | 802-11-wireless.band: --
55 | 802-11-wireless.channel: 0
56 | 802-11-wireless.bssid: --
57 | 802-11-wireless.rate: 0
58 | 802-11-wireless.tx-power: 0
59 | 802-11-wireless.mac-address: --
60 | 802-11-wireless.cloned-mac-address: --
61 | 802-11-wireless.mac-address-blacklist:
62 | 802-11-wireless.mac-address-randomization:default
63 | 802-11-wireless.mtu: auto
64 | 802-11-wireless.seen-bssids: 06:27:22:F1:EE:54
65 | 802-11-wireless.hidden: no
66 | 802-11-wireless.powersave: default (0)
67 | 802-11-wireless-security.key-mgmt: wpa-eap
68 | 802-11-wireless-security.wep-tx-keyidx: 0
69 | 802-11-wireless-security.auth-alg: --
70 | 802-11-wireless-security.proto:
71 | 802-11-wireless-security.pairwise:
72 | 802-11-wireless-security.group:
73 | 802-11-wireless-security.leap-username: --
74 | 802-11-wireless-security.wep-key0:
75 | 802-11-wireless-security.wep-key1:
76 | 802-11-wireless-security.wep-key2:
77 | 802-11-wireless-security.wep-key3:
78 | 802-11-wireless-security.wep-key-flags: 0 (none)
79 | 802-11-wireless-security.wep-key-type: 0 (unknown)
80 | 802-11-wireless-security.psk:
81 | 802-11-wireless-security.psk-flags: 0 (none)
82 | 802-11-wireless-security.leap-password:
83 | 802-11-wireless-security.leap-password-flags:0 (none)
84 | ipv4.method: auto
85 | ipv4.dns:
86 | ipv4.dns-search:
87 | ipv4.dns-options: (default)
88 | ipv4.addresses:
89 | ipv4.gateway: --
90 | ipv4.routes:
91 | ipv4.route-metric: -1
92 | ipv4.ignore-auto-routes: no
93 | ipv4.ignore-auto-dns: no
94 | ipv4.dhcp-client-id: --
95 | ipv4.dhcp-timeout: 0
96 | ipv4.dhcp-send-hostname: yes
97 | ipv4.dhcp-hostname: a-hostname-appeared
98 | ipv4.dhcp-fqdn: --
99 | ipv4.never-default: no
100 | ipv4.may-fail: yes
101 | ipv4.dad-timeout: -1 (default)
102 | ipv6.method: auto
103 | ipv6.dns:
104 | ipv6.dns-search:
105 | ipv6.dns-options: (default)
106 | ipv6.addresses:
107 | ipv6.gateway: --
108 | ipv6.routes:
109 | ipv6.route-metric: -1
110 | ipv6.ignore-auto-routes: no
111 | ipv6.ignore-auto-dns: no
112 | ipv6.never-default: no
113 | ipv6.may-fail: yes
114 | ipv6.ip6-privacy: -1 (unknown)
115 | ipv6.addr-gen-mode: stable-privacy
116 | ipv6.dhcp-send-hostname: yes
117 | ipv6.dhcp-hostname: --
118 | GENERAL.NAME: ADSY-EAP
119 | GENERAL.UUID: f3008792-bd40-4bbe-9b4d-106eac03c9f9
120 | GENERAL.DEVICES: wlp3s0
121 | GENERAL.STATE: activated
122 | GENERAL.DEFAULT: yes
123 | GENERAL.DEFAULT6: no
124 | GENERAL.VPN: no
125 | GENERAL.ZONE: --
126 | GENERAL.DBUS-PATH: /org/freedesktop/NetworkManager/ActiveConnection/4
127 | GENERAL.CON-PATH: /org/freedesktop/NetworkManager/Settings/3
128 | GENERAL.SPEC-OBJECT: /org/freedesktop/NetworkManager/AccessPoint/12
129 | GENERAL.MASTER-PATH: --
130 | IP4.ADDRESS[1]: 10.9.5.185/16
131 | IP4.GATEWAY: 10.9.1.1
132 | IP4.DNS[1]: 10.9.2.1
133 | IP4.DNS[2]: 10.1.2.8
134 | IP4.DNS[3]: 10.1.2.22
135 | IP4.DOMAIN[1]: adfinis-int.ch
136 | DHCP4.OPTION[1]: requested_ms_classless_static_routes = 1
137 | DHCP4.OPTION[2]: requested_domain_search = 1
138 | DHCP4.OPTION[3]: requested_host_name = 1
139 | DHCP4.OPTION[4]: requested_time_offset = 1
140 | DHCP4.OPTION[5]: requested_domain_name = 1
141 | DHCP4.OPTION[6]: filename = pxelinux.0
142 | DHCP4.OPTION[7]: requested_rfc3442_classless_static_routes = 1
143 | DHCP4.OPTION[8]: requested_wpad = 1
144 | DHCP4.OPTION[9]: requested_broadcast_address = 1
145 | DHCP4.OPTION[10]: next_server = 10.9.2.1
146 | DHCP4.OPTION[11]: requested_netbios_scope = 1
147 | DHCP4.OPTION[12]: requested_interface_mtu = 1
148 | DHCP4.OPTION[13]: requested_subnet_mask = 1
149 | DHCP4.OPTION[14]: routers = 10.9.1.1
150 | DHCP4.OPTION[15]: dhcp_message_type = 5
151 | DHCP4.OPTION[16]: ip_address = 10.9.5.185
152 | DHCP4.OPTION[17]: requested_static_routes = 1
153 | DHCP4.OPTION[18]: expiry = 1481225250
154 | DHCP4.OPTION[19]: requested_domain_name_servers = 1
155 | DHCP4.OPTION[20]: broadcast_address = 10.9.255.255
156 | DHCP4.OPTION[21]: requested_ntp_servers = 1
157 | DHCP4.OPTION[22]: domain_name = adfinis-int.ch
158 | DHCP4.OPTION[23]: dhcp_lease_time = 43200
159 | DHCP4.OPTION[24]: domain_name_servers = 10.9.2.1 10.1.2.8 10.1.2.22
160 | DHCP4.OPTION[25]: requested_netbios_name_servers = 1
161 | DHCP4.OPTION[26]: subnet_mask = 255.255.0.0
162 | DHCP4.OPTION[27]: network_number = 10.9.0.0
163 | DHCP4.OPTION[28]: requested_routers = 1
164 | DHCP4.OPTION[29]: dhcp_server_identifier = 10.9.2.1
165 | IP6.ADDRESS[1]: fe80::db41:83ec:a6e7:a7a4/64
166 | IP6.GATEWAY:
167 |
--------------------------------------------------------------------------------
/virtesk-tc-connectspice/test_mock_data/nmcli_con_show_adsy_eap_empty:
--------------------------------------------------------------------------------
1 | connection.id: ADSY-EAP
2 | connection.uuid: f3008792-bd40-4bbe-9b4d-106eac03c9f9
3 | connection.interface-name: --
4 | connection.type: 802-11-wireless
5 | connection.autoconnect: yes
6 | connection.autoconnect-priority: 0
7 | connection.timestamp: 1481184404
8 | connection.read-only: no
9 | connection.permissions: user:john
10 | connection.zone: --
11 | connection.master: --
12 | connection.slave-type: --
13 | connection.autoconnect-slaves: -1 (default)
14 | connection.secondaries:
15 | connection.gateway-ping-timeout: 0
16 | connection.metered: unknown
17 | connection.lldp: -1 (default)
18 | 802-1x.eap: ttls
19 | 802-1x.identity: johnw
20 | 802-1x.anonymous-identity: --
21 | 802-1x.pac-file: --
22 | 802-1x.ca-cert: --
23 | 802-1x.ca-path: --
24 | 802-1x.subject-match: --
25 | 802-1x.altsubject-matches:
26 | 802-1x.domain-suffix-match: --
27 | 802-1x.client-cert: --
28 | 802-1x.phase1-peapver: --
29 | 802-1x.phase1-peaplabel: --
30 | 802-1x.phase1-fast-provisioning: --
31 | 802-1x.phase2-auth: mschapv2
32 | 802-1x.phase2-autheap: --
33 | 802-1x.phase2-ca-cert: --
34 | 802-1x.phase2-ca-path: --
35 | 802-1x.phase2-subject-match: --
36 | 802-1x.phase2-altsubject-matches:
37 | 802-1x.phase2-domain-suffix-match: --
38 | 802-1x.phase2-client-cert: --
39 | 802-1x.password:
40 | 802-1x.password-flags: 1 (agent-owned)
41 | 802-1x.password-raw:
42 | 802-1x.password-raw-flags: 0 (none)
43 | 802-1x.private-key: --
44 | 802-1x.private-key-password:
45 | 802-1x.private-key-password-flags: 0 (none)
46 | 802-1x.phase2-private-key: --
47 | 802-1x.phase2-private-key-password:
48 | 802-1x.phase2-private-key-password-flags:0 (none)
49 | 802-1x.pin:
50 | 802-1x.pin-flags: 0 (none)
51 | 802-1x.system-ca-certs: no
52 | 802-11-wireless.ssid: ADSY-EAP
53 | 802-11-wireless.mode: infrastructure
54 | 802-11-wireless.band: --
55 | 802-11-wireless.channel: 0
56 | 802-11-wireless.bssid: --
57 | 802-11-wireless.rate: 0
58 | 802-11-wireless.tx-power: 0
59 | 802-11-wireless.mac-address: --
60 | 802-11-wireless.cloned-mac-address: --
61 | 802-11-wireless.mac-address-blacklist:
62 | 802-11-wireless.mac-address-randomization:default
63 | 802-11-wireless.mtu: auto
64 | 802-11-wireless.seen-bssids: 06:27:22:F1:EE:54
65 | 802-11-wireless.hidden: no
66 | 802-11-wireless.powersave: default (0)
67 | 802-11-wireless-security.key-mgmt: wpa-eap
68 | 802-11-wireless-security.wep-tx-keyidx: 0
69 | 802-11-wireless-security.auth-alg: --
70 | 802-11-wireless-security.proto:
71 | 802-11-wireless-security.pairwise:
72 | 802-11-wireless-security.group:
73 | 802-11-wireless-security.leap-username: --
74 | 802-11-wireless-security.wep-key0:
75 | 802-11-wireless-security.wep-key1:
76 | 802-11-wireless-security.wep-key2:
77 | 802-11-wireless-security.wep-key3:
78 | 802-11-wireless-security.wep-key-flags: 0 (none)
79 | 802-11-wireless-security.wep-key-type: 0 (unknown)
80 | 802-11-wireless-security.psk:
81 | 802-11-wireless-security.psk-flags: 0 (none)
82 | 802-11-wireless-security.leap-password:
83 | 802-11-wireless-security.leap-password-flags:0 (none)
84 | ipv4.method: auto
85 | ipv4.dns:
86 | ipv4.dns-search:
87 | ipv4.dns-options: (default)
88 | ipv4.addresses:
89 | ipv4.gateway: --
90 | ipv4.routes:
91 | ipv4.route-metric: -1
92 | ipv4.ignore-auto-routes: no
93 | ipv4.ignore-auto-dns: no
94 | ipv4.dhcp-client-id: --
95 | ipv4.dhcp-timeout: 0
96 | ipv4.dhcp-send-hostname: yes
97 | ipv4.dhcp-hostname: --
98 | ipv4.dhcp-fqdn: --
99 | ipv4.never-default: no
100 | ipv4.may-fail: yes
101 | ipv4.dad-timeout: -1 (default)
102 | ipv6.method: auto
103 | ipv6.dns:
104 | ipv6.dns-search:
105 | ipv6.dns-options: (default)
106 | ipv6.addresses:
107 | ipv6.gateway: --
108 | ipv6.routes:
109 | ipv6.route-metric: -1
110 | ipv6.ignore-auto-routes: no
111 | ipv6.ignore-auto-dns: no
112 | ipv6.never-default: no
113 | ipv6.may-fail: yes
114 | ipv6.ip6-privacy: -1 (unknown)
115 | ipv6.addr-gen-mode: stable-privacy
116 | ipv6.dhcp-send-hostname: yes
117 | ipv6.dhcp-hostname: --
118 | GENERAL.NAME: ADSY-EAP
119 | GENERAL.UUID: f3008792-bd40-4bbe-9b4d-106eac03c9f9
120 | GENERAL.DEVICES: wlp3s0
121 | GENERAL.STATE: activated
122 | GENERAL.DEFAULT: yes
123 | GENERAL.DEFAULT6: no
124 | GENERAL.VPN: no
125 | GENERAL.ZONE: --
126 | GENERAL.DBUS-PATH: /org/freedesktop/NetworkManager/ActiveConnection/4
127 | GENERAL.CON-PATH: /org/freedesktop/NetworkManager/Settings/3
128 | GENERAL.SPEC-OBJECT: /org/freedesktop/NetworkManager/AccessPoint/12
129 | GENERAL.MASTER-PATH: --
130 | IP4.ADDRESS[1]: 10.9.5.185/16
131 | IP4.GATEWAY: 10.9.1.1
132 | IP4.DNS[1]: 10.9.2.1
133 | IP4.DNS[2]: 10.1.2.8
134 | IP4.DNS[3]: 10.1.2.22
135 | IP4.DOMAIN[1]: adfinis-int.ch
136 | DHCP4.OPTION[1]: requested_ms_classless_static_routes = 1
137 | DHCP4.OPTION[2]: requested_domain_search = 1
138 | DHCP4.OPTION[3]: requested_host_name = 1
139 | DHCP4.OPTION[4]: requested_time_offset = 1
140 | DHCP4.OPTION[5]: requested_domain_name = 1
141 | DHCP4.OPTION[6]: filename = pxelinux.0
142 | DHCP4.OPTION[7]: requested_rfc3442_classless_static_routes = 1
143 | DHCP4.OPTION[8]: requested_wpad = 1
144 | DHCP4.OPTION[9]: requested_broadcast_address = 1
145 | DHCP4.OPTION[10]: next_server = 10.9.2.1
146 | DHCP4.OPTION[11]: requested_netbios_scope = 1
147 | DHCP4.OPTION[12]: requested_interface_mtu = 1
148 | DHCP4.OPTION[13]: requested_subnet_mask = 1
149 | DHCP4.OPTION[14]: routers = 10.9.1.1
150 | DHCP4.OPTION[15]: dhcp_message_type = 5
151 | DHCP4.OPTION[16]: ip_address = 10.9.5.185
152 | DHCP4.OPTION[17]: requested_static_routes = 1
153 | DHCP4.OPTION[18]: expiry = 1481225250
154 | DHCP4.OPTION[19]: requested_domain_name_servers = 1
155 | DHCP4.OPTION[20]: broadcast_address = 10.9.255.255
156 | DHCP4.OPTION[21]: requested_ntp_servers = 1
157 | DHCP4.OPTION[22]: domain_name = adfinis-int.ch
158 | DHCP4.OPTION[23]: dhcp_lease_time = 43200
159 | DHCP4.OPTION[24]: domain_name_servers = 10.9.2.1 10.1.2.8 10.1.2.22
160 | DHCP4.OPTION[25]: requested_netbios_name_servers = 1
161 | DHCP4.OPTION[26]: subnet_mask = 255.255.0.0
162 | DHCP4.OPTION[27]: network_number = 10.9.0.0
163 | DHCP4.OPTION[28]: requested_routers = 1
164 | DHCP4.OPTION[29]: dhcp_server_identifier = 10.9.2.1
165 | IP6.ADDRESS[1]: fe80::db41:83ec:a6e7:a7a4/64
166 | IP6.GATEWAY:
167 |
--------------------------------------------------------------------------------
/virtesk-tc-connectspice/test_mock_data/nmcli_device_show:
--------------------------------------------------------------------------------
1 | GENERAL.DEVICE: docker0
2 | GENERAL.TYPE: bridge
3 | GENERAL.HWADDR: 8A:7F:3B:20:49:AE
4 | GENERAL.MTU: 1500
5 | GENERAL.STATE: 100 (connected)
6 | GENERAL.CONNECTION: docker0
7 | GENERAL.CON-PATH: /org/freedesktop/NetworkManager/ActiveConnection/0
8 | IP4.ADDRESS[1]: 172.17.0.1/16
9 | IP4.GATEWAY:
10 | IP4.ROUTE[1]: dst = 169.254.0.0/16, nh = 0.0.0.0, mt = 1000
11 | IP6.GATEWAY:
12 |
13 | GENERAL.DEVICE: wlp3s0
14 | GENERAL.TYPE: wifi
15 | GENERAL.HWADDR: 28:B2:BD:E6:35:7A
16 | GENERAL.MTU: 0
17 | GENERAL.STATE: 100 (connected)
18 | GENERAL.CONNECTION: ADSY-EAP
19 | GENERAL.CON-PATH: /org/freedesktop/NetworkManager/ActiveConnection/7
20 | IP4.ADDRESS[1]: 10.9.5.185/16
21 | IP4.GATEWAY: 10.9.1.1
22 | IP4.DNS[1]: 10.9.2.1
23 | IP4.DNS[2]: 10.1.2.8
24 | IP4.DNS[3]: 10.1.2.22
25 | IP4.DOMAIN[1]: adfinis-int.ch
26 | IP6.ADDRESS[1]: fe80::db41:83ec:a6e7:a7a4/64
27 | IP6.GATEWAY:
28 |
29 | GENERAL.DEVICE: enp0s25
30 | GENERAL.TYPE: ethernet
31 | GENERAL.HWADDR: 54:EE:75:2C:E4:D5
32 | GENERAL.MTU: 1500
33 | GENERAL.STATE: 20 (unavailable)
34 | GENERAL.CONNECTION: --
35 | GENERAL.CON-PATH: --
36 | WIRED-PROPERTIES.CARRIER: off
37 |
38 | GENERAL.DEVICE: lo
39 | GENERAL.TYPE: loopback
40 | GENERAL.HWADDR: 00:00:00:00:00:00
41 | GENERAL.MTU: 65536
42 | GENERAL.STATE: 10 (unmanaged)
43 | GENERAL.CONNECTION: --
44 | GENERAL.CON-PATH: --
45 | IP4.ADDRESS[1]: 127.0.0.1/8
46 | IP4.GATEWAY:
47 | IP6.ADDRESS[1]: ::1/128
48 | IP6.GATEWAY:
49 |
--------------------------------------------------------------------------------
/virtesk-tc-connectspice/test_mock_data/nmcli_device_show_single_line:
--------------------------------------------------------------------------------
1 | IP4.ADDRESS[1]: 10.9.5.185/16
2 |
--------------------------------------------------------------------------------
/virtesk-tc-connectspice/virtesk-tc-connectspice-main:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: UTF-8 -*-
3 | # vim: autoindent expandtab tabstop=4 sw=4 sts=4 filetype=python
4 |
5 | # Copyright (c) 2013-2016, Adfinis SyGroup AG
6 | #
7 | # This file is part of Virtesk VDI.
8 | #
9 | # Virtesk VDI is free software: you can redistribute it and/or modify
10 | # it under the terms of the GNU General Public License as published by
11 | # the Free Software Foundation, either version 3 of the License, or
12 | # (at your option) any later version.
13 | #
14 | # Virtesk VDI is distributed in the hope that it will be useful,
15 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
16 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 | # GNU General Public License for more details.
18 | #
19 | # You should have received a copy of the GNU General Public License
20 | # along with Virtesk VDI. If not, see .
21 |
22 |
23 | import connect_spice_client
24 |
25 |
26 | if __name__ == "__main__":
27 | # logging.basicConfig(level=logging.DEBUG)
28 | connect_spice_client.connect_spice_client().main()
29 |
--------------------------------------------------------------------------------
/virtesk-tc-connectspice/virtesk-tc-connectspice-shutdown-vm:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: UTF-8 -*-
3 | # vim: autoindent expandtab tabstop=4 sw=4 sts=4 filetype=python
4 |
5 | # Copyright (c) 2013-2016, Adfinis SyGroup AG
6 | #
7 | # This file is part of Virtesk VDI.
8 | #
9 | # Virtesk VDI is free software: you can redistribute it and/or modify
10 | # it under the terms of the GNU General Public License as published by
11 | # the Free Software Foundation, either version 3 of the License, or
12 | # (at your option) any later version.
13 | #
14 | # Virtesk VDI is distributed in the hope that it will be useful,
15 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
16 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 | # GNU General Public License for more details.
18 | #
19 | # You should have received a copy of the GNU General Public License
20 | # along with Virtesk VDI. If not, see .
21 |
22 | import connect_spice_client
23 |
24 |
25 | if __name__ == "__main__":
26 | # logging.basicConfig(level=logging.DEBUG)
27 | connect_spice_client.connect_spice_client().shutdown_vm_action_sequence()
28 |
--------------------------------------------------------------------------------
/virtesk-tc-tools/README.md:
--------------------------------------------------------------------------------
1 | # Virtesk-tc-tools
2 |
3 | -------------------------------
4 |
5 | Virtesk-tc-tools is a collection of shell scripts for manageing thinclients.
6 | See [virtesk-tc-tools.rst](../doc/virtesk-tc-tools.rst) for details.
7 |
--------------------------------------------------------------------------------
/virtesk-tc-tools/tc_rollout_kexec:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # Copyright (c) 2013-2016, Adfinis SyGroup AG
4 | #
5 | # This file is part of Virtesk VDI.
6 | #
7 | # Virtesk VDI is free software: you can redistribute it and/or modify
8 | # it under the terms of the GNU General Public License as published by
9 | # the Free Software Foundation, either version 3 of the License, or
10 | # (at your option) any later version.
11 | #
12 | # Virtesk VDI is distributed in the hope that it will be useful,
13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | # GNU General Public License for more details.
16 | #
17 | # You should have received a copy of the GNU General Public License
18 | # along with Virtesk VDI. If not, see .
19 |
20 | # Global variables
21 | declare -a ARGV
22 | declare -a ssh_opts
23 | declare -a remote_cmdline
24 | declare -i CMDLINE_AVAILABLE=0
25 |
26 | source $(dirname $(readlink -e ${BASH_SOURCE}))/utils.sh
27 |
28 | display_usage() {
29 | cat 1>&2 <<-'EndOfHelpText'
30 | Usage:
31 |
32 | tc_rollout_kexec
33 |
34 |
35 | tc_rollout_kexec is used to roll out thinclients
36 | using ssh and kexec.
37 |
38 | It is useful for re-installation of already
39 | installed thinclients.
40 |
41 | tc_rollout_kexec is part of the virtesk-tc-tools collection.
42 |
43 | Amoothei-vdi is a virtual desktop infrastructure
44 | solution based on RHEV / Ovirt.
45 |
46 | Documentation: see doc/virtesk-tc-tools.rst .
47 | EndOfHelpText
48 |
49 | exit 1;
50 | }
51 |
52 | ARGV=( $* )
53 |
54 | source_configfiles
55 | parse_cmdline_simple "$1"
56 |
57 | debug tc_ssh "$1" -- "$ROLLOUT_CMDLINE"
58 | tc_ssh "$1" -- "$ROLLOUT_CMDLINE"
59 |
60 | RETCODE=$?
61 | exit $RETCODE
62 |
63 |
--------------------------------------------------------------------------------
/virtesk-tc-tools/tc_screenshot:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # Copyright (c) 2013-2016, Adfinis SyGroup AG
4 | #
5 | # This file is part of Virtesk VDI.
6 | #
7 | # Virtesk VDI is free software: you can redistribute it and/or modify
8 | # it under the terms of the GNU General Public License as published by
9 | # the Free Software Foundation, either version 3 of the License, or
10 | # (at your option) any later version.
11 | #
12 | # Virtesk VDI is distributed in the hope that it will be useful,
13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | # GNU General Public License for more details.
16 | #
17 | # You should have received a copy of the GNU General Public License
18 | # along with Virtesk VDI. If not, see .
19 |
20 | # Global variables
21 | declare -a ARGV
22 | declare -a ssh_opts
23 | declare -a remote_cmdline
24 | declare -i CMDLINE_AVAILABLE=0
25 |
26 | source $(dirname $(readlink -e ${BASH_SOURCE}))/utils.sh
27 |
28 | display_usage() {
29 | cat 1>&2 <<-'EndOfHelpText'
30 | Usage:
31 |
32 | tc_screenshot
33 |
34 | tc_screenshot takes screenshots of thinclients.
35 |
36 | It is useful for quality control after deploying new
37 | VMs or after rolling out new thinclient software.
38 |
39 | is an identifier. You can choose it freely.
40 |
41 | The screenshot will be put into the following file:
42 | ${SCREENSHOT_DIR}//.png
43 |
44 | tc_screenshot is part of the virtesk-tc-tools collection.
45 |
46 | Amoothei-vdi is a virtual desktop infrastructure
47 | solution based on RHEV / Ovirt.
48 |
49 | Documentation: see doc/virtesk-tc-tools.rst .
50 | EndOfHelpText
51 |
52 | exit 1;
53 | }
54 |
55 | ARGV=( $* )
56 |
57 | source_configfiles
58 | parse_cmdline_twoargument
59 |
60 | if [[ -z "${SCREENSHOT_DIR}" ]]; then
61 | error_msg Please configure $SCREENSHOT_DIR .
62 | error_msg
63 | display_usage
64 | fi
65 |
66 | FILENAME="$1.png"
67 | SESSION="$2"
68 |
69 | SESSION_DIR="${SCREENSHOT_DIR}/${SESSION}"
70 | SCREENSHOT_DEST="${SESSION_DIR}/${FILENAME}"
71 |
72 | if [[ ! -e "$SESSION_DIR" ]]; then
73 | echo "The session directory '$SESSION_DIR' does not exist."
74 | echo "Trying to create it..."
75 | mkdir -p "$SESSION_DIR"
76 | if [[ $? -eq 0 ]]; then
77 | echo "Successfully created '$SESSION_DIR'."
78 | else
79 | error_msg "Failed to create '$SESSION_DIR'."
80 | error_msg "Aborting."
81 | exit -1
82 | fi
83 | fi
84 |
85 | debug tc_ssh $1 -l vdiclient -- "$SCREENSHOT_CMDLINE" > $SCREENSHOT_DEST
86 | tc_ssh $1 -l vdiclient -- "$SCREENSHOT_CMDLINE" > $SCREENSHOT_DEST
87 | RETCODE=$?
88 |
89 | if [[ $RETCODE -ne 0 ]]; then
90 | error_msg "Taking screenshot failed with return code $RETCODE."
91 | else
92 | echo "Successfully stored a screenshot at $SCREENSHOT_DEST."
93 | ls -lh $SCREENSHOT_DEST
94 | fi
95 |
96 | exit $RETCODE
97 |
98 |
--------------------------------------------------------------------------------
/virtesk-tc-tools/tc_ssh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # Copyright (c) 2013-2016, Adfinis SyGroup AG
4 | #
5 | # This file is part of Virtesk VDI.
6 | #
7 | # Virtesk VDI is free software: you can redistribute it and/or modify
8 | # it under the terms of the GNU General Public License as published by
9 | # the Free Software Foundation, either version 3 of the License, or
10 | # (at your option) any later version.
11 | #
12 | # Virtesk VDI is distributed in the hope that it will be useful,
13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | # GNU General Public License for more details.
16 | #
17 | # You should have received a copy of the GNU General Public License
18 | # along with Virtesk VDI. If not, see .
19 |
20 | # Global variables
21 | declare -a ARGV
22 | declare -a ssh_opts
23 | declare -a remote_cmdline
24 | declare -i CMDLINE_AVAILABLE=0
25 | declare TC
26 | declare TC_RAW
27 |
28 | source $(dirname $(readlink -e ${BASH_SOURCE}))/utils.sh
29 |
30 | display_usage() {
31 | cat 1>&2 <<-'EndOfHelpText'
32 | Usage:
33 |
34 | # interactive shell:
35 | tc_ssh [ssh-args]
36 |
37 | # execute remote command
38 | tc_ssh [ssh-args] -- remote_command
39 |
40 |
41 | tc_ssh is used for ssh remote access to thinclients.
42 |
43 | It can be used to open an interactive shell, or
44 | to execute remote commands.
45 |
46 | tc_ssh is part of the virtesk-tc-tools collection.
47 |
48 | Amoothei-vdi is a virtual desktop infrastructure
49 | solution based on RHEV / Ovirt.
50 |
51 | Documentation: see doc/virtesk-tc-tools.rst .
52 | EndOfHelpText
53 |
54 | exit 1;
55 | }
56 |
57 | ARGV=( $* )
58 |
59 | source_configfiles
60 | parse_cmdline
61 | process_thinclient_arg
62 |
63 | debug ssh $SSH_GLOBAL_OPTS ${ssh_opts[@]} $TC -- "${remote_cmdline[@]}"
64 | ssh $SSH_GLOBAL_OPTS ${ssh_opts[@]} $TC -- "${remote_cmdline[@]}"
65 |
66 | RETCODE=$?
67 |
68 | if [[ $RETCODE -ne 0 ]]; then
69 | error_msg "Thinclient $TC: SSH return code: $RETCODE"
70 | fi
71 |
72 | exit $RETCODE
73 |
74 |
--------------------------------------------------------------------------------
/virtesk-tc-tools/utils.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # Copyright (c) 2013-2016, Adfinis SyGroup AG
4 | #
5 | # This file is part of Virtesk VDI.
6 | #
7 | # Virtesk VDI is free software: you can redistribute it and/or modify
8 | # it under the terms of the GNU General Public License as published by
9 | # the Free Software Foundation, either version 3 of the License, or
10 | # (at your option) any later version.
11 | #
12 | # Virtesk VDI is distributed in the hope that it will be useful,
13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | # GNU General Public License for more details.
16 | #
17 | # You should have received a copy of the GNU General Public License
18 | # along with Virtesk VDI. If not, see .
19 |
20 |
21 | debug() {
22 | if [[ $DEVELOPER_MODE -eq 1 ]]; then
23 | echo DEBUG: $* 1>&2
24 | fi
25 | }
26 |
27 | error_msg() {
28 | echo ERROR: $* 1>&2
29 | }
30 |
31 | parse_cmdline() {
32 | argc=${#ARGV[@]}
33 |
34 | [[ $argc -eq 0 ]] && display_usage
35 | [[ ${ARGV[1]} = "-h" ]] && display_usage
36 | [[ ${ARGV[1]} = "--help" ]] && display_usage
37 |
38 | TC_RAW="${ARGV[0]}"
39 | debug TC_RAW = $TC_RAW
40 |
41 | index=1
42 |
43 | while [[ $index -lt $argc ]]; do
44 | debug argument $index: ${ARGV[index]}
45 | if [[ "${ARGV[index]}" = "--" ]]; then
46 | CMDLINE_AVAILABLE=1
47 | ssh_opts=( ${ARGV[@]:1:$((index-1))} )
48 | debug ssh_opts: ${ssh_opts[@]}
49 |
50 | # skip --
51 | let index++
52 |
53 | if [[ index -eq $argc ]]; then
54 | error_msg "-- specified, but no remote cmdline given."
55 | error_msg
56 |
57 | display_usage
58 | fi
59 |
60 | remote_cmdline=( ${ARGV[@]:index:$argc} )
61 | debug remote_cmdline: ${remote_cmdline[@]}
62 |
63 | break
64 | fi
65 | let index++
66 | done
67 |
68 | if [[ $CMDLINE_AVAILABLE -eq 0 ]]; then
69 | ssh_opts=( ${ARGV[@]:1:$argc} )
70 | debug ssh_opts: ${ssh_opts[@]}
71 | fi
72 | }
73 |
74 | parse_cmdline_simple() {
75 | [[ $# -ne 1 ]] && display_usage
76 | [[ $1 = "-h" ]] && display_usage
77 | [[ $1 = "--help" ]] && display_usage
78 | }
79 |
80 | parse_cmdline_twoargument() {
81 | argc=${#ARGV[@]}
82 |
83 | [[ ${ARGV[1]} = "-h" ]] && display_usage
84 | [[ ${ARGV[1]} = "--help" ]] && display_usage
85 | [[ $argc -ne 2 ]] && display_usage
86 | }
87 |
88 | source_configfiles(){
89 | if [[ "x${AMOOTHEI_TC_TOOLS_CONF_DIR}" = "x" ]]; then
90 | AMOOTHEI_TC_TOOLS_CONF_DIR="/etc/virtesk-vdi"
91 | fi
92 |
93 | # Sourcing main configuration file
94 | MAIN_CONF_FILE="${AMOOTHEI_TC_TOOLS_CONF_DIR}/virtesk-tc-tools.conf"
95 |
96 | [[ -r "${MAIN_CONF_FILE}" ]] || {
97 | error_msg Cannot read main config file "${MAIN_CONF_FILE}"
98 | error_msg Aborting...
99 | error_msg
100 | display_usage
101 | }
102 |
103 | source "${MAIN_CONF_FILE}"
104 |
105 | # PROGNAME=$(basename $BASH_SOURCE)
106 | PROGNAME=$(basename $0)
107 | debug PROGNAME=${PROGNAME}
108 |
109 | IND_CONF_FILE="${AMOOTHEI_TC_TOOLS_CONF_DIR}/virtesk-tc-tools.conf.dir/${PROGNAME}.conf"
110 | [[ -r "${IND_CONF_FILE}" ]] && source "${IND_CONF_FILE}"
111 |
112 | }
113 |
114 | # Append $TC_DOMAIN if a short name (e.g. contains no "." or ":")
115 | # is given.
116 | process_thinclient_arg() {
117 | echo "${TC_RAW}" | egrep -q '\.|:'
118 | if [[ $? -ne 0 ]]; then
119 | TC="${TC_RAW}.${TC_DOMAIN}"
120 | else
121 | TC="${TC_RAW}"
122 | fi
123 | }
124 |
125 |
126 |
--------------------------------------------------------------------------------
/virtesk-vm-rollout/Makefile:
--------------------------------------------------------------------------------
1 | flake8:
2 | flake8 --doctests -j auto --ignore=E221,E222,E251,E272,E241,E203 *.py virtesk-virtroom-*
3 | flake8-strict:
4 | flake8 --doctests -j auto . *.py virtesk-virtroom-*
5 | indention_report:
6 | autopep8 . --recursive --select=E101,E121 --diff
7 | indention_fix:
8 | autopep8 . --recursive --select=E101,E121 --in-place
9 | autopep8_report:
10 | autopep8 . --recursive --diff
11 | clean:
12 | rm -f *.pyc
13 |
--------------------------------------------------------------------------------
/virtesk-vm-rollout/constants.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: UTF-8 -*-
3 | # vim: autoindent expandtab tabstop=4 sw=4 sts=4 filetype=python
4 |
5 | """Defines constants for Ad-Sy RHEV tools"""
6 |
7 | # Copyright (c) 2013-2016, Adfinis SyGroup AG
8 | #
9 | # This file is part of Amoothei-VDI.
10 | #
11 | # Amoothei-VDI is free software: you can redistribute it and/or modify
12 | # it under the terms of the GNU General Public License as published by
13 | # the Free Software Foundation, either version 3 of the License, or
14 | # (at your option) any later version.
15 | #
16 | # Amoothei-VDI is distributed in the hope that it will be useful,
17 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
18 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 | # GNU General Public License for more details.
20 | #
21 | # You should have received a copy of the GNU General Public License
22 | # along with Amoothei-VDI. If not, see .
23 |
24 | import os
25 |
26 | DEFAULT_CONFIGURATION_FILE_NAME = 'adsy-rhev-tools.config'
27 |
28 | CONFIG_FILE_SEARCH_PATH = [
29 | os.path.expanduser('~/.config/virtesk-vdi/virtesk-vm-rollout.conf'),
30 | '/etc/virtesk-vdi/virtesk-vm-rollout.conf'
31 | ]
32 |
33 | # Wait time in seconds after creating a new VM.
34 | VM_CREATION_SLEEP_TIME = 15
35 |
36 | # Wait time in seconds after various tasks concerning VMs
37 | VM_SLEEP_TIME = 10
38 |
39 | # Wait time in seconds after creating a new VM snapshot
40 | CREATE_VM_SNAPSHOT_SLEEP_TIME = 8
41 |
42 | # Wait time in seconds between attempts to check the state of freshly
43 | # created VM snapshots
44 | WAIT_FOR_SNAPSHOTS_READY_SLEEP_TIME = 4
45 |
--------------------------------------------------------------------------------
/virtesk-vm-rollout/rhev_manager.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: UTF-8 -*-
3 | # vim: autoindent expandtab tabstop=4 sw=4 sts=4 filetype=python
4 |
5 | # Copyright (c) 2013-2016, Adfinis SyGroup AG
6 | #
7 | # This file is part of Virtesk VDI.
8 | #
9 | # Virtesk VDI is free software: you can redistribute it and/or modify
10 | # it under the terms of the GNU General Public License as published by
11 | # the Free Software Foundation, either version 3 of the License, or
12 | # (at your option) any later version.
13 | #
14 | # Virtesk VDI is distributed in the hope that it will be useful,
15 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
16 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 | # GNU General Public License for more details.
18 | #
19 | # You should have received a copy of the GNU General Public License
20 | # along with Virtesk VDI. If not, see .
21 |
22 |
23 | # System Imports
24 | import os
25 | import time
26 | import logging
27 | import logging.config
28 | import configobj
29 | import sys
30 | import argparse
31 | import textwrap
32 |
33 | # Project imports
34 | import rhev
35 | import utils
36 | import constants
37 |
38 |
39 | class RhevManager():
40 |
41 | def __init__(self, configuration_file):
42 | assert(configuration_file)
43 |
44 | self.config_file = configuration_file
45 | self.logger = None
46 | self.rhev_lib = None
47 | self.base_configuration = None
48 |
49 | self.read_base_configuration()
50 | self.initialize_logging()
51 |
52 | self.rhev_lib = rhev.rhev(self.base_configuration)
53 |
54 | @staticmethod
55 | def construct_from_cmdargs(description):
56 | epilog = textwrap.dedent('''
57 | The following config file locations are used, first match wins:
58 | * Command line argument
59 | * ~/.config/virtesk-vdi/virtesk-vm-rollout.conf
60 | * /etc/virtesk-vdi/virtesk-vm-rollout.conf
61 | ''')
62 |
63 | parser = argparse.ArgumentParser(
64 | formatter_class=argparse.RawDescriptionHelpFormatter,
65 | epilog=epilog, description=description)
66 |
67 | parser.add_argument(
68 | '--config',
69 | help="Absolute or relative path to configuration file."
70 | )
71 |
72 | parser.add_argument(
73 | 'virtroom', help="virtual room to act on"
74 | )
75 |
76 | args = parser.parse_args()
77 |
78 | config_file = utils.get_valid_config_file(
79 | args.config
80 | )
81 |
82 | room = args.virtroom
83 |
84 | # Initialize RHEV manager
85 | rhev_manager = RhevManager(
86 | config_file
87 | )
88 |
89 | return rhev_manager, room
90 |
91 | def cleanup(self):
92 | self.rhev_lib.cleanup()
93 |
94 | def read_base_configuration(self):
95 | try:
96 | self.base_configuration = configobj.ConfigObj(
97 | self.config_file,
98 | file_error=True
99 | )
100 | self.base_configuration['general']['config_file'] = (
101 | self.config_file
102 | )
103 | logging.info('Successfully read base configuration')
104 |
105 | except (configobj.ConfigObjError, IOError), e:
106 | raise Exception(
107 | "Could not read '{0}': {1}".format(
108 | os.path.abspath(self.config_file), e
109 | )
110 | )
111 |
112 | def initialize_logging(self):
113 | assert(self.config_file)
114 |
115 | try:
116 | config_file_path, config_file_name = os.path.split(
117 | self.config_file
118 | )
119 |
120 | log_config_file = os.path.join(
121 | config_file_path,
122 | self.base_configuration['logging']['config_file']
123 | )
124 |
125 | log_file = self.base_configuration['logging']['log_file']
126 |
127 | logging.config.fileConfig(log_config_file, defaults={
128 | 'log_file': log_file,
129 | 'file_mode': 'a'
130 | })
131 |
132 | self.logger = logging.getLogger(__name__)
133 | self.base_configuration['logging']['config_file'] = log_config_file
134 |
135 | self.logger.debug('Successfully initialized logger')
136 | self.logger.debug(
137 | "Using configuration file '{0}'".format(log_config_file)
138 | )
139 |
140 | except Exception as ex:
141 | logging.error(
142 | "Failed to initialize logging. "
143 | "Logfile: `{0}'. Error details: `{1}'".format(log_file, ex)
144 | )
145 | sys.exit(-1)
146 |
147 | def cleanup_classroom(self, classroom):
148 | if not classroom:
149 | raise Exception('No classrom given')
150 |
151 | self.logger.info("cleaning up classroom '{0}'".format(classroom))
152 |
153 | try:
154 | # Get VMs for given classroom
155 | self.logger.debug(
156 | "Getting VMs for classroom '{0}'".format(classroom)
157 | )
158 | vms_for_classroom = self.rhev_lib.get_vms_for_classroom(classroom)
159 |
160 | if vms_for_classroom:
161 | # Teardown of VMs
162 | for vm in vms_for_classroom:
163 | self.rhev_lib.delete_vm(vm)
164 |
165 | self.logger.info(
166 | "Successfully cleaned up classroom '{0}'".format(classroom)
167 | )
168 |
169 | except Exception, e:
170 | raise Exception(
171 | "Cleaning up classroom '{0}' failed: {1}".format(classroom, e)
172 | )
173 |
174 | # reset vms to snapshot
175 | def reset_classroom(self, classroom):
176 | if not classroom:
177 | raise Exception('No classroom given')
178 |
179 | self.logger.info(
180 | "Starting to reset classroom '{0}'".format(classroom)
181 | )
182 |
183 | # Get VMs for given classroom
184 | vms_for_classroom = self.rhev_lib.get_vms_for_classroom(
185 | classroom)
186 |
187 | for vm in vms_for_classroom:
188 | self.rhev_lib.reset_vm_to_snapshot(vm)
189 |
190 | def analyze_config_of_classroom(self, classroom):
191 | self.logger.info(
192 | "Analyzing configuration of classroom {0}".format(classroom)
193 | )
194 |
195 | # Get VMs for given classroom
196 | vms_for_classroom = self.rhev_lib.get_vms_for_classroom(
197 | classroom)
198 |
199 | for vmconfig in vms_for_classroom:
200 | self.logger.debug(str(vmconfig))
201 |
202 | if self.rhev_lib.check_if_vms_exist(vms_for_classroom):
203 | self.logger.info(
204 | "Some VMs already exist. Please delete them before rollout"
205 | )
206 | self.rhev_lib.analyze_snapshots(vms_for_classroom)
207 |
208 | def start_all_vms_in_room(self, classroom):
209 | self.logger.info("Starting VMs in Room... {0}".format(classroom))
210 |
211 | # Get VMs for given classroom
212 | vms_for_classroom = self.rhev_lib.get_vms_for_classroom(
213 | classroom
214 | )
215 |
216 | for vmconfig in vms_for_classroom:
217 | self.logger.debug(str(vmconfig))
218 |
219 | for vmconfig in vms_for_classroom:
220 | self.rhev_lib.start_vm_if_possible(vmconfig)
221 |
222 | def shutdown_all_vms_in_room(self, classroom):
223 | self.logger.info("Shutting down VMs in Room... {0}".format(classroom))
224 |
225 | # Get VMs for given classroom
226 | vms_for_classroom = self.rhev_lib.get_vms_for_classroom(
227 | classroom)
228 |
229 | for vmconfig in vms_for_classroom:
230 | self.logger.debug(str(vmconfig))
231 |
232 | for vmconfig in vms_for_classroom:
233 | self.rhev_lib.shutdown_vm_if_possible(vmconfig)
234 |
235 | def rollout_classroom(self, classroom):
236 | if not classroom:
237 | raise Exception('No classroom given')
238 |
239 | try:
240 | with utils.tempdir("virtesk-virtroom-rollout-") as temp_dir:
241 | self.logger.info(
242 | "Starting to roll out classroom '{0}'".format(classroom)
243 | )
244 |
245 | # Get VMs for given classroom
246 | vms_for_classroom = self.rhev_lib.get_vms_for_classroom(
247 | classroom)
248 |
249 | for vmconfig in vms_for_classroom:
250 | self.logger.debug(str(vmconfig))
251 |
252 | # Make sure the VMs don't exist (avoiding conflicts)
253 | if self.rhev_lib.check_if_vms_exist(vms_for_classroom):
254 | self.logger.error(
255 | "Some VMs already exist. Please delete them first"
256 | )
257 | sys.exit(-1)
258 |
259 | # Create (template) VMs
260 | for vm in vms_for_classroom:
261 | self.rhev_lib.create_standalone_vm(vm)
262 | # sys.exit(0)
263 | time.sleep(constants.VM_CREATION_SLEEP_TIME)
264 |
265 | # Wait for VMs to shut donw
266 | self.rhev_lib.wait_for_vms_down(
267 | vmconfigs=vms_for_classroom,
268 | formatstring="VM {0} successfully created"
269 | )
270 |
271 | # Add NIC and initiate sysprep
272 | for vm in vms_for_classroom:
273 | self.rhev_lib.add_vm_nic(vm)
274 | self.rhev_lib.sysprep_vm(vm, temp_dir)
275 | self.logger.info('Waiting for sysprep to finish')
276 | time.sleep(constants.VM_SLEEP_TIME)
277 |
278 | # Wait for VMs to shut down
279 | msg_formatstring = \
280 | "VM {0} has been stopped after running Autounattend.xml."
281 |
282 | self.rhev_lib.wait_for_vms_down(
283 | vmconfigs=vms_for_classroom,
284 | formatstring=msg_formatstring
285 | )
286 |
287 | # Postprocess VMs:
288 | # Eject ISOs, set statless and add (user-) group.
289 | # Create a snapshot of every VM.
290 | for vm in vms_for_classroom:
291 | self.rhev_lib.postprocess_vm(vm)
292 |
293 | # Wait for all VM snapshots to become ready.
294 | self.rhev_lib.wait_for_vm_snapshots_ready(vms_for_classroom)
295 |
296 | # Start VMs
297 | for vm in vms_for_classroom:
298 | self.rhev_lib.start_vm_after_rollout(vm)
299 |
300 | self.logger.info(
301 | "Finished rolling out classroom '{0}' successfully".format(
302 | classroom
303 | )
304 | )
305 |
306 | except Exception, e:
307 | logging.exception(e)
308 | raise Exception(
309 | "Rolling out classroom '{0}' failed: {1}".format(classroom, e)
310 | )
311 |
312 | return True
313 |
--------------------------------------------------------------------------------
/virtesk-vm-rollout/utils.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: UTF-8 -*-
3 | # vim: autoindent expandtab tabstop=4 sw=4 sts=4 filetype=python
4 |
5 | # Copyright (c) 2013-2016, Adfinis SyGroup AG
6 | #
7 | # This file is part of Amoothei-VDI.
8 | #
9 | # Amoothei-VDI is free software: you can redistribute it and/or modify
10 | # it under the terms of the GNU General Public License as published by
11 | # the Free Software Foundation, either version 3 of the License, or
12 | # (at your option) any later version.
13 | #
14 | # Amoothei-VDI is distributed in the hope that it will be useful,
15 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
16 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 | # GNU General Public License for more details.
18 | #
19 | # You should have received a copy of the GNU General Public License
20 | # along with Amoothei-VDI. If not, see .
21 |
22 |
23 | # System imports
24 | import contextlib
25 | import errno
26 | import os
27 | import shutil
28 | import tempfile
29 |
30 | # Project imports
31 | import constants
32 |
33 |
34 | class Failure:
35 |
36 | def __init__(self, msg):
37 | self.msg = msg
38 |
39 |
40 | def get_valid_config_file(config_file):
41 | """
42 | Checks if the given parameter 'config_file'
43 | exists as file and is readable. If not, tries
44 | to get one possible configuration file within
45 | the path under CONFIG_FILE_SEARCH_PATH.
46 | """
47 |
48 | if config_file is not None:
49 | if os.path.exists(config_file):
50 | return config_file
51 | else:
52 | config_file = os.path.expanduser(config_file)
53 | if os.path.exists(config_file):
54 | return config_file
55 | else:
56 | raise Failure(
57 | "Config file `{0}' does not exist.".format(config_file)
58 | )
59 |
60 | for config_file in constants.CONFIG_FILE_SEARCH_PATH:
61 | if os.path.exists(config_file):
62 | os.stat(config_file)
63 | return config_file
64 |
65 | raise Failure(
66 | "No config file specified on command line and no "
67 | "config file available at default locations."
68 | )
69 |
70 |
71 | @contextlib.contextmanager
72 | def tempdir(prefix):
73 | try:
74 | tempdir = tempfile.mkdtemp(prefix=prefix)
75 | yield tempdir
76 | finally:
77 | try:
78 | shutil.rmtree(tempdir)
79 | except OSError as e:
80 | # Reraise unless ENOENT: No such file or directory
81 | # (ok if directory has already been deleted)
82 | if e.errno != errno.ENOENT:
83 | raise
84 |
--------------------------------------------------------------------------------
/virtesk-vm-rollout/virtesk-virtroom-delete:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: UTF-8 -*-
3 | # vim: autoindent expandtab tabstop=4 sw=4 sts=4 filetype=python
4 |
5 | # Copyright (c) 2013-2016, Adfinis SyGroup AG
6 | #
7 | # This file is part of Amoothei-VDI.
8 | #
9 | # Amoothei-VDI is free software: you can redistribute it and/or modify
10 | # it under the terms of the GNU General Public License as published by
11 | # the Free Software Foundation, either version 3 of the License, or
12 | # (at your option) any later version.
13 | #
14 | # Amoothei-VDI is distributed in the hope that it will be useful,
15 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
16 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 | # GNU General Public License for more details.
18 | #
19 | # You should have received a copy of the GNU General Public License
20 | # along with Amoothei-VDI. If not, see .
21 |
22 | # System Imports
23 | import traceback
24 | import logging
25 | import sys
26 |
27 | # Project imports
28 | import rhev_manager
29 | import utils
30 |
31 | try:
32 | description = """Deletes all VMs in a virtual room."""
33 |
34 | manager, room = rhev_manager.RhevManager.construct_from_cmdargs(
35 | description
36 | )
37 |
38 | manager.cleanup_classroom(room)
39 |
40 | manager.cleanup()
41 |
42 | except utils.Failure as f:
43 | logging.error(f.msg)
44 | sys.exit(-1)
45 | except Exception as ex:
46 | logging.exception("Unexpected error: {0}".format(ex))
47 | logging.exception(traceback.format_exc())
48 | sys.exit(-1)
49 |
--------------------------------------------------------------------------------
/virtesk-vm-rollout/virtesk-virtroom-reset:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: UTF-8 -*-
3 | # vim: autoindent expandtab tabstop=4 sw=4 sts=4 filetype=python
4 |
5 | # Copyright (c) 2013-2016, Adfinis SyGroup AG
6 | #
7 | # This file is part of Amoothei-VDI.
8 | #
9 | # Amoothei-VDI is free software: you can redistribute it and/or modify
10 | # it under the terms of the GNU General Public License as published by
11 | # the Free Software Foundation, either version 3 of the License, or
12 | # (at your option) any later version.
13 | #
14 | # Amoothei-VDI is distributed in the hope that it will be useful,
15 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
16 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 | # GNU General Public License for more details.
18 | #
19 | # You should have received a copy of the GNU General Public License
20 | # along with Amoothei-VDI. If not, see .
21 |
22 |
23 | # System Imports
24 | import traceback
25 | import logging
26 | import sys
27 |
28 | # Project imports
29 | import rhev_manager
30 | import utils
31 |
32 | try:
33 | description = """Reset a virtual room to snapshosts"""
34 |
35 | manager, room = rhev_manager.RhevManager.construct_from_cmdargs(
36 | description
37 | )
38 |
39 | manager.reset_classroom(room)
40 |
41 | manager.cleanup()
42 |
43 | except utils.Failure as f:
44 | logging.error(f.msg)
45 | sys.exit(-1)
46 | except Exception as ex:
47 | logging.exception("Unexpected error: {0}".format(ex))
48 | logging.exception(traceback.format_exc())
49 | sys.exit(-1)
50 |
--------------------------------------------------------------------------------
/virtesk-vm-rollout/virtesk-virtroom-rollout:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: UTF-8 -*-
3 | # vim: autoindent expandtab tabstop=4 sw=4 sts=4 filetype=python
4 |
5 | # Copyright (c) 2013-2016, Adfinis SyGroup AG
6 | #
7 | # This file is part of Amoothei-VDI.
8 | #
9 | # Amoothei-VDI is free software: you can redistribute it and/or modify
10 | # it under the terms of the GNU General Public License as published by
11 | # the Free Software Foundation, either version 3 of the License, or
12 | # (at your option) any later version.
13 | #
14 | # Amoothei-VDI is distributed in the hope that it will be useful,
15 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
16 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 | # GNU General Public License for more details.
18 | #
19 | # You should have received a copy of the GNU General Public License
20 | # along with Amoothei-VDI. If not, see .
21 |
22 | # System Imports
23 | import traceback
24 | import logging
25 | import sys
26 |
27 | # Project imports
28 | import rhev_manager
29 | import utils
30 |
31 | try:
32 | description = """Roll out VMs of a virtual room."""
33 |
34 | manager, room = rhev_manager.RhevManager.construct_from_cmdargs(
35 | description
36 | )
37 |
38 | manager.rollout_classroom(room)
39 |
40 | manager.cleanup()
41 |
42 | except utils.Failure as f:
43 | logging.error(f.msg)
44 | sys.exit(-1)
45 | except Exception as ex:
46 | logging.exception("Unexpected error: {0}".format(ex))
47 | logging.exception(traceback.format_exc())
48 | sys.exit(-1)
49 |
--------------------------------------------------------------------------------
/virtesk-vm-rollout/virtesk-virtroom-show:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: UTF-8 -*-
3 | # vim: autoindent expandtab tabstop=4 sw=4 sts=4 filetype=python
4 |
5 | # Copyright (c) 2013-2016, Adfinis SyGroup AG
6 | #
7 | # This file is part of Virtesk VDI.
8 | #
9 | # Virtesk VDI is free software: you can redistribute it and/or modify
10 | # it under the terms of the GNU General Public License as published by
11 | # the Free Software Foundation, either version 3 of the License, or
12 | # (at your option) any later version.
13 | #
14 | # Virtesk VDI is distributed in the hope that it will be useful,
15 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
16 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 | # GNU General Public License for more details.
18 | #
19 | # You should have received a copy of the GNU General Public License
20 | # along with Virtesk VDI. If not, see .
21 |
22 | # System Imports
23 | import traceback
24 | import logging
25 | import sys
26 |
27 | # Project imports
28 | import rhev_manager
29 | import utils
30 |
31 | try:
32 | description = """Show information about the virtual room:
33 | * config dump
34 | * analyze vm status
35 | * show snapshots
36 | """
37 |
38 | manager, room = rhev_manager.RhevManager.construct_from_cmdargs(
39 | description
40 | )
41 |
42 | manager.analyze_config_of_classroom(room)
43 |
44 | manager.cleanup()
45 |
46 | except utils.Failure as f:
47 | logging.error(f.msg)
48 | sys.exit(-1)
49 | except Exception as ex:
50 | logging.exception("Unexpected error: {0}".format(ex))
51 | logging.exception(traceback.format_exc())
52 | sys.exit(-1)
53 |
--------------------------------------------------------------------------------
/virtesk-vm-rollout/virtesk-virtroom-shutdown:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: UTF-8 -*-
3 | # vim: autoindent expandtab tabstop=4 sw=4 sts=4 filetype=python
4 |
5 | # Copyright (c) 2013-2016, Adfinis SyGroup AG
6 | #
7 | # This file is part of Amoothei-VDI.
8 | #
9 | # Amoothei-VDI is free software: you can redistribute it and/or modify
10 | # it under the terms of the GNU General Public License as published by
11 | # the Free Software Foundation, either version 3 of the License, or
12 | # (at your option) any later version.
13 | #
14 | # Amoothei-VDI is distributed in the hope that it will be useful,
15 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
16 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 | # GNU General Public License for more details.
18 | #
19 | # You should have received a copy of the GNU General Public License
20 | # along with Amoothei-VDI. If not, see .
21 |
22 | # System Imports
23 | import traceback
24 | import logging
25 | import sys
26 |
27 | # Project imports
28 | import rhev_manager
29 | import utils
30 |
31 | try:
32 | description = """Shutdown all VMs in a virtual room."""
33 |
34 | manager, room = rhev_manager.RhevManager.construct_from_cmdargs(
35 | description
36 | )
37 |
38 | manager.shutdown_all_vms_in_room(room)
39 |
40 | manager.cleanup()
41 |
42 | except utils.Failure as f:
43 | logging.error(f.msg)
44 | sys.exit(-1)
45 | except Exception as ex:
46 | logging.exception("Unexpected error: {0}".format(ex))
47 | logging.exception(traceback.format_exc())
48 | sys.exit(-1)
49 |
--------------------------------------------------------------------------------
/virtesk-vm-rollout/virtesk-virtroom-start:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: UTF-8 -*-
3 | # vim: autoindent expandtab tabstop=4 sw=4 sts=4 filetype=python
4 |
5 | # Copyright (c) 2013-2016, Adfinis SyGroup AG
6 | #
7 | # This file is part of Virtesk VDI.
8 | #
9 | # Virtesk VDI is free software: you can redistribute it and/or modify
10 | # it under the terms of the GNU General Public License as published by
11 | # the Free Software Foundation, either version 3 of the License, or
12 | # (at your option) any later version.
13 | #
14 | # Virtesk VDI is distributed in the hope that it will be useful,
15 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
16 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 | # GNU General Public License for more details.
18 | #
19 | # You should have received a copy of the GNU General Public License
20 | # along with Virtesk VDI. If not, see .
21 |
22 |
23 | # System Imports
24 | import traceback
25 | import logging
26 | import sys
27 |
28 | # Project imports
29 | import rhev_manager
30 | import utils
31 |
32 | try:
33 | description = """Starts all VMs in the virtual room."""
34 |
35 | manager, room = rhev_manager.RhevManager.construct_from_cmdargs(
36 | description
37 | )
38 |
39 | manager.start_all_vms_in_room(room)
40 |
41 | manager.cleanup()
42 |
43 | except utils.Failure as f:
44 | logging.error(f.msg)
45 | sys.exit(-1)
46 | except Exception as ex:
47 | logging.exception("Unexpected error: {0}".format(ex))
48 | logging.exception(traceback.format_exc())
49 | sys.exit(-1)
50 |
--------------------------------------------------------------------------------