blob: 822d398584474aa3ef7c5fec9b1827788f4919ff [file] [log] [blame]
Richard Felkl2e9e5452017-10-16 09:52:10 +02001/**
2 *
Richard Felkl859f4dd2018-01-04 23:03:27 +01003 * Build mirror image pipeline
Richard Felkl2e9e5452017-10-16 09:52:10 +02004 *
5 * Expected parameters:
Richard Felkl859f4dd2018-01-04 23:03:27 +01006 * CLUSTER_MODEL - An URL to the Reclass model for the mirror VM.
Richard Felkl0a9b5f62018-01-16 10:57:31 +01007 * CLUSTER_MODEL_REF - Branch or tag to use for cluster model
Richard Felkl859f4dd2018-01-04 23:03:27 +01008 * CLUSTER_NAME - Cluster name used in the above model.
9 * IMAGE_NAME - Name of the result image.
10 * OS_CREDENTIALS_ID - ID of credentials for OpenStack API stored in Jenkins.
11 * OS_PROJECT - Project in OpenStack under the VM will be spawned.
12 * OS_URL - Keystone auth endpoint of the OpenStack.
13 * OS_VERSION - OpenStack version
14 * SCRIPTS_REF - ref on the github to get the scripts from.
15 * SALT_MASTER_CREDENTIALS - ID of credentials to be used to connect to the Salt API of the VM
16 * UPLOAD_URL - URL of an WebDAV used to upload the image after creating.
17 * VM_AVAILABILITY_ZONE - Availability zone in OpenStack in the VM will be spawned.
18 * VM_CONNECT_RETRIES - Number of retries for SSH connection to the VM after it’s spawned after 8 minutes.
19 * VM_CONNECT_DELAY - Delay between connect retries above.
20 * VM_FLAVOR - Flavor to be used for VM in OpenStack.
21 * VM_FLOATING_IP_POOL - Floating IP pool to be used to assign floating IP to the VM.
22 * VM_IMAGE - Name of the image to be used for VM in OpenStack.
23 * VM_IP - Static IP that is assigned to the VM which belongs to the network used.
24 * VM_IP_RETRIES - Number of retries between tries to assign the floating IP to the VM.
25 * VM_IP_DELAY - Delay between floating IP assign retries above.
26 * VM_NETWORK_ID - ID of the network that VM connects to.
27 *
Richard Felkl2e9e5452017-10-16 09:52:10 +020028 */
29
30// Load shared libs
31def salt = new com.mirantis.mk.Salt()
32def common = new com.mirantis.mk.Common()
33def python = new com.mirantis.mk.Python()
34def openstack = new com.mirantis.mk.Openstack()
Richard Felkl2e9e5452017-10-16 09:52:10 +020035def date = new Date()
36def dateTime = date.format("ddMMyyyy-HHmmss")
Jakub Josef88aaf832018-01-18 16:18:28 +010037def venvPepper = ""
Richard Felkl2e9e5452017-10-16 09:52:10 +020038def privateKey = ""
39def floatingIP = ""
40def openstackServer = ""
41def rcFile = ""
42def openstackEnv = ""
43def serverStatus = ""
Richard Felkl802e4462017-12-06 10:08:05 +010044def uploadImageStatus = ""
45def uploadMd5Status = ""
Richard Felkl2e9e5452017-10-16 09:52:10 +020046
47def retry(int times = 5, int delay = 0, Closure body) {
48 int retries = 0
49 def exceptions = []
50 while(retries++ < times) {
51 try {
52 return body.call()
53 } catch(e) {
54 sleep(delay)
55 }
56 }
57 currentBuild.result = "FAILURE"
58 throw new Exception("Failed after $times retries")
59}
60
Richard Felkl994887c2018-01-11 17:13:59 +010061timeout(time: 12, unit: 'HOURS') {
62 node("python&&disk-xl") {
63 try {
64 def workspace = common.getWorkspace()
Richard Felkl994887c2018-01-11 17:13:59 +010065 openstackEnv = String.format("%s/venv", workspace)
Jakub Josef88aaf832018-01-18 16:18:28 +010066 venvPepper = String.format("%s/venvPepper", workspace)
67 rcFile = openstack.createOpenstackEnv(openstackEnv, OS_URL, OS_CREDENTIALS_ID, OS_PROJECT, "default", "", "default", "2", "")
Richard Felkl994887c2018-01-11 17:13:59 +010068 def openstackVersion = OS_VERSION
Richard Felkl2e9e5452017-10-16 09:52:10 +020069
Richard Felkl994887c2018-01-11 17:13:59 +010070 VM_IP_DELAY = VM_IP_DELAY as Integer
71 VM_IP_RETRIES = VM_IP_RETRIES as Integer
72 VM_CONNECT_DELAY = VM_CONNECT_DELAY as Integer
73 VM_CONNECT_RETRIES = VM_CONNECT_RETRIES as Integer
Richard Felkl2e9e5452017-10-16 09:52:10 +020074
Richard Felkl994887c2018-01-11 17:13:59 +010075 stage("Get templates"){
Richard Felkl2e9e5452017-10-16 09:52:10 +020076
Richard Felkl994887c2018-01-11 17:13:59 +010077 if (!fileExists("${workspace}/tmp")) {
78 sh "mkdir -p ${workspace}/tmp"
79 }
80
81 sh "wget https://raw.githubusercontent.com/Mirantis/mcp-common-scripts/${SCRIPTS_REF}/mirror-image/salt-bootstrap.sh"
82 openstack.setupOpenstackVirtualenv(openstackEnv, openstackVersion)
Richard Felkl2e9e5452017-10-16 09:52:10 +020083 }
84
Richard Felkl994887c2018-01-11 17:13:59 +010085 stage("Spawn Instance"){
86 privateKey = openstack.runOpenstackCommand("openstack keypair create mcp-offline-keypair-${dateTime}", rcFile, openstackEnv)
Richard Felkl2e9e5452017-10-16 09:52:10 +020087
Richard Felkl994887c2018-01-11 17:13:59 +010088 common.infoMsg(privateKey)
89 sh "echo '${privateKey}' > id_rsa;chmod 600 id_rsa"
Richard Felkl2e9e5452017-10-16 09:52:10 +020090
Richard Felkl994887c2018-01-11 17:13:59 +010091 floatingIP = openstack.runOpenstackCommand("openstack ip floating create --format value -c floating_ip_address ${VM_FLOATING_IP_POOL}", rcFile, openstackEnv)
Richard Felkl2e9e5452017-10-16 09:52:10 +020092
Richard Felkl0a9b5f62018-01-16 10:57:31 +010093 withEnv(["CLUSTER_NAME=${CLUSTER_NAME}", "CLUSTER_MODEL=${CLUSTER_MODEL}", "CLUSTER_MODEL_REF=${CLUSTER_MODEL_REF}", "MCP_VERSION=${MCP_VERSION}"]) {
Richard Felkl994887c2018-01-11 17:13:59 +010094 sh "envsubst < salt-bootstrap.sh > salt-bootstrap.sh.temp;mv salt-bootstrap.sh.temp salt-bootstrap.sh; cat salt-bootstrap.sh"
95 }
Richard Felkl2e9e5452017-10-16 09:52:10 +020096
Richard Felkl994887c2018-01-11 17:13:59 +010097 openstackServer = openstack.runOpenstackCommand("openstack server create --key-name mcp-offline-keypair-${dateTime} --availability-zone ${VM_AVAILABILITY_ZONE} --image ${VM_IMAGE} --flavor ${VM_FLAVOR} --nic net-id=${VM_NETWORK_ID},v4-fixed-ip=${VM_IP} --user-data salt-bootstrap.sh mcp-offline-mirror-${dateTime}", rcFile, openstackEnv)
98 sleep(60)
99
100 retry(VM_IP_RETRIES, VM_IP_DELAY){
101 openstack.runOpenstackCommand("openstack ip floating add ${floatingIP} mcp-offline-mirror-${dateTime}", rcFile, openstackEnv)
102 }
103
104 sleep(500)
105
106 retry(VM_CONNECT_RETRIES, VM_CONNECT_DELAY){
107 sh "scp -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -i id_rsa root@${floatingIP}:/srv/initComplete ./"
108 }
109
110 python.setupPepperVirtualenv(venvPepper, "http://${floatingIP}:6969", SALT_MASTER_CREDENTIALS)
111 }
112 stage("Prepare instance"){
113 salt.runSaltProcessStep(venvPepper, '*apt*', 'saltutil.refresh_pillar', [], null, true)
114 salt.runSaltProcessStep(venvPepper, '*apt*', 'saltutil.sync_all', [], null, true)
115 salt.enforceState(venvPepper, '*apt*', ['salt'], true, false, null, false, -1, 2)
116 salt.enforceState(venvPepper, '*apt*', ['linux'], true, false, null, false, -1, 2)
117 salt.enforceState(venvPepper, '*apt*', ['nginx'], true, false, null, false, -1, 2)
Richard Felkl2e9e5452017-10-16 09:52:10 +0200118 }
119
Richard Felkl994887c2018-01-11 17:13:59 +0100120 stage("Create Docker Registry"){
121 common.infoMsg("Creating Docker Registry")
122 salt.enforceState(venvPepper, '*apt*', ["docker.host"], true, false, null, false, -1, 2)
123 salt.cmdRun(venvPepper, '*apt*', "docker run --restart always -d -p 5000:5000 --name registry registry:2")
124 salt.enforceState(venvPepper, '*apt*', ["docker.client.registry"], true, false, null, false, -1, 2)
125 salt.cmdRun(venvPepper, '*apt*', "docker system prune --all --force")
126 salt.cmdRun(venvPepper, '*apt*', "wget https://raw.githubusercontent.com/Mirantis/mcp-common-scripts/${SCRIPTS_REF}/mirror-image/config/interfaces -O /root/interfaces")
127 salt.cmdRun(venvPepper, '*apt*', "wget https://raw.githubusercontent.com/Mirantis/mcp-common-scripts/${SCRIPTS_REF}/mirror-image/config/minion.conf -O /root/minion.conf")
Richard Felkl2e9e5452017-10-16 09:52:10 +0200128 }
129
Richard Felkl994887c2018-01-11 17:13:59 +0100130 stage("Create Aptly"){
131 common.infoMsg("Creating Aptly")
132 salt.enforceState(venvPepper, '*apt*', ['aptly'], true, false, null, false, -1, 2)
133 //TODO: Do it new way
134 salt.cmdRun(venvPepper, '*apt*', "aptly_mirror_update.sh -s -v", true, null, true, ["runas=aptly"])
135 salt.cmdRun(venvPepper, '*apt*', "nohup aptly api serve --no-lock > /dev/null 2>&1 </dev/null &", true, null, true, ["runas=aptly"])
136 salt.cmdRun(venvPepper, '*apt*', "aptly-publisher --timeout=1200 publish -v -c /etc/aptly-publisher.yaml --architectures amd64 --url http://127.0.0.1:8080 --recreate --force-overwrite", true, null, true, ["runas=aptly"])
137 salt.cmdRun(venvPepper, '*apt*', "aptly db cleanup", true, null, true, ["runas=aptly"])
138 //NEW way
139 //salt.runSaltProcessStep(venvPepper, '*apt*', 'cmd.script', ['salt://aptly/files/aptly_mirror_update.sh', "args=-sv", "runas=aptly"], null, true)
140 //salt.runSaltProcessStep(venvPepper, '*apt*', 'cmd.script', ['salt://aptly/files/aptly_publish_update.sh', "args=-acrfv", "runas=aptly"], null, true)
141 salt.cmdRun(venvPepper, '*apt*', "wget https://raw.githubusercontent.com/Mirantis/mcp-common-scripts/${SCRIPTS_REF}/mirror-image/aptly/aptly-update.sh -O /srv/scripts/aptly-update.sh")
142 salt.cmdRun(venvPepper, '*apt*', "chmod +x /srv/scripts/aptly-update.sh")
Richard Felkl2e9e5452017-10-16 09:52:10 +0200143 }
144
Richard Felkl994887c2018-01-11 17:13:59 +0100145 stage("Create Debmirrors"){
146 common.infoMsg("Creating Debmirrors")
147 salt.cmdRun(venvPepper, '*apt*', "wget https://raw.githubusercontent.com/Mirantis/mcp-common-scripts/${SCRIPTS_REF}/mirror-image/debmirror.sh -O /srv/scripts/debmirror.sh")
148 salt.cmdRun(venvPepper, '*apt*', "chmod +x /srv/scripts/debmirror.sh")
149 salt.cmdRun(venvPepper, '*apt*', "export HOME='/root';export MCP_VERSION='${MCP_VERSION}';/srv/scripts/debmirror.sh")
Richard Felkl7a006072017-12-13 09:47:07 +0100150 }
Richard Felkl14a4c6f2017-11-29 09:10:10 +0100151
Richard Felkl994887c2018-01-11 17:13:59 +0100152 stage("Create Git mirror"){
153 common.infoMsg("Creating Git mirror")
154 salt.enforceState(venvPepper, '*apt*', ['git.server'], true, false, null, false, -1, 2)
155 }
156
157 stage("Create PyPi mirror"){
158 common.infoMsg("Creating PyPi mirror")
159 salt.cmdRun(venvPepper, '*apt*', "pip install pip2pi")
160 salt.cmdRun(venvPepper, '*apt*', "wget https://raw.githubusercontent.com/Mirantis/mcp-common-scripts/${SCRIPTS_REF}/mirror-image/pypi_mirror/requirements.txt -O /srv/pypi_mirror/requirements.txt")
161 salt.cmdRun(venvPepper, '*apt*', "pip2pi /srv/pypi_mirror/packages/ -r /srv/pypi_mirror/requirements.txt")
162 }
163
164 stage("Create mirror of images"){
165 common.infoMsg("Creating mirror of images")
166 salt.cmdRun(venvPepper, '*apt*', "wget https://raw.githubusercontent.com/Mirantis/mcp-common-scripts/${SCRIPTS_REF}/mirror-image/images_mirror/images.txt -O /srv/images.txt")
167 salt.cmdRun(venvPepper, '*apt*', "wget https://raw.githubusercontent.com/Mirantis/mcp-common-scripts/${SCRIPTS_REF}/mirror-image/images_mirror/update-images.sh -O /srv/scripts/update-images.sh")
168 salt.cmdRun(venvPepper, '*apt*', "chmod +x /srv/scripts/update-images.sh")
169 salt.cmdRun(venvPepper, '*apt*', "/srv/scripts/update-images.sh -u http://ci.mcp.mirantis.net:8085/images")
170 }
171
172 stage("Create instance snapshot"){
173 salt.cmdRun(venvPepper, '*apt*', "rm -rf /var/lib/cloud/sem/* /var/lib/cloud/instance /var/lib/cloud/instances/*")
174 salt.cmdRun(venvPepper, '*apt*', "cloud-init init")
175
176 retry(3, 5){
177 openstack.runOpenstackCommand("openstack server stop mcp-offline-mirror-${dateTime}", rcFile, openstackEnv)
178 }
179
180 retry(6, 30){
181 serverStatus = openstack.runOpenstackCommand("openstack server show --format value -c status mcp-offline-mirror-${dateTime}", rcFile, openstackEnv)
182 if(serverStatus != "SHUTOFF"){
183 throw new ResourceException("Instance is not ready for image create.")
184 }
185 }
186 retry(3, 5){
187 openstack.runOpenstackCommand("openstack server image create --name ${IMAGE_NAME}-${dateTime} --wait mcp-offline-mirror-${dateTime}", rcFile, openstackEnv)
Richard Felkl2e9e5452017-10-16 09:52:10 +0200188 }
189 }
Richard Felkl2e9e5452017-10-16 09:52:10 +0200190
Richard Felkl994887c2018-01-11 17:13:59 +0100191 stage("Publish image"){
192 common.infoMsg("Saving image ${IMAGE_NAME}-${dateTime}")
193 retry(3, 5){
194 openstack.runOpenstackCommand("openstack image save --file ${IMAGE_NAME}-${dateTime}.qcow2 ${IMAGE_NAME}-${dateTime}", rcFile, openstackEnv)
Richard Felkl802e4462017-12-06 10:08:05 +0100195 }
Richard Felkl994887c2018-01-11 17:13:59 +0100196 sh "md5sum ${IMAGE_NAME}-${dateTime}.qcow2 > ${IMAGE_NAME}-${dateTime}.qcow2.md5"
Richard Felkl2e9e5452017-10-16 09:52:10 +0200197
Richard Felkl994887c2018-01-11 17:13:59 +0100198 common.infoMsg("Uploading image ${IMAGE_NAME}-${dateTime}")
199 retry(3, 5){
200 uploadImageStatus = sh(script: "curl -f -T ${IMAGE_NAME}-${dateTime}.qcow2 ${UPLOAD_URL}", returnStatus: true)
201 if(uploadImageStatus!=0){
202 throw new Exception("Image upload failed")
203 }
204 }
205 retry(3, 5){
206 uploadMd5Status = sh(script: "curl -f -T ${IMAGE_NAME}-${dateTime}.qcow2.md5 ${UPLOAD_URL}", returnStatus: true)
207 if(uploadMd5Status != 0){
208 throw new Exception("MD5 sum upload failed")
209 }
210 }
211 currentBuild.description = "<a href='http://ci.mcp.mirantis.net:8085/images/${IMAGE_NAME}-${dateTime}.qcow2'>${IMAGE_NAME}-${dateTime}.qcow2</a>"
Richard Felkl2e9e5452017-10-16 09:52:10 +0200212 }
Richard Felkl994887c2018-01-11 17:13:59 +0100213
214 } catch (Throwable e) {
215 // If there was an error or exception thrown, the build failed
216 currentBuild.result = "FAILURE"
217 throw e
218 } finally {
219 stage("Cleanup"){
220 if(openstackServer != ""){
221 openstack.runOpenstackCommand("openstack ip floating remove ${floatingIP} mcp-offline-mirror-${dateTime}", rcFile, openstackEnv)
222 openstack.runOpenstackCommand("openstack server delete mcp-offline-mirror-${dateTime}", rcFile, openstackEnv)
223 }
224 if(privateKey != ""){
225 openstack.runOpenstackCommand("openstack keypair delete mcp-offline-keypair-${dateTime}", rcFile, openstackEnv)
226 }
227 sh "rm -rf ./*"
Richard Felkl2e9e5452017-10-16 09:52:10 +0200228 }
Richard Felkl2e9e5452017-10-16 09:52:10 +0200229 }
230 }
Jakub Josef88aaf832018-01-18 16:18:28 +0100231}