blob: 3941e248b65c2d4d2eab4d81a2a716772b7c9e50 [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.
7 * CLUSTER_NAME - Cluster name used in the above model.
8 * IMAGE_NAME - Name of the result image.
9 * OS_CREDENTIALS_ID - ID of credentials for OpenStack API stored in Jenkins.
10 * OS_PROJECT - Project in OpenStack under the VM will be spawned.
11 * OS_URL - Keystone auth endpoint of the OpenStack.
12 * OS_VERSION - OpenStack version
13 * SCRIPTS_REF - ref on the github to get the scripts from.
14 * SALT_MASTER_CREDENTIALS - ID of credentials to be used to connect to the Salt API of the VM
15 * UPLOAD_URL - URL of an WebDAV used to upload the image after creating.
16 * VM_AVAILABILITY_ZONE - Availability zone in OpenStack in the VM will be spawned.
17 * VM_CONNECT_RETRIES - Number of retries for SSH connection to the VM after it’s spawned after 8 minutes.
18 * VM_CONNECT_DELAY - Delay between connect retries above.
19 * VM_FLAVOR - Flavor to be used for VM in OpenStack.
20 * VM_FLOATING_IP_POOL - Floating IP pool to be used to assign floating IP to the VM.
21 * VM_IMAGE - Name of the image to be used for VM in OpenStack.
22 * VM_IP - Static IP that is assigned to the VM which belongs to the network used.
23 * VM_IP_RETRIES - Number of retries between tries to assign the floating IP to the VM.
24 * VM_IP_DELAY - Delay between floating IP assign retries above.
25 * VM_NETWORK_ID - ID of the network that VM connects to.
26 *
Richard Felkl2e9e5452017-10-16 09:52:10 +020027 */
28
29// Load shared libs
30def salt = new com.mirantis.mk.Salt()
31def common = new com.mirantis.mk.Common()
32def python = new com.mirantis.mk.Python()
33def openstack = new com.mirantis.mk.Openstack()
Richard Felkl2e9e5452017-10-16 09:52:10 +020034def date = new Date()
35def dateTime = date.format("ddMMyyyy-HHmmss")
36def venvPepper = "venvPepper"
Richard Felkl2e9e5452017-10-16 09:52:10 +020037def privateKey = ""
38def floatingIP = ""
39def openstackServer = ""
40def rcFile = ""
41def openstackEnv = ""
42def serverStatus = ""
Richard Felkl802e4462017-12-06 10:08:05 +010043def uploadImageStatus = ""
44def uploadMd5Status = ""
Richard Felkl2e9e5452017-10-16 09:52:10 +020045
46def retry(int times = 5, int delay = 0, Closure body) {
47 int retries = 0
48 def exceptions = []
49 while(retries++ < times) {
50 try {
51 return body.call()
52 } catch(e) {
53 sleep(delay)
54 }
55 }
56 currentBuild.result = "FAILURE"
57 throw new Exception("Failed after $times retries")
58}
59
60node("python&&disk-xl") {
61 try {
62 def workspace = common.getWorkspace()
63 rcFile = openstack.createOpenstackEnv(OS_URL, OS_CREDENTIALS_ID, OS_PROJECT, "default", "", "default", "2", "")
64 openstackEnv = String.format("%s/venv", workspace)
Richard Felkl077b6422017-12-14 16:19:54 +010065 def openstackVersion = OS_VERSION
Richard Felkl2e9e5452017-10-16 09:52:10 +020066
67 VM_IP_DELAY = VM_IP_DELAY as Integer
68 VM_IP_RETRIES = VM_IP_RETRIES as Integer
69 VM_CONNECT_DELAY = VM_CONNECT_DELAY as Integer
70 VM_CONNECT_RETRIES = VM_CONNECT_RETRIES as Integer
71
72 stage("Get templates"){
73
74 if (!fileExists("${workspace}/tmp")) {
75 sh "mkdir -p ${workspace}/tmp"
76 }
77
Richard Felkl077b6422017-12-14 16:19:54 +010078 sh "wget https://raw.githubusercontent.com/Mirantis/mcp-common-scripts/${SCRIPTS_REF}/mirror-image/salt-bootstrap.sh"
Richard Felkl2e9e5452017-10-16 09:52:10 +020079 openstack.setupOpenstackVirtualenv(openstackEnv, openstackVersion)
80 }
81
82 stage("Spawn Instance"){
83 privateKey = openstack.runOpenstackCommand("openstack keypair create mcp-offline-keypair-${dateTime}", rcFile, openstackEnv)
84
85 common.infoMsg(privateKey)
86 sh "echo '${privateKey}' > id_rsa;chmod 600 id_rsa"
87
88 floatingIP = openstack.runOpenstackCommand("openstack ip floating create --format value -c floating_ip_address ${VM_FLOATING_IP_POOL}", rcFile, openstackEnv)
89
90 withEnv(["CLUSTER_NAME=${CLUSTER_NAME}", "CLUSTER_MODEL=${CLUSTER_MODEL}"]) {
91 sh "envsubst < salt-bootstrap.sh > salt-bootstrap.sh.temp;mv salt-bootstrap.sh.temp salt-bootstrap.sh; cat salt-bootstrap.sh"
92 }
93
Richard Felkl54cc3d52017-11-28 17:19:22 +010094 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)
Richard Felkl2e9e5452017-10-16 09:52:10 +020095 sleep(60)
96
97 retry(VM_IP_RETRIES, VM_IP_DELAY){
98 openstack.runOpenstackCommand("openstack ip floating add ${floatingIP} mcp-offline-mirror-${dateTime}", rcFile, openstackEnv)
99 }
100
101 sleep(500)
102
103 retry(VM_CONNECT_RETRIES, VM_CONNECT_DELAY){
104 sh "scp -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -i id_rsa root@${floatingIP}:/srv/initComplete ./"
105 }
106
107 python.setupPepperVirtualenv(venvPepper, "http://${floatingIP}:6969", SALT_MASTER_CREDENTIALS)
108 }
109 stage("Prepare instance"){
110 salt.runSaltProcessStep(venvPepper, '*apt*', 'saltutil.refresh_pillar', [], null, true)
111 salt.runSaltProcessStep(venvPepper, '*apt*', 'saltutil.sync_all', [], null, true)
112 salt.enforceState(venvPepper, '*apt*', ['salt'], true, false, null, false, -1, 2)
113 salt.enforceState(venvPepper, '*apt*', ['linux'], true, false, null, false, -1, 2)
114 salt.enforceState(venvPepper, '*apt*', ['nginx'], true, false, null, false, -1, 2)
115 }
116
117 stage("Create Docker Registry"){
118 common.infoMsg("Creating Docker Registry")
Richard Felklae5ef472017-12-21 15:35:54 +0100119 salt.enforceState(venvPepper, '*apt*', ["docker.host"], true, false, null, false, -1, 2)
120 salt.runSaltProcessStep(venvPepper, '*apt*', 'cmd.run', ["docker run --restart always -d -p 5000:5000 --name registry registry:2"], null, true)
121 salt.enforceState(venvPepper, '*apt*', ["docker.client.registry"], true, false, null, false, -1, 2)
122 salt.runSaltProcessStep(venvPepper, '*apt*', 'cmd.run', ["docker system prune --all --force"], null, true)
Richard Felkl2e9e5452017-10-16 09:52:10 +0200123 }
124
125 stage("Create Aptly"){
126 common.infoMsg("Creating Aptly")
127 salt.enforceState(venvPepper, '*apt*', ['aptly'], true, false, null, false, -1, 2)
128 //TODO: Do it new way
Richard Felklae5ef472017-12-21 15:35:54 +0100129 salt.runSaltProcessStep(venvPepper, '*apt*', 'cmd.run', ["aptly_mirror_update.sh -s -v", "runas=aptly"], null, true)
130 salt.runSaltProcessStep(venvPepper, '*apt*', 'cmd.run', ["nohup aptly api serve --no-lock > /dev/null 2>&1 </dev/null &", "runas=aptly"], null, true)
131 salt.runSaltProcessStep(venvPepper, '*apt*', 'cmd.run', ["aptly-publisher --timeout=1200 publish -v -c /etc/aptly-publisher.yaml --architectures amd64 --url http://127.0.0.1:8080 --recreate --force-overwrite", "runas=aptly"], null, true)
132 salt.runSaltProcessStep(venvPepper, '*apt*', 'cmd.run', ["aptly db cleanup", "runas=aptly"], null, true)
Richard Felkl2e9e5452017-10-16 09:52:10 +0200133 //NEW way
Richard Felklae5ef472017-12-21 15:35:54 +0100134 //salt.runSaltProcessStep(venvPepper, '*apt*', 'cmd.script', ['salt://aptly/files/aptly_mirror_update.sh', "args=-sv", "runas=aptly"], null, true)
135 //salt.runSaltProcessStep(venvPepper, '*apt*', 'cmd.script', ['salt://aptly/files/aptly_publish_update.sh', "args=-acrfv", "runas=aptly"], null, true)
136 salt.runSaltProcessStep(venvPepper, '*apt*', 'cmd.run', ["wget https://raw.githubusercontent.com/Mirantis/mcp-common-scripts/${SCRIPTS_REF}/mirror-image/aptly/aptly-update.sh -O /srv/scripts/aptly-update.sh"], null, true)
137 salt.runSaltProcessStep(venvPepper, '*apt*', 'cmd.run', ["chmod +x /srv/scripts/aptly-update.sh"], null, true)
Richard Felkl2e9e5452017-10-16 09:52:10 +0200138 }
139
Richard Felkl859f4dd2018-01-04 23:03:27 +0100140 stage("Create Debmirrors"){
141 common.infoMsg("Creating Debmirrors")
142 salt.runSaltProcessStep(venvPepper, '*apt*', 'cmd.run', ["wget https://raw.githubusercontent.com/Mirantis/mcp-common-scripts/${SCRIPTS_REF}/mirror-image/debmirror.sh -O /srv/scripts/debmirror.sh"], null, true)
143 salt.runSaltProcessStep(venvPepper, '*apt*', 'cmd.run', ["chmod +x /srv/scripts/debmirror.sh"], null, true)
144 salt.runSaltProcessStep(venvPepper, '*apt*', 'cmd.run', ["export MCP_VERSION='${MCP_VERSION}';/srv/scripts/debmirror.sh"], null, true)
145 }
146
Richard Felkl2e9e5452017-10-16 09:52:10 +0200147 stage("Create Git mirror"){
148 common.infoMsg("Creating Git mirror")
149 salt.enforceState(venvPepper, '*apt*', ['git.server'], true, false, null, false, -1, 2)
150 }
151
152 stage("Create PyPi mirror"){
153 common.infoMsg("Creating PyPi mirror")
Richard Felklae5ef472017-12-21 15:35:54 +0100154 salt.runSaltProcessStep(venvPepper, '*apt*', 'cmd.run', ["pip install pip2pi"], null, true)
155 salt.runSaltProcessStep(venvPepper, '*apt*', 'cmd.run', ["wget https://raw.githubusercontent.com/Mirantis/mcp-common-scripts/${SCRIPTS_REF}/mirror-image/pypi_mirror/requirements.txt -O /srv/pypi_mirror/requirements.txt"], null, true)
156 salt.runSaltProcessStep(venvPepper, '*apt*', 'cmd.run', ["pip2pi /srv/pypi_mirror/packages/ -r /srv/pypi_mirror/requirements.txt"], null, true)
Richard Felkl2e9e5452017-10-16 09:52:10 +0200157 }
158
159 stage("Create mirror of images"){
160 common.infoMsg("Creating mirror of images")
Richard Felklae5ef472017-12-21 15:35:54 +0100161 salt.runSaltProcessStep(venvPepper, '*apt*', 'cmd.run', ["wget https://raw.githubusercontent.com/Mirantis/mcp-common-scripts/${SCRIPTS_REF}/mirror-image/images_mirror/images.txt -O /srv/images.txt"], null, true)
162 salt.runSaltProcessStep(venvPepper, '*apt*', 'cmd.run', ["wget https://raw.githubusercontent.com/Mirantis/mcp-common-scripts/${SCRIPTS_REF}/mirror-image/images_mirror/update-images.sh -O /srv/scripts/update-images.sh"], null, true)
163 salt.runSaltProcessStep(venvPepper, '*apt*', 'cmd.run', ["chmod +x /srv/scripts/update-images.sh"], null, true)
164 salt.runSaltProcessStep(venvPepper, '*apt*', 'cmd.run', ["/srv/scripts/update-images.sh -u http://ci.mcp.mirantis.net:8085/images"], null, true)
Richard Felkl2e9e5452017-10-16 09:52:10 +0200165 }
166
167 stage("Create instance snapshot"){
Richard Felklae5ef472017-12-21 15:35:54 +0100168 salt.runSaltProcessStep(venvPepper, '*apt*', 'cmd.run', ["rm -rf /var/lib/cloud/sem/* /var/lib/cloud/instance /var/lib/cloud/instances/*"], null, true)
169 salt.runSaltProcessStep(venvPepper, '*apt*', 'cmd.run', ["cloud-init init"], null, true)
Richard Felkl14a4c6f2017-11-29 09:10:10 +0100170
Richard Felkl7a006072017-12-13 09:47:07 +0100171 retry(3, 5){
172 openstack.runOpenstackCommand("openstack server stop mcp-offline-mirror-${dateTime}", rcFile, openstackEnv)
173 }
Richard Felkl14a4c6f2017-11-29 09:10:10 +0100174
Richard Felkl2e9e5452017-10-16 09:52:10 +0200175 retry(6, 30){
176 serverStatus = openstack.runOpenstackCommand("openstack server show --format value -c status mcp-offline-mirror-${dateTime}", rcFile, openstackEnv)
177 if(serverStatus != "SHUTOFF"){
178 throw new ResourceException("Instance is not ready for image create.")
179 }
180 }
Richard Felkl7a006072017-12-13 09:47:07 +0100181 retry(3, 5){
182 openstack.runOpenstackCommand("openstack server image create --name ${IMAGE_NAME}-${dateTime} --wait mcp-offline-mirror-${dateTime}", rcFile, openstackEnv)
183 }
Richard Felkl2e9e5452017-10-16 09:52:10 +0200184 }
185
186 stage("Publish image"){
Richard Felkl802e4462017-12-06 10:08:05 +0100187 common.infoMsg("Saving image ${IMAGE_NAME}-${dateTime}")
Richard Felkl7a006072017-12-13 09:47:07 +0100188 retry(3, 5){
189 openstack.runOpenstackCommand("openstack image save --file ${IMAGE_NAME}-${dateTime} ${IMAGE_NAME}-${dateTime}", rcFile, openstackEnv)
190 }
Richard Felkl802e4462017-12-06 10:08:05 +0100191 sh "md5sum ${IMAGE_NAME}-${dateTime} > ${IMAGE_NAME}-${dateTime}.md5"
192
193 common.infoMsg("Uploading image ${IMAGE_NAME}-${dateTime}")
194 retry(3, 5){
195 uploadImageStatus = sh(script: "curl -f -T ${IMAGE_NAME}-${dateTime} ${UPLOAD_URL}", returnStatus: true)
196 if(uploadImageStatus!=0){
197 throw new Exception("Image upload failed")
198 }
199 }
200 retry(3, 5){
201 uploadMd5Status = sh(script: "curl -f -T ${IMAGE_NAME}-${dateTime}.md5 ${UPLOAD_URL}", returnStatus: true)
202 if(uploadMd5Status != 0){
203 throw new Exception("MD5 sum upload failed")
204 }
205 }
Richard Felkl2e9e5452017-10-16 09:52:10 +0200206 }
207
208 } catch (Throwable e) {
209 // If there was an error or exception thrown, the build failed
210 currentBuild.result = "FAILURE"
211 throw e
212 } finally {
213 stage("Cleanup"){
214 if(openstackServer != ""){
215 openstack.runOpenstackCommand("openstack ip floating remove ${floatingIP} mcp-offline-mirror-${dateTime}", rcFile, openstackEnv)
216 openstack.runOpenstackCommand("openstack server delete mcp-offline-mirror-${dateTime}", rcFile, openstackEnv)
217 }
218 if(privateKey != ""){
219 openstack.runOpenstackCommand("openstack keypair delete mcp-offline-keypair-${dateTime}", rcFile, openstackEnv)
220 }
221 sh "rm -rf ./*"
222 }
223 }
224}