├── .gitignore ├── .travis.yml ├── LICENSE ├── Makefile ├── README.md ├── automation ├── build-artifacts.mounts ├── build-artifacts.packages ├── build-artifacts.sh ├── check-merged.packages ├── check-merged.sh ├── check-patch.mounts ├── check-patch.packages └── check-patch.sh ├── image-specifications ├── README.md ├── base │ ├── Dockerfile │ └── setup.sh ├── engine-database │ ├── Dockerfile │ └── setup.sh ├── engine-spice-proxy │ ├── Dockerfile │ └── README.md ├── engine │ ├── 999-ovirt-engine.conf │ ├── Dockerfile │ ├── answers.conf.in │ ├── entrypoint.sh │ └── setup.patch ├── vdsc-syslog │ ├── Dockerfile │ └── root │ │ ├── entrypoint.sh │ │ └── etc │ │ └── rsyslog.conf └── vdsc │ ├── Dockerfile │ ├── confs │ ├── 50-offline-packager.conf │ ├── logger.conf │ ├── rsyslog.conf │ ├── sanlock.conf │ ├── svdsm.logger.conf │ └── vdsm.conf │ └── scripts │ ├── add_network.py │ ├── deploy.sh │ └── vdsm-deploy.service ├── os-manifests ├── configure_repo.sh ├── engine │ └── engine-deployment.yaml └── vdsc │ └── vdsc-deployment.yaml ├── project.conf └── tools └── src └── ovc ├── build.go ├── build ├── commands.go ├── dockerfiles.go ├── images.go ├── project.go ├── re.go └── templates.go ├── clean.go ├── deploy.go ├── glide.lock ├── glide.yaml ├── log └── log.go ├── main.go ├── push.go ├── save.go └── scripts └── embed.go /.gitignore: -------------------------------------------------------------------------------- 1 | *.gz 2 | *.log 3 | *.tar 4 | /exported-artifacts/ 5 | /tools/bin/ 6 | /tools/pkg/ 7 | /tools/src/ovc/embedded.go 8 | vendor/ 9 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: go 2 | 3 | go: 4 | - 1.8 5 | 6 | script: 7 | - make tool 8 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2017 Red Hat, Inc. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | 17 | # This Makefile is used to build and execute the tools, in particular 18 | # the 'build' tool which is responsible for reading the source code and 19 | # determining what needs to be done to build the images. 20 | # 21 | # If you are looking at how to build the images, then just run 'make', 22 | # and it should take care of it. 23 | # 24 | # If you are looking at changing the build process, then this isn't 25 | # probably the right place. Look at 'tools/src/ovirt/cmd/build/build.go' 26 | # instead, as that is the starting point for the main build process. 27 | 28 | # In order to use things like 'pushd' we need to explicitly set 'bash' as the 29 | # shell, as in some enviroments (Travis CI, for example) the default shell is 30 | # plain 'sh': 31 | SHELL=/bin/bash 32 | 33 | # The root of the Go source code: 34 | ROOT=$(PWD)/tools 35 | 36 | # Locations of the Go and Glide binaries: 37 | GO_BINARY=go 38 | GLIDE_BINARY=$(ROOT)/bin/glide 39 | 40 | # Location of the Glide project: 41 | GLIDE_PROJECT=$(shell find tools/src -name glide.yaml -print -quit) 42 | 43 | # Location of the generated tool: 44 | TOOL_BINARY=$(ROOT)/bin/ovc 45 | 46 | # Install Glide if necessary: 47 | $(GLIDE_BINARY): 48 | mkdir -p `dirname $(GLIDE_BINARY)` 49 | GOPATH="$(ROOT)"; \ 50 | export GOPATH; \ 51 | PATH="$(ROOT)/bin:$${PATH}"; \ 52 | export PATH; \ 53 | curl https://glide.sh/get | sh 54 | 55 | # The sources of the tool are the .go files, but also the image 56 | # specifications and the OpenShift manifests, as they are embedded 57 | # within the binary: 58 | TOOL_SOURCES=\ 59 | project.conf \ 60 | $(shell find tools/src -type f -name '*.go') \ 61 | $(shell find image-specifications -type f) \ 62 | $(shell find os-manifests -type f) \ 63 | $(NULL) 64 | 65 | # Rule to build the tool from its source code: 66 | $(TOOL_BINARY): $(GLIDE_BINARY) $(TOOL_SOURCES) 67 | GOPATH="$(ROOT)"; \ 68 | export GOPATH; \ 69 | pushd $$(dirname $(GLIDE_PROJECT)); \ 70 | $(GLIDE_BINARY) install && \ 71 | $(GO_BINARY) generate && \ 72 | $(GO_BINARY) build -o $@ *.go || \ 73 | exit 1; \ 74 | popd \ 75 | 76 | .PHONY: tool 77 | tool: $(TOOL_BINARY) 78 | 79 | .PHONY: build 80 | build: $(TOOL_BINARY) 81 | $< $@ 82 | 83 | .PHONY: save 84 | save: $(TOOL_BINARY) 85 | $< $@ 86 | 87 | .PHONY: push 88 | push: $(TOOL_BINARY) 89 | $< $@ 90 | 91 | .PHONY: deploy 92 | deploy: $(TOOL_BINARY) 93 | $< $@ 94 | 95 | .PHONY: deploy 96 | clean: $(TOOL_BINARY) 97 | $< $@ 98 | rm -rf tools/{bin,pkg} 99 | docker images --filter dangling=true --quiet | xargs -r docker rmi --force 100 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # oVirt-Containers - master snapshot 2 | 3 | 4 | > IMPORTANT: This project has been dropped from oVirt 5 | > 6 | > Keeping the repo only for reference. 7 | 8 | 9 | 10 | The repository includes image-specifications (for docker currently) and yaml 11 | manifests for openshift to run oVirt deployment (oVirt-Engine and oVirt-Node). 12 | 13 | ## Pre-requisites 14 | Must use oc tool version 1.5.0 - https://github.com/openshift/origin/releases 15 | 16 | | WARNING | 17 | | ---- | 18 | | origin-clients rpm installation adds to /bin oc binary that might be older - verify that you work with 1.5 by "oc version" | 19 | 20 | ## Getting openshift environment 21 | There are two options - running a cluster of openshift locally or using 22 | Minishift VM: 23 | ### Orchestration using Minishift 24 | Minishift is a VM running openshift cluster in it. This mostly being used for 25 | testing for easy and quicker deployment without changing local environemnt 26 | - Install minishift - https://github.com/minishift/minishift 27 | #### Nested virtualization support for the minishift VM 28 | Since we are going to run VMs inside the minishift VM, it will need nested virtualization support. Minishift documentation suggests to install docker-machine-driver-kvm v0.7.0 but this is not enough to get virtualization support and a more recent one is needed; the right instructions (assuming centos7) to get it are: 29 | ``` 30 | curl -L https://github.com/docker/machine/releases/download/v0.11.0/docker-machine-`uname -s`-`uname -m` >/tmp/docker-machine && 31 | chmod +x /tmp/docker-machine && 32 | sudo cp /tmp/docker-machine /usr/local/bin/docker-machine 33 | curl -L https://github.com/dhiltgen/docker-machine-kvm/releases/download/v0.10.0/docker-machine-driver-kvm-centos7 > /usr/local/bin/docker-machine-driver-kvm && 34 | chmod +x /usr/local/bin/docker-machine-driver-kvm 35 | ``` 36 | Nested virtualization support is required on your physical system, please check it with: 37 | ``` 38 | cat /sys/module/kvm_intel/parameters/nested 39 | Y 40 | ``` 41 | If nested virtualization is not supported, please check your OS documentation about how to enable it. 42 | 43 | - Run the following 44 | ``` 45 | export OCTAG=v1.5.0 46 | export PROJECT=ovirt 47 | export LATEST_MINISHIFT_CENTOS_ISO_BASE=$(curl -I https://github.com/minishift/minishift-centos-iso/releases/latest | grep "Location" | cut -d: -f2- | tr -d '\r' | xargs) 48 | export MINISHIFT_CENTOS_ISO=${LATEST_MINISHIFT_CENTOS_ISO_BASE/tag/download}/minishift-centos7.iso 49 | 50 | minishift start --memory 6144 --cpus 4 --iso-url=$MINISHIFT_CENTOS_ISO --openshift-version=$OCTAG 51 | export PATH=$PATH:~/.minishift/cache/oc/$OCTAG 52 | ``` 53 | ### Orchestration using 'oc cluster up' 54 | Just follow https://github.com/openshift/origin/blob/master/docs/cluster_up_down.md#linux 55 | 56 | ## Load oVirt to openshift instructions 57 | ### Login to openshift as system admin 58 | ``` 59 | oc login -u system:admin 60 | ``` 61 | 62 | ### Create oVirt project 63 | ``` 64 | export PROJECT=ovirt 65 | oc new-project $PROJECT --description="oVirt" --display-name="oVirt" 66 | ``` 67 | 68 | ### Add administrator permissions to 'developer' user account 69 | ``` 70 | oc adm policy add-role-to-user admin developer -n $PROJECT 71 | ``` 72 | 73 | ### Force a permissive security context constraints 74 | Allows the usage of root account inside engine pod 75 | ``` 76 | oc create serviceaccount useroot 77 | oc adm policy add-scc-to-user anyuid -z useroot 78 | ``` 79 | 80 | ### Allows host advanced privileges inside the vdsc pod 81 | ``` 82 | oc create serviceaccount privilegeduser 83 | oc adm policy add-scc-to-user privileged -z privilegeduser 84 | ``` 85 | 86 | ### Create engine and vdsc deployments and add them to the project 87 | Please note that the engine deployment is configured as paused 88 | ``` 89 | oc create -f os-manifests -R 90 | ``` 91 | 92 | #### To deploy just engine 93 | ``` 94 | oc create -f os-manifests/engine -R 95 | ``` 96 | 97 | #### To deploy just vdsc 98 | ``` 99 | oc create -f os-manifests/vdsc -R 100 | ``` 101 | 102 | ### Change the hostname for engine deployment and unpause it 103 | According to the hostname that was assigned to the associated route 104 | ``` 105 | oc set env dc/ovirt-engine -c ovirt-engine OVIRT_FQDN=$(oc describe routes ovirt-engine | grep "Requested Host:" | cut -d: -f2 | xargs) 106 | oc set env dc/ovirt-engine -c ovirt-engine SPICE_PROXY=http://$(oc describe routes ovirt-spice-proxy | grep "Requested Host:" | cut -d: -f2 | xargs):3128 107 | oc patch dc/ovirt-engine --patch '{"spec":{"paused": false}}' 108 | ``` 109 | 110 | Now you should be able to login as developer user (developer:admin) to the 111 | $PROJECT project, the server is accessible via web console at 112 | $(minishift console --url)" or locally at https://localhost:8443. 113 | -------------------------------------------------------------------------------- /automation/build-artifacts.mounts: -------------------------------------------------------------------------------- 1 | /var/run/docker.sock:/var/run/docker.sock 2 | -------------------------------------------------------------------------------- /automation/build-artifacts.packages: -------------------------------------------------------------------------------- 1 | docker 2 | git 3 | golang 4 | gzip 5 | -------------------------------------------------------------------------------- /automation/build-artifacts.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -xe 2 | [[ -d exported-artifacts ]] \ 3 | || mkdir -p exported-artifacts 4 | 5 | function clean_up { 6 | # We want to return the status of the last command executed *before* 7 | # cleaning, so we need to save it. 8 | local status="$?" 9 | 10 | # Do not exit inmediately if the cleaning fails, as we want to 11 | # report the status of the build, not of the cleaning. 12 | make clean || true 13 | 14 | exit "${status}" 15 | } 16 | 17 | trap clean_up EXIT SIGHUP SIGINT SIGTERM 18 | 19 | # TODO: add jenkins docker login 20 | 21 | # Build the images: 22 | make build 23 | 24 | # Save the images to tar files: 25 | make save 26 | 27 | # Move the generated artifacts and log files to the artifacts directory: 28 | mv \ 29 | tools/bin/ovc \ 30 | *.log \ 31 | *.tar.gz \ 32 | exported-artifacts 33 | 34 | # Pushing the images to the registry is currently disabled because 35 | # Jenkins doesn't have yet the required credentials. 36 | #make push 37 | 38 | clean_up 39 | -------------------------------------------------------------------------------- /automation/check-merged.packages: -------------------------------------------------------------------------------- 1 | docker 2 | -------------------------------------------------------------------------------- /automation/check-merged.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | # TODO verify container safety (on minishift?) -------------------------------------------------------------------------------- /automation/check-patch.mounts: -------------------------------------------------------------------------------- 1 | /var/run/docker.sock:/var/run/docker.sock 2 | -------------------------------------------------------------------------------- /automation/check-patch.packages: -------------------------------------------------------------------------------- 1 | docker 2 | git 3 | golang 4 | gzip 5 | -------------------------------------------------------------------------------- /automation/check-patch.sh: -------------------------------------------------------------------------------- 1 | ./automation/build-artifacts.sh 2 | -------------------------------------------------------------------------------- /image-specifications/README.md: -------------------------------------------------------------------------------- 1 | # Building oVirt Docker Images 2 | This document provides instructions for building local versions of the Docker 3 | images that are used by an ovirt-containers deployment. Unless you need to 4 | make changes you can skip these instructions. By default, deployment will pull 5 | all of the required images from DockerHub. 6 | 7 | ## Build 8 | Start working on your development machine within an appropriate checkout of 9 | this repository. If you are using minishift, set up your environment to use 10 | the minishift docker instance: 11 | ``` 12 | eval $( minishift docker-env ) 13 | ``` 14 | 15 | To automatically rebuild all required Docker images: 16 | ``` 17 | make build 18 | ``` 19 | 20 | #### Manual build instructions 21 | 22 | Check the openshift manifest files 23 | (`os-manifests/*/*-deployment.yaml`) to determine which docker images you need. 24 | At the time of this writing we require the following images: 25 | - ovirt/vdsc-syslog:master 26 | - ovirt/vdsc:master 27 | - ovirt/engine-spice-proxy:master 28 | - ovirt/engine-database:master 29 | - ovirt/engine:master 30 | 31 | Look in the Dockerfile associated with each image (eg. 32 | `image-specifications/vdsc/Dockerfile`) and discover that the images depend 33 | on the base layer `ovirt/base:master`. 34 | 35 | We are not concerned with locally building images outside of the ovirt 36 | namespace (eg. CentOS) and will allow these to be pulled from DockerHub. 37 | 38 | Build the images (make sure to tag each one properly using '-t'): 39 | ``` 40 | docker build -t ovirt/base:master image-specifications/base 41 | docker build -t ovirt/vdsc-syslog:master image-specifications/vdsc-syslog 42 | docker build -t ovirt/vdsc:master image-specifications/vdsc 43 | docker build -t ovirt/engine-spice-proxy:master image-specifications/engine-spice-proxy 44 | docker build -t ovirt/engine-database:master image-specifications/engine-database 45 | docker build -t ovirt/engine:master image-specifications/engine 46 | ``` 47 | 48 | After building make sure the updated images are available to the Openshift 49 | docker instance. Unless you targeted the minishift docker environment as 50 | described above you may need to transfer the images. This can be done with 51 | docker save/load: 52 | ``` 53 | docker save ovirt/vdsc:master | ssh 'docker load' 54 | ``` 55 | 56 | ## Install 57 | After making changes to the docker images or openshift deployment files you 58 | may want to replace an existing deployment. Use a similar command to delete 59 | the application as you used to create it, for example: 60 | ``` 61 | oc delete -f os-manifests -R 62 | ``` 63 | 64 | Then create the application again to use the updated images and manifests: 65 | ``` 66 | oc create -f os-manifests -R 67 | ``` 68 | -------------------------------------------------------------------------------- /image-specifications/base/Dockerfile: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2017 Red Hat, Inc. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | 17 | FROM centos:7 18 | 19 | COPY setup.sh / 20 | RUN /setup.sh && rm /setup.sh 21 | -------------------------------------------------------------------------------- /image-specifications/base/setup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -ex 2 | 3 | # 4 | # Copyright (c) 2017 Red Hat, Inc. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | # This is script is intended to run during the build of the image, to 20 | # perform all the setup steps generating only one layer. 21 | 22 | # Install the oVirt release RPM: 23 | yum -y install http://resources.ovirt.org/pub/yum-repo/ovirt-release-master.rpm 24 | 25 | # Add here the lines to install other packages that are used/useful in 26 | # all the oVirt containers: 27 | #yum -y install ... 28 | yum -y install centos-release-scl 29 | 30 | # Clean the yum database: 31 | yum -y clean all 32 | -------------------------------------------------------------------------------- /image-specifications/engine-database/Dockerfile: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2017 Red Hat, Inc. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | 17 | FROM centos/postgresql-95-centos7 18 | 19 | # The base image changes to user 26 (postgres) in order to run the 20 | # database server. But we need to run the setup as root, as otherwise it 21 | # can't write some of the files. Once that is done we restore user 26. 22 | USER root 23 | COPY setup.sh / 24 | RUN /setup.sh && rm /setup.sh 25 | USER 26 26 | -------------------------------------------------------------------------------- /image-specifications/engine-database/setup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -ex 2 | 3 | # 4 | # Copyright (c) 2017 Red Hat, Inc. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | # The base image creates the 'postgresql.conf' file from this template 20 | # each time the container is started. See here for details: 21 | # 22 | # https://github.com/sclorg/postgresql-container/blob/master/9.5/root/usr/share/container-scripts/postgresql/common.sh 23 | # 24 | # That means that we can modify it, to add our own settings. We check 25 | # that the file exists just fail the build and hence notice early if 26 | # this changes. 27 | POSTGRESQL_CONF_TEMPLATE="${CONTAINER_SCRIPTS_PATH}/openshift-custom-postgresql.conf.template" 28 | if [ ! -f "${POSTGRESQL_CONF_TEMPLATE}" ]; then 29 | echo "The file '${POSTGRESQL_CONF_TEMPLATE}' doesn't exist." >&2 30 | exit 1 31 | fi 32 | 33 | # Recent versions of the engine need custom auto-vacuum parameters. The 34 | # setup tool checks them, and fails the start of the engine if they 35 | # aren't set. 36 | cat >> "${POSTGRESQL_CONF_TEMPLATE}" <<. 37 | autovacuum_vacuum_scale_factor = 0.01 38 | autovacuum_analyze_scale_factor = 0.075 39 | autovacuum_max_workers = 6 40 | maintenance_work_mem = 65536 41 | . 42 | -------------------------------------------------------------------------------- /image-specifications/engine-spice-proxy/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM {{ tag "base" }} 2 | 3 | MAINTAINER Roman Mohr 4 | 5 | EXPOSE 3128 6 | 7 | RUN yum install -y squid && yum clean all 8 | 9 | RUN sed -i -e "s/http_access deny CONNECT !SSL_ports/http_access deny CONNECT !Safe_ports/" /etc/squid/squid.conf 10 | 11 | CMD squid -NCd1 12 | -------------------------------------------------------------------------------- /image-specifications/engine-spice-proxy/README.md: -------------------------------------------------------------------------------- 1 | # docker-spice-squid 2 | Spice proxy for ovirt in a container 3 | -------------------------------------------------------------------------------- /image-specifications/engine/999-ovirt-engine.conf: -------------------------------------------------------------------------------- 1 | ENGINE_HTTP_ENABLED=true 2 | ENGINE_HTTPS_ENABLED=true 3 | ENGINE_HTTP_PORT=8700 4 | ENGINE_HTTPS_PORT=8701 5 | -------------------------------------------------------------------------------- /image-specifications/engine/Dockerfile: -------------------------------------------------------------------------------- 1 | # TODO: log setup log and boot.log to stdout only 2 | # TODO: fix gpg key warnings 3 | # TODO: make sure unicode is used 4 | # TODO: give ovirt user a well known gid and uid 5 | # TODO: fix redirect from http to https (port is missing) 6 | 7 | FROM {{ tag "base" }} 8 | 9 | MAINTAINER Redhat Inc. 10 | 11 | # Database 12 | ENV POSTGRES_USER engine 13 | ENV POSTGRES_PASSWORD engine 14 | ENV POSTGRES_DB engine 15 | ENV POSTGRES_HOST postgres 16 | ENV POSTGRES_PORT 5432 17 | 18 | # oVirt 19 | ENV OVIRT_FQDN localhost 20 | 21 | EXPOSE 8700 8701 22 | 23 | USER root 24 | 25 | RUN yum -y install ovirt-engine patch rh-postgresql95-postgresql \ 26 | && yum -y clean all 27 | 28 | # dockerize helps us waiting for postgres being ready 29 | ENV DOCKERIZE_VERSION v0.2.0 30 | RUN curl -OL https://github.com/jwilder/dockerize/releases/download/$DOCKERIZE_VERSION/dockerize-linux-amd64-$DOCKERIZE_VERSION.tar.gz \ 31 | && tar -C /usr/local/bin -xzvf dockerize-linux-amd64-$DOCKERIZE_VERSION.tar.gz 32 | 33 | # engine-setup needs the link to initctl 34 | RUN ln -s /usr/sbin/service /usr/bin/initctl 35 | 36 | #oVirt 37 | ENV OVIRT_PASSWORD engine 38 | ENV OVIRT_PKI_ORGANIZATION oVirt 39 | 40 | COPY entrypoint.sh answers.conf.in setup.patch / 41 | COPY 999-ovirt-engine.conf /etc/ovirt-engine/engine.conf.d/ 42 | 43 | # patch engine-setup so that it does not try to start or stop services with systemd 44 | RUN patch -p0 < setup.patch 45 | 46 | # For kubernetes copy pki template files to a backup directory 47 | RUN cp -a /etc/pki/ovirt-engine /etc/pki/ovirt-engine.tmpl 48 | 49 | # Persist this folder to keep the generated TLS certificates on the first start 50 | VOLUME /etc/pki/ovirt-engine 51 | # Persist this folder to keep the database backups 52 | VOLUME /var/lib/ovirt-engine/backups 53 | 54 | # Encrypt host communication 55 | ENV HOST_ENCRYPT=true 56 | # Try to provision hosts when they are added 57 | ENV HOST_INSTALL=true 58 | # Use host identifier when talking with the host, so that the host sees who it is from the engines view. 59 | # This is valuable when working with ovirt-vdsmfake 60 | ENV HOST_USE_IDENTIFIER=false 61 | # HACK: Config BlockMigrationOnSwapUsagePercentage so that the vm will start in ovirt-engine 62 | # For some reason this check fails the start vm - this should be figured out instead of this hack 63 | ENV BLOCK_MIGRATION_ON_SWAP_USAGE_PERCENTAGE=9999 64 | 65 | # Public reachable HTTPS port 66 | ENV HTTPS_PORT 8701 67 | ENV SSO_ALTERNATE_ENGINE_FQDNS="localhost:8701 127.0.0.1:8701" 68 | 69 | CMD bash /entrypoint.sh 70 | -------------------------------------------------------------------------------- /image-specifications/engine/answers.conf.in: -------------------------------------------------------------------------------- 1 | # action=setup 2 | [environment:default] 3 | OVESETUP_DIALOG/confirmSettings=bool:True 4 | OVESETUP_CONFIG/applicationMode=str:both 5 | OVESETUP_CONFIG/remoteEngineSetupStyle=none:None 6 | OVESETUP_CONFIG/sanWipeAfterDelete=bool:False 7 | OVESETUP_CONFIG/storageIsLocal=bool:False 8 | OVESETUP_CONFIG/firewallManager=none:None 9 | OVESETUP_CONFIG/remoteEngineHostRootPassword=none:None 10 | OVESETUP_CONFIG/firewallChangesReview=none:None 11 | OVESETUP_CONFIG/updateFirewall=bool:False 12 | OVESETUP_CONFIG/remoteEngineHostSshPort=none:None 13 | OVESETUP_CONFIG/storageType=none:None 14 | OSETUP_RPMDISTRO/requireRollback=none:None 15 | OSETUP_RPMDISTRO/enableUpgrade=none:None 16 | OVESETUP_DB/upgradeWithHeEl6Hosts=none:None 17 | OVESETUP_DB/secured=bool:False 18 | OVESETUP_DB/dumper=str:pg_custom 19 | OVESETUP_DB/fixDbViolations=none:None 20 | OVESETUP_DB/filter=none:None 21 | OVESETUP_DB/restoreJobs=int:2 22 | OVESETUP_DB/securedHostValidation=bool:False 23 | OVESETUP_ENGINE_CORE/enable=bool:True 24 | OVESETUP_CORE/engineStop=none:None 25 | OVESETUP_SYSTEM/memCheckEnabled=bool:False 26 | OVESETUP_SYSTEM/nfsConfigEnabled=none:None 27 | OVESETUP_PKI/renew=none:None 28 | OVESETUP_CONFIG/isoDomainName=none:None 29 | OVESETUP_CONFIG/engineHeapMax=str:2929M 30 | OVESETUP_CONFIG/isoDomainACL=none:None 31 | OVESETUP_CONFIG/isoDomainMountPoint=none:None 32 | OVESETUP_CONFIG/engineDbBackupDir=str:/var/lib/ovirt-engine/backups 33 | OVESETUP_CONFIG/engineHeapMin=str:2929M 34 | OVESETUP_AIO/configure=none:None 35 | OVESETUP_AIO/storageDomainName=none:None 36 | OVESETUP_AIO/storageDomainDir=none:None 37 | OVESETUP_PROVISIONING/postgresProvisioningEnabled=bool:False 38 | OVESETUP_APACHE/configureRootRedirection=bool:True 39 | OVESETUP_APACHE/configureSsl=bool:True 40 | OVESETUP_VMCONSOLE_PROXY_CONFIG/vmconsoleProxyConfig=bool:True 41 | OVESETUP_CONFIG/websocketProxyConfig=bool:True 42 | OVESETUP_CONFIG/fenceKdumpListenerStopNeeded=bool:False 43 | OVESETUP_APACHE/enable=bool:False 44 | OVESETUP_CONFIG/engineServiceStopNeeded=bool:False 45 | OVESETUP_ASYNC/clearTasks=bool:False 46 | OVESETUP_DWH_CORE/enable=bool:False 47 | OVESETUP_DWH_PROVISIONING/postgresProvisioningEnabled=bool:False 48 | OVESETUP_CONFIG/imageioProxyConfig=bool:False 49 | 50 | # Don't install the the OVN provider: 51 | OVESETUP_OVN/ovirtProviderOvn=bool:False 52 | 53 | # Don't perform database full vacuum: 54 | OVESETUP_DB/engineVacuumFull=bool:False 55 | 56 | # Work with PostgreSQL 9.5 from SCL 57 | COMMAND/pg_dump=str:/opt/rh/rh-postgresql95/root/usr/bin/pg_dump 58 | COMMAND/psql=str:/opt/rh/rh-postgresql95/root/usr/bin/psql 59 | COMMAND/pg_restore=str:/opt/rh/rh-postgresql95/root/usr/bin/pg_restore 60 | COMMAND/postgresql-setup=str:/opt/rh/rh-postgresql95/root/usr/bin/postgresql-setup 61 | -------------------------------------------------------------------------------- /image-specifications/engine/entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | cp -f answers.conf.in answers.conf 5 | echo OVESETUP_DB/user=str:$POSTGRES_USER >> answers.conf 6 | echo OVESETUP_DB/password=str:$POSTGRES_PASSWORD >> answers.conf 7 | echo OVESETUP_DB/database=str:$POSTGRES_DB >> answers.conf 8 | echo OVESETUP_DB/host=str:$POSTGRES_HOST >> answers.conf 9 | echo OVESETUP_DB/port=str:$POSTGRES_PORT >> answers.conf 10 | echo OVESETUP_ENGINE_CONFIG/fqdn=str:$OVIRT_FQDN >> answers.conf 11 | echo OVESETUP_CONFIG/fqdn=str:$OVIRT_FQDN >> answers.conf 12 | echo OVESETUP_CONFIG/adminPassword=str:$OVIRT_PASSWORD >> answers.conf 13 | echo OVESETUP_PKI/organization=str:$OVIRT_PKI_ORGANIZATION >> answers.conf 14 | 15 | # On the first run, copy pki template files into original 16 | # template location because kubernetes mounts hide 17 | # the original files in the image. 18 | if [ ! -f /etc/pki/ovirt-engine/serial.txt ]; then 19 | cp -a /etc/pki/ovirt-engine.tmpl/* /etc/pki/ovirt-engine/ 20 | fi 21 | chown ovirt:ovirt /etc/pki/ovirt-engine 22 | 23 | # Wait for postgres 24 | dockerize -wait tcp://${POSTGRES_HOST}:${POSTGRES_PORT} -timeout 1m 25 | 26 | scl enable rh-postgresql95 -- engine-setup --config=answers.conf --offline 27 | 28 | if [ -n "$SPICE_PROXY" ]; then 29 | engine-config -s SpiceProxyDefault=$SPICE_PROXY 30 | fi 31 | 32 | # SSO configuration 33 | echo SSO_ALTERNATE_ENGINE_FQDNS="\"$SSO_ALTERNATE_ENGINE_FQDNS\"" >> /etc/ovirt-engine/engine.conf.d/999-ovirt-engine.conf 34 | echo ENGINE_SSO_SERVICE_SSL_VERIFY_HOST=false >> /etc/ovirt-engine/engine.conf.d/999-ovirt-engine.conf 35 | 36 | if [ -n "$ENGINE_SSO_AUTH_URL" ]; then 37 | echo ENGINE_SSO_INSTALLED_ON_ENGINE_HOST=false >> /etc/ovirt-engine/engine.conf.d/999-ovirt-engine.conf 38 | echo "ENGINE_SSO_AUTH_URL=\"$ENGINE_SSO_AUTH_URL\"" >> /etc/ovirt-engine/engine.conf.d/999-ovirt-engine.conf 39 | else 40 | echo "ENGINE_SSO_AUTH_URL=\"https://${OVIRT_FQDN}/ovirt-engine/sso\"" >> /etc/ovirt-engine/engine.conf.d/999-ovirt-engine.conf 41 | fi 42 | 43 | echo SSO_CALLBACK_PREFIX_CHECK=false >> /etc/ovirt-engine/engine.conf.d/999-ovirt-engine.conf 44 | echo "ENGINE_SSO_SERVICE_URL=\"https://localhost:8701/ovirt-engine/sso\"" >> /etc/ovirt-engine/engine.conf.d/999-ovirt-engine.conf 45 | echo "ENGINE_BASE_URL=\"https://${OVIRT_FQDN}/ovirt-engine/\"" >> /etc/ovirt-engine/engine.conf.d/999-ovirt-engine.conf 46 | echo "SSO_ENGINE_URL=\"https://localhost:8701/ovirt-engine/\"" >> /etc/ovirt-engine/engine.conf.d/999-ovirt-engine.conf 47 | 48 | export PGPASSWORD=$POSTGRES_PASSWORD 49 | 50 | psql $POSTGRES_DB -h $POSTGRES_HOST -p $POSTGRES_PORT -U $POSTGRES_USER -c "UPDATE vdc_options set option_value = '$HOST_INSTALL' where option_name = 'InstallVds';" 51 | psql $POSTGRES_DB -h $POSTGRES_HOST -p $POSTGRES_PORT -U $POSTGRES_USER -c "UPDATE vdc_options set option_value = '$HOST_USE_IDENTIFIER' where option_name = 'UseHostNameIdentifier';" 52 | 53 | engine-config -s SSLEnabled=$HOST_ENCRYPT 54 | engine-config -s EncryptHostCommunication=$HOST_ENCRYPT 55 | engine-config -s BlockMigrationOnSwapUsagePercentage=$BLOCK_MIGRATION_ON_SWAP_USAGE_PERCENTAGE 56 | 57 | su -m -s /bin/python ovirt /usr/share/ovirt-engine/services/ovirt-engine/ovirt-engine.py start 58 | -------------------------------------------------------------------------------- /image-specifications/engine/setup.patch: -------------------------------------------------------------------------------- 1 | diff -Naur /usr/share/ovirt-engine-orig/services/ovirt-engine/ovirt-engine.xml.in /usr/share/ovirt-engine/services/ovirt-engine/ovirt-engine.xml.in 2 | --- /usr/share/ovirt-engine-orig/services/ovirt-engine/ovirt-engine.xml.in 2016-02-29 23:07:12.000000000 +0000 3 | +++ /usr/share/ovirt-engine/services/ovirt-engine/ovirt-engine.xml.in 2016-03-05 05:36:58.991177449 +0000 4 | @@ -162,18 +162,14 @@ 5 | 6 | 7 | 8 | - 9 | - 10 | - {% if config.getboolean('ENGINE_LOG_TO_CONSOLE') %} 11 | 12 | - {% endif %} 13 | 14 | 15 | 16 | 17 | 18 | 19 | - 20 | + 21 | 22 | 23 | 24 | @@ -186,8 +182,7 @@ 25 | 26 | 27 | 28 | - 29 | - 30 | + 31 | 32 | 33 | 34 | diff -Naur /usr/share/ovirt-engine/setup_backup/plugins/ovirt-engine-common/ovirt-engine-common/system/apache.py /usr/share/ovirt-engine/setup/plugins/ovirt-engine-common/ovirt-engine-common/system/apache.py 35 | --- /usr/share/ovirt-engine/setup_backup/plugins/ovirt-engine-common/ovirt-engine-common/system/apache.py 2016-02-29 23:07:13.000000000 +0000 36 | +++ /usr/share/ovirt-engine/setup/plugins/ovirt-engine-common/ovirt-engine-common/system/apache.py 2016-03-04 10:45:25.198285051 +0000 37 | @@ -70,7 +70,7 @@ 38 | self._enabled and 39 | self.environment[ 40 | oengcommcons.ApacheEnv.NEED_RESTART 41 | - ] 42 | + ] and False 43 | ), 44 | ) 45 | def _closeup(self): 46 | diff -Naur /usr/share/ovirt-engine/setup_backup/plugins/ovirt-engine-rename/ovirt-engine/engine.py /usr/share/ovirt-engine/setup/plugins/ovirt-engine-rename/ovirt-engine/engine.py 47 | --- /usr/share/ovirt-engine/setup_backup/plugins/ovirt-engine-rename/ovirt-engine/engine.py 2016-02-29 23:07:13.000000000 +0000 48 | +++ /usr/share/ovirt-engine/setup/plugins/ovirt-engine-rename/ovirt-engine/engine.py 2016-03-04 10:45:49.672298016 +0000 49 | @@ -45,7 +45,7 @@ 50 | name=oengcommcons.Stages.CORE_ENGINE_START, 51 | condition=lambda self: not self.environment[ 52 | osetupcons.CoreEnv.DEVELOPER_MODE 53 | - ], 54 | + ] and False, 55 | ) 56 | def _closeup(self): 57 | self.logger.info(_('Starting engine service')) 58 | diff -Naur /usr/share/ovirt-engine/setup_backup/plugins/ovirt-engine-setup/ovirt-engine/fence_kdump_listener/config.py /usr/share/ovirt-engine/setup/plugins/ovirt-engine-setup/ovirt-engine/fence_kdump_listener/config.py 59 | --- /usr/share/ovirt-engine/setup_backup/plugins/ovirt-engine-setup/ovirt-engine/fence_kdump_listener/config.py 2016-02-29 23:07:12.000000000 +0000 60 | +++ /usr/share/ovirt-engine/setup/plugins/ovirt-engine-setup/ovirt-engine/fence_kdump_listener/config.py 2016-03-04 10:46:26.547317550 +0000 61 | @@ -89,7 +89,7 @@ 62 | not self.environment[ 63 | osetupcons.CoreEnv.DEVELOPER_MODE 64 | ] and 65 | - self._enabled 66 | + self._enabled and False 67 | ), 68 | ) 69 | def _closeup(self): 70 | diff -Naur /usr/share/ovirt-engine/setup_backup/plugins/ovirt-engine-setup/ovirt-engine/system/engine.py /usr/share/ovirt-engine/setup/plugins/ovirt-engine-setup/ovirt-engine/system/engine.py 71 | --- /usr/share/ovirt-engine/setup_backup/plugins/ovirt-engine-setup/ovirt-engine/system/engine.py 2016-02-29 23:07:13.000000000 +0000 72 | +++ /usr/share/ovirt-engine/setup/plugins/ovirt-engine-setup/ovirt-engine/system/engine.py 2016-03-04 10:48:23.823379673 +0000 73 | @@ -46,7 +46,7 @@ 74 | self.environment[oenginecons.CoreEnv.ENABLE] and 75 | not self.environment[ 76 | osetupcons.CoreEnv.DEVELOPER_MODE 77 | - ] 78 | + ] and False 79 | ), 80 | ) 81 | def _closeup(self): 82 | diff -Naur /usr/share/ovirt-engine/setup_backup/plugins/ovirt-engine-setup/vmconsole_proxy_helper/system.py /usr/share/ovirt-engine/setup/plugins/ovirt-engine-setup/vmconsole_proxy_helper/system.py 83 | --- /usr/share/ovirt-engine/setup_backup/plugins/ovirt-engine-setup/vmconsole_proxy_helper/system.py 2016-02-29 23:07:12.000000000 +0000 84 | +++ /usr/share/ovirt-engine/setup/plugins/ovirt-engine-setup/vmconsole_proxy_helper/system.py 2016-03-04 11:00:24.780761585 +0000 85 | @@ -80,7 +80,7 @@ 86 | osetupcons.CoreEnv.DEVELOPER_MODE 87 | ] and self.environment[ 88 | ovmpcons.ConfigEnv.VMCONSOLE_PROXY_CONFIG 89 | - ] 90 | + ] and False 91 | ), 92 | ) 93 | def _closeup(self): 94 | diff -Nuar /usr/share/ovirt-engine/setup_backup/plugins/ovirt-engine-setup/websocket_proxy/config.py /usr/share/ovirt-engine/setup/plugins/ovirt-engine-setup/websocket_proxy/config.py 95 | --- /usr/share/ovirt-engine/setup_backup/plugins/ovirt-engine-setup/websocket_proxy/config.py 2016-02-29 23:07:12.000000000 +0000 96 | +++ /usr/share/ovirt-engine/setup/plugins/ovirt-engine-setup/websocket_proxy/config.py 2016-03-04 11:06:01.215939805 +0000 97 | @@ -271,7 +271,7 @@ 98 | ] and ( 99 | self._needStart or 100 | self._enabled 101 | - ) 102 | + ) and False 103 | ), 104 | ) 105 | def _closeup(self): 106 | -------------------------------------------------------------------------------- /image-specifications/vdsc-syslog/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM {{ tag "base" }} 2 | 3 | MAINTAINER "Yaniv Bronhaim" 4 | 5 | RUN yum -y install rsyslog && yum -y clean all 6 | 7 | EXPOSE 514 514/tcp 8 | 9 | COPY root / 10 | 11 | ENTRYPOINT /entrypoint.sh 12 | -------------------------------------------------------------------------------- /image-specifications/vdsc-syslog/root/entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -ex 2 | 3 | # 4 | # Copyright (c) 2017 Red Hat, Inc. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | # Load the environment file: 20 | if [ -f /etc/sysconfig/rsyslog]; then 21 | . /etc/sysconfig/rsyslog 22 | fi 23 | 24 | # Start the daemon: 25 | umask 0066 26 | exec /usr/sbin/rsyslogd -n ${SYSLOGD_OPTIONS} 27 | -------------------------------------------------------------------------------- /image-specifications/vdsc-syslog/root/etc/rsyslog.conf: -------------------------------------------------------------------------------- 1 | #### MODULES #### 2 | $ModLoad imtcp 3 | $InputTCPServerRun 514 4 | $InputTCPServerBindRuleset remote 5 | 6 | #### GLOBAL DIRECTIVES #### 7 | # Use default timestamp format 8 | $ActionFileDefaultTemplate RSYSLOG_TraditionalFileFormat 9 | 10 | #### RULES #### 11 | *.* /dev/stdout 12 | -------------------------------------------------------------------------------- /image-specifications/vdsc/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM {{ tag "base" }} 2 | MAINTAINER "Yaniv Bronhaim" 3 | 4 | ENV container docker 5 | 6 | RUN echo "root:root" | chpasswd 7 | RUN echo "options kvm-intel nested=1" > /etc/modprobe.d/kvm-intel.conf 8 | RUN ln -s ../boot/grub2/grub.cfg /etc/grub2.cfg 9 | 10 | # copied from http://developers.redhat.com/blog/2014/05/05/running-systemd-within-docker-container/ 11 | RUN yum -y update; yum clean all 12 | RUN yum -y install systemd; yum clean all; \ 13 | (cd /lib/systemd/system/sysinit.target.wants/; for i in *; do [ $i == systemd-tmpfiles-setup.service ] || rm -f $i; done); \ 14 | rm -f /lib/systemd/system/multi-user.target.wants/*;\ 15 | rm -f /etc/systemd/system/*.wants/*;\ 16 | rm -f /lib/systemd/system/local-fs.target.wants/*; \ 17 | rm -f /lib/systemd/system/sockets.target.wants/*udev*; \ 18 | rm -f /lib/systemd/system/sockets.target.wants/*initctl*; \ 19 | rm -f /lib/systemd/system/basic.target.wants/*;\ 20 | rm -f /lib/systemd/system/anaconda.target.wants/*; 21 | VOLUME [ "/sys/fs/cgroup" ] 22 | # http://developers.redhat.com/blog/2014/05/05/running-systemd-within-docker-container/ 23 | 24 | # copied from ovirt-container-node 25 | RUN yum -y install libvirt-daemon-driver-* libvirt-daemon libvirt-daemon-kvm qemu-kvm qemu-kvm-tools 26 | RUN localedef -i en_US -c -f UTF-8 en_US.UTF-8 27 | RUN rm -rf /etc/sysconfig/network-scripts/ifcfg-* 28 | RUN yum install -y tuned kexec-tools iptables-services; yum clean all 29 | RUN mkdir -p /etc/iscsi; 30 | # ovirt-container-node 31 | 32 | RUN yum install -y epel-release 33 | RUN yum install -y vdsm vdsm-cli vdsm-hook-faqemu; yum clean all; 34 | RUN yum install -y dhclient rsyslog iproute grub2-tools openssh-server; yum clean all; 35 | 36 | # conf for host-deploy to avoid upgrading packages check 37 | RUN mkdir /etc/ovirt-host-deploy.conf.d 38 | ADD confs/50-offline-packager.conf /etc/ovirt-host-deploy.conf.d/ 39 | ADD confs/vdsm.conf /etc/vdsm/vdsm.conf 40 | 41 | # set logging to local syslog 42 | ADD confs/logger.conf /etc/vdsm/logger.conf 43 | ADD confs/svdsm.logger.conf /etc/vdsm/svdsm.logger.conf 44 | 45 | # disable sanlock wdmd 46 | ADD confs/sanlock.conf /etc/sanlock/sanlock.conf 47 | 48 | ADD confs/rsyslog.conf /etc/rsyslog.conf 49 | 50 | # for some reason this file is missing when running vdsm-tool configure 51 | RUN touch /etc/libvirt/qemu-sanlock.conf 52 | 53 | # removing multipath and iscsi dependency 54 | RUN sed -i 's/multipathd.service //g' /usr/lib/systemd/system/vdsmd.service 55 | RUN sed -i 's/iscsid.service //g' /usr/lib/systemd/system/vdsmd.service 56 | 57 | # we need to enable vdsm and supervdsm to start. not part of configure yet, but should 58 | RUN systemctl enable vdsmd.service supervdsmd.service sshd.service rsyslog.service 59 | 60 | # set version for host-deploy 61 | RUN echo $(date -u +%Y%m%d%H%M%S) > /etc/ovirt-container-node-release 62 | 63 | # COPYING SCRIPT AND ENABLE DEPLOY SYSTEMD SCRIPT RUN 64 | ADD scripts/* /root/ 65 | RUN mv /root/vdsm-deploy.service /usr/lib/systemd/system/ 66 | RUN systemctl enable vdsm-deploy.service 67 | 68 | EXPOSE 54321 69 | 70 | CMD [ "/usr/sbin/init" ] 71 | -------------------------------------------------------------------------------- /image-specifications/vdsc/confs/50-offline-packager.conf: -------------------------------------------------------------------------------- 1 | [environment:init] 2 | ODEPLOY/offlinePackager=bool:True 3 | PACKAGER/yumpackagerEnabled=bool:False 4 | -------------------------------------------------------------------------------- /image-specifications/vdsc/confs/logger.conf: -------------------------------------------------------------------------------- 1 | [loggers] 2 | keys=root 3 | 4 | [handlers] 5 | keys=syslog,logfile 6 | 7 | [formatters] 8 | keys=long 9 | 10 | [logger_root] 11 | level=DEBUG 12 | handlers=syslog,logfile 13 | propagate=0 14 | 15 | [handler_syslog] 16 | level=DEBUG 17 | class=handlers.SysLogHandler 18 | formatter=long 19 | args=('/dev/log', handlers.SysLogHandler.LOG_USER) 20 | 21 | [handler_logfile] 22 | class=vdsm.logUtils.UserGroupEnforcingHandler 23 | args=('vdsm', 'kvm', '/var/log/vdsm/vdsm.log',) 24 | filters=storage.misc.TracebackRepeatFilter 25 | level=DEBUG 26 | formatter=long 27 | 28 | [formatter_long] 29 | format: %(levelname)-5s (%(threadName)s) [%(name)s] %(message)s (%(module)s:%(lineno)d) 30 | -------------------------------------------------------------------------------- /image-specifications/vdsc/confs/rsyslog.conf: -------------------------------------------------------------------------------- 1 | #### MODULES #### 2 | $Modload imjournal 3 | 4 | #### GLOBAL DIRECTIVES #### 5 | # Use default timestamp format 6 | $ActionFileDefaultTemplate RSYSLOG_TraditionalFileFormat 7 | 8 | #### RULES #### 9 | *.* @@vdsm-kube-logger:514 10 | *.* @@localhost:514 11 | -------------------------------------------------------------------------------- /image-specifications/vdsc/confs/sanlock.conf: -------------------------------------------------------------------------------- 1 | use_watchdog = 0 2 | -------------------------------------------------------------------------------- /image-specifications/vdsc/confs/svdsm.logger.conf: -------------------------------------------------------------------------------- 1 | [loggers] 2 | keys=root 3 | 4 | [handlers] 5 | keys=logfile,syslog 6 | 7 | [formatters] 8 | keys=long 9 | 10 | [logger_root] 11 | level=DEBUG 12 | handlers=logfile,syslog 13 | propagate=0 14 | 15 | [handler_logfile] 16 | class=vdsm.logUtils.UserGroupEnforcingHandler 17 | args=('root', 'root', '/var/log/vdsm/supervdsm.log',) 18 | filters=storage.misc.TracebackRepeatFilter 19 | level=DEBUG 20 | formatter=long 21 | 22 | [handler_syslog] 23 | level=DEBUG 24 | class=handlers.SysLogHandler 25 | formatter=long 26 | args=('/dev/log', handlers.SysLogHandler.LOG_USER) 27 | 28 | [formatter_long] 29 | format: %(levelname)-5s (%(threadName)s) [%(name)s] %(message)s (%(module)s:%(lineno)d) 30 | -------------------------------------------------------------------------------- /image-specifications/vdsc/confs/vdsm.conf: -------------------------------------------------------------------------------- 1 | [var] 2 | fake_kvm_support=true 3 | -------------------------------------------------------------------------------- /image-specifications/vdsc/scripts/add_network.py: -------------------------------------------------------------------------------- 1 | #!/bin/python 2 | from vdsm import vdscli 3 | import socket 4 | 5 | c = vdscli.connect() 6 | network_attrs = {'nic': 'veth_name0', 7 | 'ipaddr': socket.gethostbyname(socket.gethostname()), 8 | 'netmask': '255.240.0.0', 9 | 'gateway': '172.17.0.1', 10 | 'defaultRoute': True, 11 | 'bridged': True} 12 | 13 | c.setupNetworks({'ovirtmgmt': network_attrs}, {}, {'connectivityCheck': False}) 14 | -------------------------------------------------------------------------------- /image-specifications/vdsc/scripts/deploy.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # /dev is mounted from the host so we have to fix permissions at runtime 4 | chown root:kvm /dev/kvm 5 | chmod 0660 /dev/kvm 6 | 7 | # loading kernel modules for networking 8 | modprobe bonding 9 | modprobe 8021q 10 | modprobe ebtables 11 | modprobe etables_nat 12 | 13 | mkdir -p /var/log/vdsm 14 | mkdir -p /var/log/ovirt-imageio-daemon 15 | chown vdsm:kvm /var/log/vdsm /var/log/ovirt-imageio-daemon 16 | 17 | vdsm-tool configure --force 18 | 19 | # setting link name - vdsm recognize veth_* prefix as veth type device 20 | ip link set eth0 down 21 | ip link set eth0 name veth_name0 22 | ip link set veth_name0 up 23 | 24 | sleep 5 25 | 26 | ip route add default via 172.17.0.1 dev veth_name0 27 | service vdsmd restart 28 | 29 | sleep 5 30 | 31 | python /root/add_network.py 32 | 33 | # ovirt registration flow. 34 | declare $(xargs -n 1 -0 < /proc/1/environ | grep MY_NODE_NAME) 35 | MYNAME=$(hostname -f) 36 | SSHPORT=22222 37 | ENGINE_SERVICE=ovirt-engine.ovirt.svc 38 | ENGINE_HTTPS_PORT=443 39 | ENGINE_FQDN=$(echo "Q" | openssl s_client -connect $ENGINE_SERVICE:$ENGINE_HTTPS_PORT 2>&1 | grep "subject=" | sed 's/^.*CN=//g') 40 | vdsm-tool register --engine-fqdn $ENGINE_FQDN \ 41 | --engine-https-port $ENGINE_HTTPS_PORT \ 42 | --check-fqdn false \ 43 | --node-name $MYNAME \ 44 | --node-address $MY_NODE_NAME \ 45 | --ssh-port $SSHPORT 46 | -------------------------------------------------------------------------------- /image-specifications/vdsc/scripts/vdsm-deploy.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=Simple service file to configure host after vdsm is running 3 | Wants=vdsmd.service 4 | After=vdsmd.service 5 | 6 | [Service] 7 | Type=oneshot 8 | ExecStart=/bin/sh /root/deploy.sh 9 | RemainAfterExit=yes 10 | 11 | [Install] 12 | WantedBy=multi-user.target 13 | -------------------------------------------------------------------------------- /os-manifests/configure_repo.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | if [ $# -ne 2 ]; then 4 | echo "USAGE: configure_img.sh [OLD_IMG_REPO] [NEW_IMG_REPO]" 5 | echo "NOTE: in case old_repo is wrong, the replacement does nothing" 6 | exit 1 7 | fi 8 | echo "configure_img.sh $1 $2" 9 | 10 | sed -ri 's/image: '${1}'/image: '${2}'/g' engine/engine-deployment.yaml vdsc/vdsc-deployment.yaml 11 | echo "" 12 | echo "" 13 | echo "Grepping images after modification:" 14 | echo "" 15 | grep -hr "image:" engine/* vdsc/* 16 | -------------------------------------------------------------------------------- /os-manifests/engine/engine-deployment.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: List 3 | items: 4 | - apiVersion: v1 5 | kind: Service 6 | metadata: 7 | name: ovirt-engine 8 | spec: 9 | ports: 10 | - name: ovirt-engine 11 | port: 443 12 | targetPort: 8701 13 | tls: 14 | termination: passthrough 15 | - name: ovirt-spice-proxy 16 | port: 3128 17 | targetPort: 3128 18 | - name: ovirt-engine-debug 19 | port: 8787 20 | targetPort: 8787 21 | selector: 22 | deploymentconfig: ovirt-engine 23 | type: ClusterIP 24 | 25 | - apiVersion: v1 26 | kind: Route 27 | metadata: 28 | name: ovirt-engine 29 | spec: 30 | to: 31 | kind: Service 32 | name: ovirt-engine 33 | port: 34 | targetPort: ovirt-engine 35 | tls: 36 | termination: passthrough 37 | wildcardPolicy: None 38 | 39 | - apiVersion: v1 40 | kind: Route 41 | metadata: 42 | name: ovirt-spice-proxy 43 | spec: 44 | to: 45 | kind: Service 46 | name: ovirt-engine 47 | port: 48 | targetPort: ovirt-spice-proxy 49 | wildcardPolicy: None 50 | 51 | - apiVersion: v1 52 | kind: PersistentVolumeClaim 53 | metadata: 54 | name: ovirt-db-claim 55 | spec: 56 | accessModes: 57 | - ReadWriteOnce 58 | resources: 59 | requests: 60 | storage: 10Gi 61 | 62 | - apiVersion: v1 63 | kind: PersistentVolumeClaim 64 | metadata: 65 | name: ovirt-engine-claim 66 | spec: 67 | accessModes: 68 | - ReadWriteOnce 69 | resources: 70 | requests: 71 | storage: 10Gi 72 | 73 | - apiVersion: v1 74 | kind: DeploymentConfig 75 | metadata: 76 | name: ovirt-engine 77 | spec: 78 | replicas: 1 79 | selector: 80 | deploymentconfig: ovirt-engine 81 | strategy: 82 | # We set the type of strategy to Recreate, which means that it will be scaled down prior to being scaled up 83 | type: Recreate 84 | recreateParams: 85 | timeoutSeconds: 1200 86 | paused: true 87 | template: 88 | metadata: 89 | labels: 90 | app: ovirt-engine 91 | deploymentconfig: ovirt-engine 92 | name: ovirt-engine 93 | spec: 94 | serviceAccountName: useroot 95 | containers: 96 | - image: {{ tag "engine-spice-proxy" }} 97 | name: spice-proxy 98 | imagePullPolicy: "IfNotPresent" 99 | ports: 100 | - containerPort: 3128 101 | protocol: TCP 102 | 103 | - image: {{ tag "engine-database" }} 104 | name: postgres 105 | imagePullPolicy: "IfNotPresent" 106 | ports: 107 | - containerPort: 5432 108 | protocol: TCP 109 | volumeMounts: 110 | - mountPath: /var/lib/postgresql/data 111 | name: pgdata 112 | env: 113 | - name: POSTGRESQL_USER 114 | value: engine 115 | - name: POSTGRESQL_PASSWORD 116 | value: engine 117 | - name: POSTGRESQL_DATABASE 118 | value: engine 119 | - name: POSTGRESQL_MAX_CONNECTIONS 120 | value: "150" 121 | 122 | - image: {{ tag "engine" }} 123 | name: ovirt-engine 124 | imagePullPolicy: "IfNotPresent" 125 | ports: 126 | - containerPort: 8700 127 | protocol: TCP 128 | - containerPort: 8701 129 | protocol: TCP 130 | - containerPort: 8787 131 | protocol: TCP 132 | volumeMounts: 133 | - mountPath: /etc/pki/ovirt-engine 134 | name: engine-data 135 | subPath: pki 136 | - mountPath: /var/lib/ovirt-engine/backups 137 | name: engine-data 138 | subPath: backups 139 | - mountPath: /usr/share/ovirt-engine/ui-plugins/ 140 | name: engine-data 141 | subPath: ui-plugins 142 | - mountPath: /etc/ovirt-engine/ui-plugins/ 143 | name: engine-data 144 | subPath: ui-plugins-etc 145 | livenessProbe: 146 | httpGet: 147 | path: /ovirt-engine/services/health 148 | port: 8701 149 | scheme: HTTPS 150 | initialDelaySeconds: 1200 151 | timeoutSeconds: 5 152 | periodSeconds: 60 153 | successThreshold: 1 154 | failureThreshold: 3 155 | readinessProbe: 156 | httpGet: 157 | path: /ovirt-engine/services/health 158 | port: 8701 159 | scheme: HTTPS 160 | initialDelaySeconds: 30 161 | timeoutSeconds: 5 162 | periodSeconds: 10 163 | successThreshold: 1 164 | failureThreshold: 3 165 | env: 166 | - name: POSTGRES_USER 167 | value: engine 168 | - name: POSTGRES_PASSWORD 169 | value: engine 170 | - name: POSTGRES_DB 171 | value: engine 172 | - name: POSTGRES_HOST 173 | value: localhost 174 | - name: POSTGRES_PORT 175 | value: "5432" 176 | - name: OVIRT_FQDN 177 | value: engine-ovirt.10.34.63.173.xip.io # Is there a way to get this from openshift? 178 | - name: OVIRT_PASSWORD 179 | value: engine 180 | - name: OVIRT_PKI_ORGANIZATION 181 | value: oVirt 182 | - name: SPICE_PROXY 183 | value: http://172.17.0.1:3128 # Is there a way to get this from openshift? 184 | - name: ENGINE_SSO_SERVICE_URL 185 | value: https://localhost:8701/ovirt-engine/sso 186 | 187 | volumes: 188 | - name: engine-data 189 | persistentVolumeClaim: 190 | claimName: ovirt-engine-claim 191 | - name: pgdata 192 | persistentVolumeClaim: 193 | claimName: ovirt-db-claim 194 | -------------------------------------------------------------------------------- /os-manifests/vdsc/vdsc-deployment.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: List 3 | items: 4 | 5 | # Technically a service is not required since we are exposing the required 6 | # container ports with hostPort directive but as for 7 | # https://github.com/kubernetes/kubernetes/issues/23920 8 | # this is a workaround to get the firewall properly configured 9 | - apiVersion: v1 10 | kind: Service 11 | metadata: 12 | name: vdsc-service 13 | spec: 14 | selector: 15 | name: vdsc-ds 16 | ports: 17 | - name: vdsc-syslog 18 | port: 514 19 | protocol: TCP 20 | targetPort: 514 21 | - name: vdsm-kube 22 | port: 54321 23 | protocol: TCP 24 | targetPort: 54321 25 | - name: vdsm-ssh 26 | port: 22222 27 | protocol: TCP 28 | targetPort: 22 29 | sessionAffinity: None 30 | type: ClusterIP 31 | 32 | - apiVersion: v1 33 | kind: PersistentVolumeClaim 34 | metadata: 35 | name: vdsc-claim 36 | spec: 37 | accessModes: 38 | - ReadWriteOnce 39 | resources: 40 | requests: 41 | storage: 10Gi 42 | 43 | - apiVersion: extensions/v1beta1 44 | kind: DaemonSet 45 | metadata: 46 | labels: 47 | name: vdsc-ds 48 | spec: 49 | paused: true 50 | template: 51 | metadata: 52 | labels: 53 | name: vdsc-template 54 | spec: 55 | restartPolicy: "Always" 56 | hostIPC: true 57 | serviceAccountName: privilegeduser 58 | containers: 59 | - image: {{ tag "vdsc-syslog" }} 60 | name: vdsc-syslog 61 | imagePullPolicy: "IfNotPresent" 62 | ports: 63 | - containerPort: 514 64 | protocol: TCP 65 | hostPort: 514 66 | 67 | - image: {{ tag "vdsc" }} 68 | name: vdsc 69 | ports: 70 | - containerPort: 54321 71 | protocol: TCP 72 | hostPort: 54321 73 | - containerPort: 22 74 | protocol: TCP 75 | hostPort: 22222 76 | imagePullPolicy: "IfNotPresent" 77 | securityContext: 78 | privileged: true 79 | volumeMounts: 80 | - name: sys-fs-cgroup 81 | mountPath: /sys/fs/cgroup 82 | readOnly: true 83 | - name: dev 84 | mountPath: /dev 85 | - name: boot 86 | mountPath: /boot 87 | - name: lib-modules 88 | mountPath: /lib/modules 89 | env: 90 | - name: MY_NODE_NAME 91 | valueFrom: 92 | fieldRef: 93 | fieldPath: spec.nodeName 94 | volumes: 95 | - name: sys-fs-cgroup 96 | hostPath: 97 | path: /sys/fs/cgroup 98 | - name: dev 99 | hostPath: 100 | path: /dev 101 | - name: boot 102 | hostPath: 103 | path: /boot 104 | - name: vdsc-persist-data 105 | persistentVolumeClaim: 106 | claimName: vdsc-claim 107 | - name: lib-modules 108 | hostPath: 109 | path: /lib/modules 110 | -------------------------------------------------------------------------------- /project.conf: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2017 Red Hat, Inc. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | 17 | # 18 | # This file contains the configuration of the project. The comments that 19 | # describe the values are followed by a commented out line that contains 20 | # the default value for the corresponding parameter. 21 | # 22 | 23 | # 24 | # The version of the project. 25 | # 26 | #version=master 27 | 28 | [images] 29 | 30 | # 31 | # The names of the images built by this project are constructed from a 32 | # prefix, a image name, and a project version. The image name is taken 33 | # from the directory that contains the Dockerfile for that image. The 34 | # version is taken from the above 'version' parameter. The prefix is 35 | # taken from this parameter. 36 | # 37 | #prefix=ovirt 38 | 39 | # 40 | # The address of the Docker registry where images should be pushed. By 41 | # default this empty, which means that images are stored in the local 42 | # docker storage. 43 | # 44 | # A local registry can be created with the following command: 45 | # 46 | # docker run -d -p 5000:5000 --restart=always --name registry registry:2 47 | # 48 | # Then, to use that registry, change this parameter as follows: 49 | # 50 | # registry=localhost:5000 51 | #registry= 52 | -------------------------------------------------------------------------------- /tools/src/ovc/build.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017 Red Hat, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package main 18 | 19 | // This tool builds all the images. 20 | 21 | import ( 22 | "fmt" 23 | 24 | "ovc/build" 25 | "ovc/log" 26 | ) 27 | 28 | func buildTool(project *build.Project) error { 29 | for _, image := range project.Images().List() { 30 | log.Info("Building image '%s'", image) 31 | err := image.Build() 32 | if err != nil { 33 | return fmt.Errorf("Failed to build image '%s'", image) 34 | } 35 | } 36 | 37 | return nil 38 | } 39 | -------------------------------------------------------------------------------- /tools/src/ovc/build/commands.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017 Red Hat, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package build 18 | 19 | // This file contains functions intended to simplify the execution and 20 | // evaluation of external commands. 21 | 22 | import ( 23 | "os/exec" 24 | "strings" 25 | 26 | "ovc/log" 27 | ) 28 | 29 | // RunCommand executes the given command and waits till it finishes. The 30 | // standard output and standard error of the command are redirected to 31 | // the standard output and standard error of the calling program. 32 | // 33 | func RunCommand(name string, args ...string) error { 34 | log.Debug("Running command '%s' with arguments '%s'", name, strings.Join(args, " ")) 35 | command := exec.Command(name, args...) 36 | command.Stdout = log.DebugWriter() 37 | command.Stderr = log.ErrorWriter() 38 | return command.Run() 39 | } 40 | 41 | // EvalCommand executes the given command, waits till it finishes and 42 | // returns the text that it writes to the standard output. If the 43 | // execution of the command fails it returns nil. 44 | // 45 | func EvalCommand(name string, args ...string) []byte { 46 | log.Debug("Evaluating command '%s' with arguments '%s'", name, strings.Join(args, " ")) 47 | bytes, err := exec.Command(name, args...).Output() 48 | if err != nil { 49 | return nil 50 | } 51 | return bytes 52 | } 53 | -------------------------------------------------------------------------------- /tools/src/ovc/build/dockerfiles.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017 Red Hat, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package build 18 | 19 | // This file contains types useful to load and manipulate docker files. 20 | 21 | import ( 22 | "io/ioutil" 23 | "regexp" 24 | "strings" 25 | ) 26 | 27 | // Instruction represents each of the instructions that form an 28 | // Dockerfile. 29 | // 30 | type DockerfileInstruction struct { 31 | // The name of the instruction. 32 | Name string 33 | 34 | // The arguments of the instruction. 35 | Args string 36 | } 37 | 38 | // Dockerfile conatins the information extracted from o docker file. 39 | // 40 | type Dockerfile struct { 41 | instructions []*DockerfileInstruction 42 | } 43 | 44 | // NewDockerfile creates a new empty docker file. 45 | // 46 | func NewDockerfile() *Dockerfile { 47 | return new(Dockerfile) 48 | } 49 | 50 | // Load loads a docker file and builds a list of structures containing 51 | // the instruction names and arguments. 52 | // 53 | func (d *Dockerfile) Load(path string) *Dockerfile { 54 | d.instructions = make([]*DockerfileInstruction, 0) 55 | bytes, err := ioutil.ReadFile(path) 56 | if err != nil { 57 | panic(err) 58 | } 59 | text := string(bytes) 60 | text = continueRe.ReplaceAllString(text, "") 61 | lines := strings.Split(text, "\n") 62 | for _, line := range lines { 63 | line = commentRe.ReplaceAllString(line, "") 64 | if line == "" { 65 | continue 66 | } 67 | groups := FindRegexpGroups(line, instructionRe) 68 | if groups == nil { 69 | continue 70 | } 71 | name := groups["name"] 72 | args := groups["args"] 73 | instruction := &DockerfileInstruction{ 74 | Name: name, 75 | Args: args, 76 | } 77 | d.instructions = append(d.instructions, instruction) 78 | } 79 | return d 80 | } 81 | 82 | // Instruction finds the first instruction within the given Dockerfile 83 | // that haves the given name. If there is no such instruction then it 84 | // returns nil. 85 | // 86 | func (d *Dockerfile) Instruction(name string) *DockerfileInstruction { 87 | for _, instruction := range d.instructions { 88 | if instruction.Name == name { 89 | return instruction 90 | } 91 | } 92 | return nil 93 | } 94 | 95 | // From finds the first FROM instruction within a Dockerfile. If that 96 | // instruction exists then it returns its arguments. If it doesn't exist 97 | // then it returns an empty string. 98 | // 99 | func (d *Dockerfile) From() string { 100 | from := d.Instruction("FROM") 101 | if from == nil { 102 | return "" 103 | } 104 | return from.Args 105 | } 106 | 107 | // Regular expressions used to process docker files. 108 | // 109 | var ( 110 | commentRe = regexp.MustCompile("\\s*#.*$") 111 | continueRe = regexp.MustCompile("\\\\\n") 112 | instructionRe = regexp.MustCompile("^\\s*(?P[a-zA-Z]+)\\s+(?P.*)$") 113 | ) 114 | -------------------------------------------------------------------------------- /tools/src/ovc/build/images.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017 Red Hat, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package build 18 | 19 | // This file contains types and function used to load and manipulate the 20 | // descriptions of images. 21 | 22 | import ( 23 | "fmt" 24 | "os" 25 | "path/filepath" 26 | "strings" 27 | ) 28 | 29 | // Image contains the description of an image, as well as methods to 30 | // build it. 31 | // 32 | type Image struct { 33 | project *Project 34 | name string 35 | tag string 36 | dockerfile *Dockerfile 37 | parent *Image 38 | } 39 | 40 | // NewImage creates a new empty image with the given name and belonging 41 | // to the given project. 42 | // 43 | func NewImage(project *Project, name string) *Image { 44 | i := new(Image) 45 | i.project = project 46 | i.name = name 47 | return i 48 | } 49 | 50 | // Load loads the details of the image, including the content of 51 | // the Dockerfile, if it exists. 52 | // 53 | func (i *Image) Load() error { 54 | // If the tag already has a value then the image has been loaded 55 | // before, so we don't need to do anything: 56 | if i.tag != "" { 57 | return nil 58 | } 59 | 60 | // Calculate the tag: 61 | i.tag = fmt.Sprintf( 62 | "%s/%s:%s", 63 | i.project.Images().Prefix(), 64 | i.name, 65 | i.project.Version(), 66 | ) 67 | registry := i.project.Images().Registry() 68 | if registry != "" { 69 | i.tag = fmt.Sprintf( 70 | "%s/%s", 71 | registry, 72 | i.tag, 73 | ) 74 | } 75 | 76 | // Process the templates: 77 | source := i.Directory() 78 | work := i.WorkingDirectory() 79 | err := ProcessTemplates(i.project, source, work) 80 | if err != nil { 81 | return err 82 | } 83 | 84 | // Check if there is a Dockerfile in the working directory, and 85 | // if it does then load it: 86 | dockerfilePath := filepath.Join(work, "Dockerfile") 87 | if _, err := os.Stat(dockerfilePath); err == nil { 88 | i.dockerfile = NewDockerfile() 89 | i.dockerfile.Load(dockerfilePath) 90 | } 91 | 92 | return nil 93 | } 94 | 95 | // Directory returns the absolute path of the directory that contains the 96 | // source files of the image. 97 | // 98 | func (i *Image) Directory() string { 99 | return filepath.Join(i.project.Images().Directory(), i.name) 100 | } 101 | 102 | // WorkingDirectory returns the absolute path of the work directory for the 103 | // image. 104 | // 105 | func (i *Image) WorkingDirectory() string { 106 | return filepath.Join(i.project.Images().WorkingDirectory(), i.name) 107 | } 108 | 109 | // Name returns the name of the image. 110 | // 111 | func (i *Image) Name() string { 112 | return i.name 113 | } 114 | 115 | // Tag returns the tag of the image. 116 | // 117 | func (i *Image) Tag() string { 118 | return i.tag 119 | } 120 | 121 | // Dockerfile returns the object that describes the Dockerfile used by 122 | // the image. 123 | // 124 | func (i *Image) Dockerfile() *Dockerfile { 125 | return i.dockerfile 126 | } 127 | 128 | // Parent returns the parent image. 129 | // 130 | func (i *Image) Parent() *Image { 131 | return i.parent 132 | } 133 | 134 | // String returns a string representation of the image. 135 | // 136 | func (i *Image) String() string { 137 | return i.Tag() 138 | } 139 | 140 | // Build builds the given image. 141 | // 142 | func (i *Image) Build() error { 143 | return RunCommand( 144 | "docker", 145 | "build", 146 | fmt.Sprintf("--tag=%s", i.Tag()), 147 | i.WorkingDirectory(), 148 | ) 149 | } 150 | 151 | // Saves the image to a tar file. 152 | // 153 | func (i *Image) Save() error { 154 | // Get the tag of the image and calculate a file name from it, 155 | // replacing all characters that aren't convenient in file names 156 | // (slashes and colons) with dashes: 157 | tag := i.Tag() 158 | replacer := strings.NewReplacer( 159 | "/", "-", 160 | ":", "-", 161 | ) 162 | path := replacer.Replace(tag) + ".tar" 163 | 164 | // Save the image to a tar file: 165 | err := RunCommand( 166 | "docker", 167 | "save", 168 | tag, 169 | fmt.Sprintf("--output=%s", path), 170 | ) 171 | if err != nil { 172 | return err 173 | } 174 | 175 | // Compress the tar file, using gzip: 176 | return RunCommand( 177 | "gzip", 178 | "--force", 179 | path, 180 | ) 181 | } 182 | 183 | // Push pushes the image to the docker registry. 184 | // 185 | func (i *Image) Push() error { 186 | return RunCommand( 187 | "docker", 188 | "push", 189 | i.Tag(), 190 | ) 191 | } 192 | 193 | // Remove removes the image from the local docker storage. 194 | // 195 | func (i *Image) Remove() error { 196 | return RunCommand( 197 | "docker", 198 | "rmi", 199 | i.Tag(), 200 | ) 201 | } 202 | -------------------------------------------------------------------------------- /tools/src/ovc/build/project.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017 Red Hat, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package build 18 | 19 | // This file contains types and functions used to load and manipulate 20 | // the project configuration file. 21 | 22 | import ( 23 | "container/list" 24 | "fmt" 25 | "io/ioutil" 26 | "os" 27 | "path/filepath" 28 | "regexp" 29 | 30 | "github.com/go-ini/ini" 31 | ) 32 | 33 | // Project contains the project configuration. 34 | // 35 | type Project struct { 36 | work string 37 | root string 38 | version string 39 | images *ProjectImages 40 | manifests *ProjectManifests 41 | } 42 | 43 | // ProjectImages contains the information about the images that are part 44 | // of the project. 45 | // 46 | type ProjectImages struct { 47 | project *Project 48 | path string 49 | prefix string 50 | registry string 51 | list []*Image 52 | index map[string]*Image 53 | } 54 | 55 | // ProjectManifests contains the information about the manifests that 56 | // are part of the project. 57 | // 58 | type ProjectManifests struct { 59 | project *Project 60 | path string 61 | } 62 | 63 | // WorkingDirectory returns the absolute path of the working directory 64 | // of the project. 65 | // 66 | func (p *Project) WorkingDirectory() string { 67 | return p.work 68 | } 69 | 70 | // Directory returns the the absolute path of the root directory of the 71 | // project. 72 | // 73 | func (p *Project) Directory() string { 74 | return p.root 75 | } 76 | 77 | // Version returns the version of the project. 78 | // 79 | func (p *Project) Version() string { 80 | return p.version 81 | } 82 | 83 | // Images returns the information about the images that are part of the 84 | // project. 85 | // 86 | func (p *Project) Images() *ProjectImages { 87 | return p.images 88 | } 89 | 90 | // Manifests returns the information about he OpenShift manifests that 91 | // are part of the project. 92 | // 93 | func (p *Project) Manifests() *ProjectManifests { 94 | return p.manifests 95 | } 96 | 97 | // WorkingDirectory returns the absolute path of the working directory for the 98 | // images of the project. 99 | // 100 | func (pi *ProjectImages) WorkingDirectory() string { 101 | return filepath.Join(pi.project.work, pi.path) 102 | } 103 | 104 | // Directory returns the absolute path of the directory containing the source 105 | // files of the image specifications. 106 | // 107 | func (pi *ProjectImages) Directory() string { 108 | return filepath.Join(pi.project.root, pi.path) 109 | } 110 | 111 | // Prefix returns the prefix that should be used to tag the images of 112 | // the project. 113 | // 114 | func (pi *ProjectImages) Prefix() string { 115 | return pi.prefix 116 | } 117 | 118 | // Registry returns the address of the Docker registry where images 119 | // should be pushed to. 120 | // 121 | func (pi *ProjectImages) Registry() string { 122 | return pi.registry 123 | } 124 | 125 | // List returns a slice containing the images that are part of the 126 | // project, sorted in the right build order. 127 | // 128 | func (pi *ProjectImages) List() []*Image { 129 | return pi.list 130 | } 131 | 132 | // Index returns a map containing the images that are part of the 133 | // project, indexed by name. 134 | // 135 | func (pi *ProjectImages) Index() map[string]*Image { 136 | return pi.index 137 | } 138 | 139 | // WorkingDirectory returns the absolute path of the working directory for the 140 | // OpenShift manifests of the project. 141 | // 142 | func (pm *ProjectManifests) WorkingDirectory() string { 143 | return filepath.Join(pm.project.work, pm.path) 144 | } 145 | 146 | // Directory returns the absolute path of the directory containing the 147 | // source files of the OpenShift manifests. 148 | // 149 | func (pm *ProjectManifests) Directory() string { 150 | return filepath.Join(pm.project.root, pm.path) 151 | } 152 | 153 | // Close releases all the resources used by the project, including the 154 | // temporary directory used to store the results of processsing 155 | // templates. Once the project is closed it can no longer be used. 156 | // 157 | func (p *Project) Close() error { 158 | return os.RemoveAll(p.work) 159 | } 160 | 161 | // Default project file name. 162 | // 163 | const defaultProjectFile = "project.conf" 164 | 165 | // Default global project configuration data. This will be loaded first, 166 | // and then the 'project.conf' file will be loaded on top of it, 167 | // overriding any value that is present. 168 | // 169 | const defaultProjectData = ` 170 | version=master 171 | 172 | [images] 173 | prefix=ovirt 174 | directory=image-specifications 175 | registry= 176 | 177 | [manifests] 178 | directory=os-manifests 179 | ` 180 | 181 | // LoadProject loads a project from the given path. If the path is empty 182 | // then it will load the project from the 'project.conf' file inside the 183 | // current working directory. 184 | // 185 | func LoadProject(path string) (project *Project, err error) { 186 | var file *ini.File 187 | var section *ini.Section 188 | 189 | // Create an initially empty project: 190 | project = new(Project) 191 | 192 | // Calculate the absolute path of the project: 193 | root, _ := filepath.Abs(filepath.Dir(path)) 194 | project.root = root 195 | 196 | // Create a temporary directory that will be used to store the 197 | // results of generating files from templates, and maybe other 198 | // temporary files. 199 | project.work, err = ioutil.TempDir("", "work") 200 | if err != nil { 201 | err = fmt.Errorf("Can't create temporary work directory: %s\n", err) 202 | return 203 | } 204 | 205 | // If the path is empty then use the current directory and the 206 | // default project file name: 207 | if path == "" { 208 | path, err = os.Getwd() 209 | if err != nil { 210 | return 211 | } 212 | path = filepath.Join(path, defaultProjectFile) 213 | } 214 | 215 | // Load the default project data: 216 | file = ini.Empty() 217 | err = file.Append([]byte(defaultProjectData)) 218 | if err != nil { 219 | return 220 | } 221 | 222 | // Load the project file: 223 | err = file.Append(path) 224 | if err != nil { 225 | return 226 | } 227 | 228 | // Copy the main parameters from the configuration to the 229 | // project object: 230 | section = file.Section("") 231 | project.version = section.Key("version").MustString("") 232 | 233 | // Load the images: 234 | err = loadImages(file, project) 235 | if err != nil { 236 | return 237 | } 238 | 239 | // Load the manifests: 240 | err = loadManifests(file, project) 241 | if err != nil { 242 | return 243 | } 244 | 245 | return 246 | } 247 | 248 | // Regular expression used to extract the name and version of an image 249 | // from the value of the FROM instruction of a Dockerfile. 250 | // 251 | var fromRe = regexp.MustCompile("^(?P.*)/(?P[^/]+):(?P[^:]+)$") 252 | 253 | // loadImages images scans the images directory, loads the descriptions 254 | // and stores them into the project. 255 | // 256 | // The images will have their parent resolved, but only if the parent is 257 | // also in the same images directory, otherwise it will be nil. 258 | // 259 | func loadImages(file *ini.File, project *Project) error { 260 | // Check that the 'images' section is available: 261 | section := file.Section("images") 262 | if section == nil { 263 | return fmt.Errorf("The project configuration doesn't contain the 'images' section\n") 264 | } 265 | 266 | // Load basic attributes: 267 | images := new(ProjectImages) 268 | project.images = images 269 | images.project = project 270 | images.path = section.Key("directory").MustString("") 271 | images.prefix = section.Key("prefix").MustString("") 272 | images.registry = section.Key("registry").MustString("") 273 | 274 | // The source files of images may be templates, and those 275 | // templates may refer to some properties of other images. In 276 | // particular the Dockerfile of one image may refer to its 277 | // parent using a template: 278 | // 279 | // FROM {{ tag "base" }} 280 | // 281 | // In order to support that we need first to do a basic loading 282 | // of the images, to have at least the name. After that we can 283 | // load the image details, which will process the templates. 284 | images.list = []*Image{} 285 | paths, err := filepath.Glob(filepath.Join(project.root, images.path, "*")) 286 | if err != nil { 287 | return err 288 | } 289 | for _, path := range paths { 290 | info, err := os.Stat(path) 291 | if err != nil { 292 | return err 293 | } 294 | if info.IsDir() { 295 | image := NewImage(project, filepath.Base(path)) 296 | if err != nil { 297 | return err 298 | } 299 | images.list = append(images.list, image) 300 | } 301 | } 302 | images.index = make(map[string]*Image) 303 | for _, image := range images.list { 304 | images.index[image.name] = image 305 | } 306 | 307 | // Now that we have the names of all the images, we can process 308 | // load the details of the images. 309 | for _, image := range images.list { 310 | image.Load() 311 | } 312 | 313 | // Resolve the references to parent images, using the FROM 314 | // instruction: 315 | for _, image := range project.images.list { 316 | from := image.Dockerfile().From() 317 | if from == "" { 318 | continue 319 | } 320 | groups := FindRegexpGroups(from, fromRe) 321 | if groups == nil { 322 | continue 323 | } 324 | prefix := groups["prefix"] 325 | if prefix != project.Images().Prefix() { 326 | continue 327 | } 328 | name := groups["name"] 329 | parent := project.images.index[name] 330 | if parent != nil { 331 | image.parent = parent 332 | } 333 | } 334 | 335 | // Sort the loaded images in build order: 336 | sortImages(project.images.list) 337 | 338 | return nil 339 | } 340 | 341 | // loadImage loads the details of the image, including the content of 342 | // the Dockerfile, if it exists. 343 | // 344 | func loadImage(image *Image) error { 345 | // Check if there is a Dockerfile in the directory, and if it 346 | // does then load it: 347 | path := filepath.Join(image.Directory(), "Dockerfile") 348 | if _, err := os.Stat(path); err == nil { 349 | image.dockerfile = NewDockerfile() 350 | image.dockerfile.Load(path) 351 | } 352 | 353 | return nil 354 | } 355 | 356 | 357 | // sortImages implements a topological sort of the images according to 358 | // their dependencies. If image A is the base for image B, then image A 359 | // is guaranteed to appear before imabe B in the sorted slice. this is 360 | // intended to be able to build images in the right order. 361 | // 362 | func sortImages(images []*Image) { 363 | index := 0 364 | visited := make(map[*Image]bool) 365 | visited[nil] = true 366 | pending := list.New() 367 | for _, image := range images { 368 | visited[image] = false 369 | pending.PushBack(image) 370 | } 371 | for pending.Len() > 0 { 372 | current := pending.Remove(pending.Front()).(*Image) 373 | parent := current.Parent() 374 | if visited[parent] { 375 | visited[current] = true 376 | images[index] = current 377 | index++ 378 | } else { 379 | pending.PushBack(parent) 380 | pending.PushBack(current) 381 | } 382 | } 383 | } 384 | 385 | // loadManifests images scans the OpenShift manifests directory, loads 386 | // the descriptions and stores them into the project. 387 | // 388 | func loadManifests(file *ini.File, project *Project) error { 389 | // Check that the 'manifests' section is available: 390 | section := file.Section("manifests") 391 | if section == nil { 392 | return fmt.Errorf("The project configuration doesn't contain the 'manifests' section\n") 393 | } 394 | 395 | // Create the manifests object, and get the directory: 396 | manifests := new(ProjectManifests) 397 | project.manifests = manifests 398 | manifests.project = project 399 | manifests.path = section.Key("directory").MustString("") 400 | 401 | // Process the templates: 402 | return ProcessTemplates( 403 | project, 404 | manifests.Directory(), 405 | manifests.WorkingDirectory(), 406 | ) 407 | } 408 | -------------------------------------------------------------------------------- /tools/src/ovc/build/re.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017 Red Hat, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | // This file contains functions useful when working with regular expressions. 18 | 19 | package build 20 | 21 | import ( 22 | "regexp" 23 | ) 24 | 25 | // FindRegexGroups checks if line matches the re regular expression. If 26 | // it does match, then it returns a map containing the names of the 27 | // groups as the keys and the text that matches each group as the 28 | // values. If it doesn't match, then it returns nil. 29 | // 30 | func FindRegexpGroups(line string, re *regexp.Regexp) map[string]string { 31 | groups := make(map[string]string) 32 | matches := re.FindStringSubmatch(line) 33 | if matches != nil { 34 | names := re.SubexpNames() 35 | for index, name := range names { 36 | groups[name] = matches[index] 37 | } 38 | } 39 | return groups 40 | } 41 | -------------------------------------------------------------------------------- /tools/src/ovc/build/templates.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017 Red Hat, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package build 18 | 19 | // This file contains functions intended to process templates. 20 | 21 | import ( 22 | "fmt" 23 | "os" 24 | "path/filepath" 25 | "text/template" 26 | 27 | "ovc/log" 28 | ) 29 | 30 | // Context contains the objects passed to templates when they are 31 | // evaluated. 32 | // 33 | type Context struct { 34 | project *Project 35 | } 36 | 37 | // ProcessTemplates scans all the files in the input directory, 38 | // processes them as templates, and writes the result to the output 39 | // directory. 40 | // 41 | func ProcessTemplates(project *Project, inDir string, outDir string) error { 42 | return filepath.Walk(inDir, func(inPath string, info os.FileInfo, err error) error { 43 | path, err := filepath.Rel(inDir, inPath) 44 | if err != nil { 45 | return err 46 | } 47 | outPath := filepath.Join(outDir, path) 48 | if info.IsDir() { 49 | return os.MkdirAll(outPath, info.Mode()) 50 | } 51 | return ProcessTemplate(project, inPath, outPath) 52 | }) 53 | } 54 | 55 | // ProcessTemplate loads the input file, processes it as a template, and 56 | // writes the result to the output file. 57 | // 58 | func ProcessTemplate(project *Project, in string, out string) error { 59 | // Prepare the context object used for template evaluation: 60 | ctx := new(Context) 61 | ctx.project = project 62 | 63 | // Create the template and register the functions: 64 | tmpl := template.New(filepath.Base(in)) 65 | tmpl.Funcs(template.FuncMap{ 66 | "tag": func(name string) (string, error) { 67 | return tagFunc(ctx, name) 68 | }, 69 | }) 70 | 71 | // Parse the template: 72 | log.Debug("Loading template from file '%s'", in) 73 | _, err := tmpl.ParseFiles(in) 74 | if err != nil { 75 | return err 76 | } 77 | 78 | // Create the file where the output of the template evaluation 79 | // will be written, and remember to close it: 80 | info, err := os.Stat(in) 81 | if err != nil { 82 | return err 83 | } 84 | log.Debug("Creating template result file '%s'", out) 85 | file, err := os.OpenFile(out, os.O_CREATE|os.O_WRONLY, info.Mode()) 86 | if err != nil { 87 | return err 88 | } 89 | defer file.Close() 90 | 91 | // Evaluate the template: 92 | return tmpl.Execute(file, ctx) 93 | } 94 | 95 | // tagFunc is a function intended to simplify writing templates that 96 | // need to use the complete tag of an image, including the address of 97 | // the registry. For example, a template for an OpenShift manifest that 98 | // needs to specify the name of an image can be written as follows: 99 | // 100 | // image: {{ tag "engine" }} 101 | // 102 | // With the default configuration that will be translated to this: 103 | // 104 | // image: ovirt/engine:master 105 | // 106 | func tagFunc(context *Context, name string) (tag string, err error) { 107 | image, present := context.project.Images().Index()[name] 108 | if !present { 109 | err = fmt.Errorf("Can't find image for name '%s'", name) 110 | return 111 | } 112 | tag = image.Tag() 113 | return 114 | } 115 | -------------------------------------------------------------------------------- /tools/src/ovc/clean.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017 Red Hat, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package main 18 | 19 | // This tool untas all the images created by the project, so that the 20 | // next build will create them again. 21 | 22 | import ( 23 | "fmt" 24 | 25 | "ovc/build" 26 | "ovc/log" 27 | ) 28 | 29 | func cleanTool(project *build.Project) error { 30 | // The list of images is always returned in build order, with 31 | // base images before the images that depend on them. In order 32 | // to remove them without issues we need to reverse that order, 33 | // so that base images are removed after the images that depend 34 | // on them. 35 | images := project.Images().List() 36 | for i := len(images) - 1; i >= 0; i-- { 37 | image := images[i] 38 | log.Info("Remove image '%s'", image) 39 | err := image.Remove() 40 | if err != nil { 41 | return fmt.Errorf("Failed to remove image '%s'", image) 42 | } 43 | } 44 | 45 | return nil 46 | } 47 | -------------------------------------------------------------------------------- /tools/src/ovc/deploy.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017 Red Hat, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package main 18 | 19 | // This tool deploys the application to the OpenShift cluster. 20 | 21 | import ( 22 | "fmt" 23 | "os" 24 | "path/filepath" 25 | "regexp" 26 | "strconv" 27 | "strings" 28 | 29 | "ovc/build" 30 | ) 31 | 32 | // The name of the project. 33 | // 34 | const ( 35 | projectName = "ovirt" 36 | projectTitle = "oVirt" 37 | ) 38 | 39 | // Names of the required service accounts. 40 | // 41 | const ( 42 | useRoot = "useroot" 43 | privilegedUser = "privilegeduser" 44 | ) 45 | 46 | func deployTool(project *build.Project) error { 47 | var err error 48 | 49 | // Check that the 'oc' tool is available and that it is the 50 | // right version: 51 | err = validateOc() 52 | if err != nil { 53 | return err 54 | } 55 | 56 | // Log in as system administrator: 57 | err = runOc( 58 | "login", 59 | "-u", 60 | "system:admin", 61 | ) 62 | if err != nil { 63 | return err 64 | } 65 | 66 | // Create the project: 67 | err = runOc( 68 | "new-project", 69 | projectName, 70 | "--description="+projectTitle, 71 | "--display-name="+projectTitle, 72 | ) 73 | if err != nil { 74 | return err 75 | } 76 | 77 | // Add administrator permissios to the 'developer' user account: 78 | err = runOc( 79 | "adm", 80 | "policy", 81 | "add-role-to-user", 82 | "admin", 83 | "developer", 84 | "-n", 85 | projectName, 86 | ) 87 | if err != nil { 88 | return err 89 | } 90 | 91 | // Create a service account that can use the root user: 92 | err = runOc( 93 | "create", 94 | "serviceaccount", 95 | useRoot, 96 | ) 97 | if err != nil { 98 | return err 99 | } 100 | err = runOc( 101 | "adm", 102 | "policy", 103 | "add-scc-to-user", 104 | "anyuid", 105 | "-z", 106 | useRoot, 107 | ) 108 | if err != nil { 109 | return err 110 | } 111 | 112 | // Create a service account that can has access to advanced host 113 | // privileges, for use inside the VSDC pod: 114 | err = runOc( 115 | "create", 116 | "serviceaccount", 117 | privilegedUser, 118 | ) 119 | if err != nil { 120 | return err 121 | } 122 | err = runOc( 123 | "adm", 124 | "policy", 125 | "add-scc-to-user", 126 | "privileged", 127 | "-z", 128 | privilegedUser, 129 | ) 130 | if err != nil { 131 | return err 132 | } 133 | 134 | // Create engine and VDSC deployments and add them to the 135 | // project: 136 | err = runOc( 137 | "create", 138 | "-f", 139 | project.Manifests().WorkingDirectory(), 140 | "-R", 141 | ) 142 | if err != nil { 143 | return err 144 | } 145 | 146 | // Change the host name for the engine deployment, according to 147 | // the host name that was assigned to the associated route, then 148 | // unpause it: 149 | engineHost, err := evalOc( 150 | "get", 151 | "routes", 152 | "ovirt-engine", 153 | "--output=jsonpath={.spec.host}", 154 | ) 155 | if err != nil { 156 | return err 157 | } 158 | spiceProxyHost, err := evalOc( 159 | "get", 160 | "routes", 161 | "ovirt-spice-proxy", 162 | "--output=jsonpath={.spec.host}", 163 | ) 164 | if err != nil { 165 | return err 166 | } 167 | err = runOc( 168 | "set", 169 | "env", 170 | "dc/ovirt-engine", 171 | "-c", 172 | "ovirt-engine", 173 | "OVIRT_FQDN="+engineHost, 174 | "SPICE_PROXY=http://"+spiceProxyHost+":3128", 175 | ) 176 | if err != nil { 177 | return err 178 | } 179 | err = runOc( 180 | "patch", 181 | "dc/ovirt-engine", 182 | "--patch", 183 | `{ 184 | "spec": { 185 | "paused": false 186 | } 187 | }`, 188 | ) 189 | if err != nil { 190 | return err 191 | } 192 | 193 | return nil 194 | } 195 | 196 | // Regular expression used to extract the version of the 'oc' tool from 197 | // the first line of output of the 'oc version' command. The typical 198 | // output from that command is something like this: 199 | // 200 | // oc v1.5.0+031cbe4 201 | // kubernetes v1.5.2+43a9be4 202 | // features: Basic-Auth GSSAPI Kerberos SPNEGO 203 | // 204 | // This regular expression captures the major, minor and micro version 205 | // numbers of the first line. 206 | // 207 | var ocVersionRe = regexp.MustCompile( 208 | "^oc\\s+v(?P\\d+)\\.(?P\\d+)\\.(?P\\d+).*$", 209 | ) 210 | 211 | // Minimum supported 'oc' version. 212 | // 213 | const ( 214 | minOcMajor = 1 215 | minOcMinor = 5 216 | ) 217 | 218 | // ValidateOc checks that the OpenShift 'oc' tool is installed and that 219 | // it is the right version. If the validation fails it prints an error 220 | // message and aborts the application. 221 | // 222 | func validateOc() error { 223 | // Get the value of the PATH environment variable: 224 | path, present := os.LookupEnv("PATH") 225 | if !present { 226 | return fmt.Errorf( 227 | "The PATH environment variable isn't set, can't locate the 'oc' tool'", 228 | ) 229 | } 230 | 231 | // Check that the 'oc' tools is available in one of the 232 | // directories specified in the PATH environment variable: 233 | dirs := strings.Split(path, string(os.PathListSeparator)) 234 | exec := "" 235 | for _, dir := range dirs { 236 | file := filepath.Join(dir, "oc") 237 | info, err := os.Lstat(file) 238 | if err != nil || info.IsDir() { 239 | continue 240 | } 241 | if info.Mode()|0111 != 0 { 242 | exec = file 243 | break 244 | } 245 | } 246 | if exec == "" { 247 | return fmt.Errorf( 248 | "Can't find the 'oc' tool in the path", 249 | ) 250 | } 251 | 252 | // Run the tool to extract the version number, and check that it 253 | // is what we expect: 254 | out := build.EvalCommand("oc", "version") 255 | if out == nil { 256 | return fmt.Errorf("Failed to run 'oc version'") 257 | } 258 | lines := strings.Split(string(out), "\n") 259 | if len(lines) < 1 { 260 | return fmt.Errorf("Output of 'oc version' is empty") 261 | } 262 | line := lines[0] 263 | groups := build.FindRegexpGroups(lines[0], ocVersionRe) 264 | if len(groups) <= 1 { 265 | return fmt.Errorf( 266 | "The 'oc' version line '%s' doesn't match the expected regular expression", 267 | line, 268 | ) 269 | } 270 | major, _ := strconv.Atoi(groups["major"]) 271 | minor, _ := strconv.Atoi(groups["minor"]) 272 | micro, _ := strconv.Atoi(groups["micro"]) 273 | if major < minOcMajor || (major == minOcMajor && minor < minOcMinor) { 274 | 275 | return fmt.Errorf( 276 | "Version %d.%d.%d of 'oc' isn't supported, should be at least %d.%d", 277 | major, minor, micro, 278 | minOcMajor, minOcMinor, 279 | ) 280 | } 281 | 282 | return nil 283 | } 284 | 285 | func runOc(args ...string) error { 286 | err := build.RunCommand("oc", args...) 287 | if err != nil { 288 | return fmt.Errorf("The 'oc' command failed: %s", err) 289 | } 290 | return nil 291 | } 292 | 293 | func evalOc(args ...string) (result string, err error) { 294 | bytes := build.EvalCommand("oc", args...) 295 | if bytes == nil { 296 | err = fmt.Errorf("The 'oc' command failed") 297 | } 298 | result = string(bytes) 299 | return 300 | } 301 | -------------------------------------------------------------------------------- /tools/src/ovc/glide.lock: -------------------------------------------------------------------------------- 1 | hash: 4de13599e262976dc3aaf850a3e41cc81c09f1a4bc2796295cdbc3011d4cf1e9 2 | updated: 2017-06-06T14:04:26.429728957+02:00 3 | imports: 4 | - name: github.com/go-ini/ini 5 | version: d3de07a94d22b4a0972deb4b96d790c2c0ce8333 6 | testImports: [] 7 | -------------------------------------------------------------------------------- /tools/src/ovc/glide.yaml: -------------------------------------------------------------------------------- 1 | package: ovc 2 | import: 3 | - package: github.com/go-ini/ini 4 | version: v1.28.0 5 | -------------------------------------------------------------------------------- /tools/src/ovc/log/log.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017 Red Hat, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | // This file contains functions useful for generating log files. 18 | 19 | package log 20 | 21 | import ( 22 | "bytes" 23 | "fmt" 24 | "io" 25 | "os" 26 | "path/filepath" 27 | ) 28 | 29 | // The log file. 30 | // 31 | var path string 32 | var file *os.File 33 | 34 | // The writers for the different levels. 35 | // 36 | var errorWriter io.Writer 37 | var infoWriter io.Writer 38 | var debugWriter io.Writer 39 | 40 | // prefixWriter implements a writer that adds a prefix to each line. 41 | // 42 | type prefixWriter struct { 43 | prefix string 44 | stream io.Writer 45 | start bool 46 | } 47 | 48 | // newPrefixWriter creates a new prefix writer that adds the given 49 | // prefix and writes the modified lines to the given stream. 50 | // 51 | func newPrefixWriter(stream io.Writer, prefix string) io.Writer { 52 | p := new(prefixWriter) 53 | p.prefix = prefix 54 | p.stream = stream 55 | p.start = true 56 | return p 57 | } 58 | 59 | func (p *prefixWriter) Write(data []byte) (count int, err error) { 60 | buffer := new(bytes.Buffer) 61 | buffer.Grow(len(data)) 62 | for _, char := range data { 63 | if p.start { 64 | buffer.WriteString(p.prefix) 65 | p.start = false 66 | } 67 | buffer.WriteByte(char) 68 | if char == 10 { 69 | p.start = true 70 | } 71 | } 72 | count = len(data) 73 | _, err = p.stream.Write(buffer.Bytes()) 74 | return 75 | } 76 | 77 | // newLogWriter creates a log writer that will write to the given file 78 | // and console. Each line will have the prefix added, in the given 79 | // color. The file and the console can be nil. 80 | // 81 | func newLogWriter(file, console io.Writer, prefix, color string) io.Writer { 82 | writers := make([]io.Writer, 0) 83 | if file != nil { 84 | plain := fmt.Sprintf("[%s] ", prefix) 85 | file = newPrefixWriter(file, plain) 86 | writers = append(writers, file) 87 | } 88 | if console != nil { 89 | colored := fmt.Sprintf("\033[%sm[%s]\033[m ", color, prefix) 90 | console = newPrefixWriter(console, colored) 91 | writers = append(writers, console) 92 | } 93 | return io.MultiWriter(writers...) 94 | } 95 | 96 | // Open creates a log file with the given name and the .log extension, 97 | // and configures the log to write to it. 98 | // 99 | func Open(name string) error { 100 | var err error 101 | 102 | path, err = filepath.Abs(name + ".log") 103 | if err != nil { 104 | return err 105 | } 106 | file, err = os.OpenFile(path, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0664) 107 | if err != nil { 108 | return err 109 | } 110 | errorWriter = newLogWriter(file, os.Stderr, "ERROR", "0;31") 111 | infoWriter = newLogWriter(file, os.Stdout, "INFO", "0;32") 112 | debugWriter = newLogWriter(file, nil, "DEBUG", "0;34") 113 | return nil 114 | } 115 | 116 | // Close closes the log file. 117 | // 118 | func Close() error { 119 | return file.Close() 120 | } 121 | 122 | // Path the returns the path of the log file. 123 | // 124 | func Path() string { 125 | return path 126 | } 127 | 128 | // Info sends an informative message to the log file and to the standard 129 | // ouptut of the process. 130 | // 131 | func Info(format string, args ...interface{}) { 132 | write(infoWriter, format, args...) 133 | } 134 | 135 | // Debug sends a debug message to the log file. 136 | // 137 | func Debug(format string, args ...interface{}) { 138 | write(debugWriter, format, args...) 139 | } 140 | 141 | // Error sends an error message to the log file and to the standard 142 | // error stream of the process. 143 | // 144 | func Error(format string, args ...interface{}) { 145 | write(errorWriter, format, args...) 146 | } 147 | 148 | func write(writer io.Writer, format string, args ...interface{}) { 149 | message := fmt.Sprintf(format, args...) 150 | writer.Write([]byte(message)) 151 | writer.Write([]byte("\n")) 152 | } 153 | 154 | // InfoWriter returns the writer that writes informative messages to the 155 | // log file and to the standard output of the process. 156 | // 157 | func InfoWriter() io.Writer { 158 | return infoWriter 159 | } 160 | 161 | // DebugWriter returns the writer that writes debug messages to the log 162 | // file. 163 | // 164 | func DebugWriter() io.Writer { 165 | return debugWriter 166 | } 167 | 168 | // ErrorWriter returns the writer that writes error messages to the log 169 | // file and to the standard error stream of the process. 170 | // file. 171 | // 172 | func ErrorWriter() io.Writer { 173 | return errorWriter 174 | } 175 | -------------------------------------------------------------------------------- /tools/src/ovc/main.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017 Red Hat, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | // This is used to embed the project configuration into the binary of the tool, 18 | // so that during run-time there is no need to have both the binary and the 19 | // configuration files. 20 | // 21 | //go:generate go run scripts/embed.go -directory ../../.. -output tools/src/ovc/embedded.go project.conf image-specifications os-manifests 22 | 23 | package main 24 | 25 | // This tool loads and builds all the images. 26 | 27 | import ( 28 | "archive/tar" 29 | "bytes" 30 | "compress/gzip" 31 | "fmt" 32 | "io" 33 | "io/ioutil" 34 | "os" 35 | "path/filepath" 36 | 37 | "ovc/build" 38 | "ovc/log" 39 | ) 40 | 41 | // ToolFunc is the type of functions that implement tools. 42 | // 43 | type ToolFunc func(project *build.Project) error 44 | 45 | // This index contains the mapping from names to tool functions. 46 | // 47 | var tools = map[string]ToolFunc{ 48 | "build": buildTool, 49 | "clean": cleanTool, 50 | "deploy": deployTool, 51 | "push": pushTool, 52 | "save": saveTool, 53 | } 54 | 55 | // The name of the project file. 56 | // 57 | const conf = "project.conf" 58 | 59 | func main() { 60 | // Get the name of the tool: 61 | if len(os.Args) < 2 { 62 | fmt.Fprintf(os.Stderr, "Usage: %s TOOL [ARGS...]\n", filepath.Base(os.Args[0])) 63 | os.Exit(1) 64 | } 65 | name := os.Args[1] 66 | 67 | // Find the function that corresponds to the tool name: 68 | tool := tools[name] 69 | if tool == nil { 70 | fmt.Fprintf(os.Stderr, "Can't find tool named '%s'.\n", name) 71 | os.Exit(1) 72 | } 73 | 74 | // Run the tool inside a different function, so that we can take 75 | // advantage of the 'defer' mechanism: 76 | os.Exit(run(name, tool)) 77 | } 78 | 79 | func run(name string, tool ToolFunc) int { 80 | // Open the log: 81 | log.Open(name) 82 | log.Info("Log file is '%s'", log.Path()) 83 | defer log.Close() 84 | 85 | // Check if the project file exists. If doesn't exist then we 86 | // need extract it, together with the rest of the source files 87 | // of the project, from the embedded data. 88 | file, _ := filepath.Abs(conf) 89 | if _, err := os.Stat(file); os.IsNotExist(err) { 90 | log.Info("Extracting project") 91 | tmp, err := ioutil.TempDir("", "project") 92 | if err != nil { 93 | log.Error("Can't create temporary directory for project: %s", err) 94 | os.Exit(1) 95 | } 96 | defer os.RemoveAll(tmp) 97 | err = extractData(embedded, tmp) 98 | if err != nil { 99 | log.Error("Can't extract project: %s", err) 100 | os.Exit(1) 101 | } 102 | file = filepath.Join(tmp, conf) 103 | } 104 | 105 | // Load the project: 106 | log.Info("Loading project file '%s'", file) 107 | project, err := build.LoadProject(file) 108 | if err != nil { 109 | log.Error("%s", err) 110 | return 1 111 | } 112 | defer project.Close() 113 | 114 | // Call the tool function: 115 | log.Debug("Running tool '%s'", name) 116 | err = tool(project) 117 | if err != nil { 118 | log.Error("%s", err) 119 | log.Error("Tool failed, check log file '%s' for details", log.Path()) 120 | return 1 121 | } else { 122 | log.Info("Tool finished successfully") 123 | return 0 124 | } 125 | } 126 | 127 | func extractData(data []byte, dir string) error { 128 | // Open the data archive: 129 | buffer := bytes.NewReader(data) 130 | expand, err := gzip.NewReader(buffer) 131 | if err != nil { 132 | return err 133 | } 134 | archive := tar.NewReader(expand) 135 | 136 | // Iterate through the entries of the archive and extract them 137 | // to the output directory: 138 | for { 139 | header, err := archive.Next() 140 | if err == io.EOF { 141 | break 142 | } 143 | if err != nil { 144 | return err 145 | } 146 | switch header.Typeflag { 147 | case tar.TypeReg: 148 | err = extractFile(archive, header, dir) 149 | case tar.TypeDir: 150 | err = extractDir(archive, header, dir) 151 | default: 152 | err = nil 153 | } 154 | if err != nil { 155 | return err 156 | } 157 | } 158 | 159 | return nil 160 | } 161 | 162 | func extractFile(archive *tar.Reader, header *tar.Header, dir string) error { 163 | // Create the file: 164 | path := filepath.Join(dir, header.Name) 165 | info := header.FileInfo() 166 | log.Debug("Extracting file '%s' to '%s'", header.Name, path) 167 | file, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, info.Mode().Perm()) 168 | if err != nil { 169 | return err 170 | } 171 | defer file.Close() 172 | 173 | // Copy the contents: 174 | _, err = io.Copy(file, archive) 175 | return err 176 | } 177 | 178 | func extractDir(archive *tar.Reader, header *tar.Header, dir string) error { 179 | path := filepath.Join(dir, header.Name) 180 | info := header.FileInfo() 181 | log.Debug("Extracting directory '%s' to '%s'", header.Name, path) 182 | return os.Mkdir(path, info.Mode().Perm()) 183 | } 184 | -------------------------------------------------------------------------------- /tools/src/ovc/push.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017 Red Hat, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package main 18 | 19 | // This tool pushes the image to the docker registry. 20 | 21 | import ( 22 | "fmt" 23 | 24 | "ovc/build" 25 | "ovc/log" 26 | ) 27 | 28 | func pushTool(project *build.Project) error { 29 | for _, image := range project.Images().List() { 30 | log.Info("Pushing image '%s'", image) 31 | err := image.Push() 32 | if err != nil { 33 | return fmt.Errorf("Failed to push image '%s': %s", image, err) 34 | } 35 | } 36 | 37 | return nil 38 | } 39 | -------------------------------------------------------------------------------- /tools/src/ovc/save.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017 Red Hat, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package main 18 | 19 | // This tool saves the images to tar files. 20 | 21 | import ( 22 | "fmt" 23 | 24 | "ovc/build" 25 | "ovc/log" 26 | ) 27 | 28 | func saveTool(project *build.Project) error { 29 | for _, image := range project.Images().List() { 30 | log.Info("Saving image '%s'", image) 31 | err := image.Save() 32 | if err != nil { 33 | return fmt.Errorf("Failed to save image '%s': %s", image, err) 34 | } 35 | } 36 | 37 | return nil 38 | } 39 | -------------------------------------------------------------------------------- /tools/src/ovc/scripts/embed.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017 Red Hat, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package main 18 | 19 | // This file is intended to be used as an script. It takes the files 20 | // given in the command line, creates a compresses tarball, and 21 | // generates a Go source file that contains a data variable with the 22 | // contents of that tarball. For example, to following command line will 23 | // generate an embedded.go file that contains the the project.conf file 24 | // and os-manifests directory: 25 | // 26 | // go run embed.go -output embedded.go project.conf os-manifests 27 | // 28 | // The generated embedded.go file can then be added to the project, and 29 | // used to extract the embedded data during run-time. 30 | 31 | import ( 32 | "archive/tar" 33 | "bytes" 34 | "compress/gzip" 35 | "flag" 36 | "fmt" 37 | "io" 38 | "log" 39 | "os" 40 | "path/filepath" 41 | ) 42 | 43 | func main() { 44 | // Option for the directory where the script should change to before 45 | // doing anything else: 46 | var directoryFlag string 47 | flag.StringVar( 48 | &directoryFlag, 49 | "directory", 50 | "", 51 | "change to `directory` before doing anything else", 52 | ) 53 | 54 | // Option for the name of the output file: 55 | var outputFlag string 56 | flag.StringVar( 57 | &outputFlag, 58 | "output", 59 | "embedded.go", 60 | "name of the output `file`", 61 | ) 62 | 63 | // Prepare the usage message: 64 | flag.Usage = func() { 65 | fmt.Fprintf( 66 | os.Stderr, 67 | "Usage: %s [OPTIONS] FILE ...\n", 68 | filepath.Base(os.Args[0]), 69 | ) 70 | flag.PrintDefaults() 71 | } 72 | 73 | // Parse the command line: 74 | flag.Parse() 75 | 76 | // Check that there is at least one file to add: 77 | paths := flag.Args() 78 | if len(paths) == 0 { 79 | flag.Usage() 80 | os.Exit(1) 81 | } 82 | 83 | // Change directory: 84 | if directoryFlag != "" { 85 | err := os.Chdir(directoryFlag) 86 | if err != nil { 87 | fmt.Fprintf( 88 | os.Stderr, 89 | "Can't change to directory '%s': %s\n", 90 | directoryFlag, 91 | err, 92 | ) 93 | os.Exit(1) 94 | } 95 | } 96 | 97 | // Create a tar archive writer that will compress and write the 98 | // result to an in-memory buffer: 99 | buffer := new(bytes.Buffer) 100 | compress := gzip.NewWriter(buffer) 101 | archive := tar.NewWriter(compress) 102 | 103 | // Add paths to the tar archive: 104 | for _, path := range paths { 105 | addTree(archive, path) 106 | } 107 | 108 | // Close the tarball and the gzip stream: 109 | if err := archive.Close(); err != nil { 110 | log.Fatalln(err) 111 | } 112 | if err := compress.Close(); err != nil { 113 | log.Fatalln(err) 114 | } 115 | 116 | // Create the output file: 117 | outputFile, err := os.Create(outputFlag) 118 | if err != nil { 119 | fmt.Fprintf( 120 | os.Stderr, 121 | "Can't create output file '%s': %s\n", 122 | outputFlag, 123 | err, 124 | ) 125 | os.Exit(1) 126 | } 127 | 128 | // Generate the Go source code that contains the compressed 129 | // tarball: 130 | fmt.Fprintf(outputFile, "package main\n") 131 | fmt.Fprintf(outputFile, "\n") 132 | fmt.Fprintf(outputFile, "var embedded = []byte{\n") 133 | for _, datum := range buffer.Bytes() { 134 | fmt.Fprintf(outputFile, "\t0x%02x,\n", datum) 135 | } 136 | fmt.Fprintf(outputFile, "}\n") 137 | 138 | // Close the output file: 139 | outputFile.Close() 140 | } 141 | 142 | func addTree(archive *tar.Writer, base string) error { 143 | return filepath.Walk(base, func(path string, info os.FileInfo, err error) error { 144 | // Stop inmediately if something fails when trying to 145 | // walk the directory: 146 | if err != nil { 147 | return err 148 | } 149 | 150 | // Add an entry to the tarball: 151 | switch { 152 | case info.Mode().IsRegular(): 153 | return addFile(archive, path, info) 154 | case info.Mode().IsDir(): 155 | return addDir(archive, path, info) 156 | default: 157 | return nil 158 | } 159 | }) 160 | } 161 | 162 | func addFile(archive *tar.Writer, path string, info os.FileInfo) error { 163 | // Add the header: 164 | header, err := tar.FileInfoHeader(info, "") 165 | if err != nil { 166 | return err 167 | } 168 | header.Name = path 169 | err = archive.WriteHeader(header) 170 | if err != nil { 171 | return err 172 | } 173 | 174 | // Add the content: 175 | file, err := os.Open(path) 176 | if err != nil { 177 | return err 178 | } 179 | defer file.Close() 180 | _, err = io.Copy(archive, file) 181 | return err 182 | } 183 | 184 | func addDir(archive *tar.Writer, path string, info os.FileInfo) error { 185 | header, err := tar.FileInfoHeader(info, "") 186 | if err != nil { 187 | return err 188 | } 189 | header.Name = path + "/" 190 | return archive.WriteHeader(header) 191 | } 192 | --------------------------------------------------------------------------------