· 7 years ago · Jul 13, 2018, 10:58 AM
1#!/usr/bin/env python
2
3from fabric.api import run, sudo, env, lcd
4from fabric.api import cd, hide, local, settings
5from fabric.operations import put, get
6from fabric.contrib.files import append
7import signal
8import random
9import sys
10import os
11
12PACKER_TMP = ''
13JSON_PATH = ''
14JSON_CFG = 'packer.json'
15
16# ESXi host where VM will be created
17esxi_host = 'ova-builder'
18esxi_user = 'xxxx'
19esxi_passwd = 'xxxx'
20esxi_datastore = 'datastore1'
21
22size_dict = { '80 GB': 80*1024,
23 '64 GB': 64*1024,
24 '40 GB': 40*1024,
25 '32 GB': 32*1024,
26 '20 GB': 20*1024,
27 }
28
29user_dict = { 'xxxx-xxxx' : 'xxxx',
30 'xxxx-xxxx' : 'xxxx',
31 'xxxx-xxxx' : 'xxxx'
32 }
33
34json_template = """{
35 "variables": {
36 "aws_access_key": "*********",
37 "aws_secret_key": "*********",
38 "s3_key_name": "%(name)s.ova",
39 "ami_name": "%(name)s.ova",
40 "ami_description": "%(desc)s"
41 },
42 "builders": [
43 {
44 "type": "vmware-iso",
45 "iso_url": "%(isourl)s",
46 "iso_checksum": "%(checksum)s",
47 "iso_checksum_type": "md5",
48 "disk_size": "%(disksiz)u",
49 "disk_type_id": "zeroedthick",
50 "remote_host": "%(host)s",
51 "remote_datastore": "%(datastore)s",
52 "remote_username": "%(user)s",
53 "remote_password": "%(passwd)s",
54 "remote_type": "esx5",
55 "ssh_username": "%(sshuser)s",
56 "ssh_password": "xxxx",
57 "ssh_port": 22,
58 "ssh_wait_timeout": "30m",
59 "shutdown_command": "echo xxxx | sudo -S shutdown -P now",
60 "headless": "false",
61 "boot_wait": "20s",
62 "guest_os_type": "ubuntu-64",
63 "output_directory": "%(name)s",
64 "vm_name": "%(name)s",
65 "format": "ova",
66 "boot_command": [
67 "<enter><wait>",
68 "<enter>"
69 ],
70 "vmx_data": {
71 "ethernet0.networkName": "VM Network",
72 "memsize": "4096",
73 "numvcpus": "4",
74 "virtualhw.version": "10",
75 "cpuid.coresPerSocket": "1",
76 "ide0:0.fileName": "disk.vmdk",
77 "ide0:0.present": "TRUE",
78 "ide0:0.redo": "",
79 "scsi0:0.present": "FALSE"
80 }
81 }
82 ],
83 "provisioners": [
84 {
85 "type": "shell",
86 "inline": [
87 "sleep 120",
88 "echo '=> Adding cloud instance file'",
89 "echo xxxx | sudo -S rm -f /opt/xxxx/confd/var/confd/cdb/*.cdb",
90 "echo xxxx | sudo -S bash -c 'echo AWS > /opt/xxxx/etc/cloud_instance'",
91 "echo xxxx | sudo -S chmod g+r /opt/xxxx/etc/cloud_instance",
92
93 ]
94 }
95 ],
96 "post-processors": [
97 {
98 "type": "artifice",
99 "files": [ "{{user `output_directory`}}.ova" ]
100 }%(amijson)s
101 ]
102}
103"""
104
105ami_import_json = """,
106 {
107 "type": "amazon-import",
108 "ami_name": "{{user `ami_name`}}",
109 "ami_description": "{{user `ami description`}}",
110 "access_key": "{{user `aws_access_key`}}",
111 "secret_key": "{{user `aws_secret_key`}}",
112 "region": "%s",
113 "s3_bucket_name": "xxxx-jenkins-%s",
114 "s3_key_name": "{{user `s3_key_name`}}",
115 "license_type": "BYOL"
116 }"""
117
118class ESXI:
119 def __init__(self, addr, user, passwd, datastore):
120 self.address = addr
121 self.user = user
122 self.passwd = passwd
123 self.datastore = '/vmfs/volumes/%s'%(datastore)
124 self.vmid = 0
125 return
126
127 def enable_guestiphack(self):
128 self.setup_fabric_env()
129 print '=> Enabling GuestIPHack on ESXi'
130 with settings(warn_only=True):
131 with hide('output'):
132 run('esxcli system settings advanced set -o /Net/GuestIPHack -i 1')
133 return
134
135 def setup_fabric_env(self):
136 env.host_string = self.address
137 env.user = self.user
138 env.password = self.passwd
139 env.shell = '/bin/sh -l -c'
140 return
141
142 def delete_packer_cache(self):
143 with settings(warn_only=True):
144 run('rm -fr %s/packer_cache'%(self.datastore))
145 return
146
147
148def setup_fabric_env():
149 env.user = 'xxxx'
150 env.password = 'xxxx'
151 env.host_string = 'xxxx'
152 return
153
154
155def download_iso(url):
156 '''
157 Downloads ISO and MD5SUM file
158 '''
159
160 # Trim URL if path to file is provided
161 file = os.path.basename(url)
162 if file.find('.iso') > 0:
163 url = os.path.dirname(url)
164
165 setup_fabric_env()
166 with hide('running', 'output'):
167 run('mkdir -p %s'%(PACKER_TMP))
168 with cd(PACKER_TMP):
169 print '=> Cleaning old files'
170 run('rm -fr *')
171
172 print '=> Downloading ISO'
173 run('wget -q -nd -r -np -R "index.html*" %s'%(url))
174 iso = run('echo *.iso')
175 print '=> Downloaded %s'%(iso)
176 return
177
178
179def generate_packer_json(product, regions, size):
180 '''
181 Generates packer JSON config file
182 '''
183 setup_fabric_env()
184 with hide('running', 'output'):
185 with cd(PACKER_TMP):
186 md5sum = run('cat MD5SUM | awk \'{print $1}\'')
187 iso = run('echo *.iso')
188 hash = run('echo *.iso | cut -d- -f3')
189 branch = run('echo *.iso | cut -d- -f4 | cut -d. -f1,2')
190
191 oname = '%s-%s-%s'%(product, hash, branch)
192 assert(user_dict.has_key(product))
193 uname = user_dict[product]
194 description = '%s %s'%(product.title().replace('-', ' '), branch)
195
196 print '=> Creating packer json config file'
197 config = open(JSON_CFG, 'w')
198
199 ami_json = ''
200 for region in regions.split(','):
201 if region == 'cn-north-1':
202 ami_json += ami_china_import_json%(region, region)
203 else:
204 ami_json += ami_import_json%(region, region)
205
206 config.write(json_template%({
207 'name' : oname,
208 'desc' : description,
209 'isourl' : iso,
210 'checksum' : md5sum,
211 'disksiz' : size,
212 'host' : esxi_host,
213 'datastore': esxi_datastore,
214 'user' : esxi_user,
215 'passwd' : esxi_passwd,
216 'sshuser' : uname,
217 'amijson' : ami_json,
218 }))
219 config.close()
220
221
222 print '=> Uploading packer json config'
223 with hide('running'):
224 put(JSON_CFG, JSON_PATH)
225 return oname
226
227
228
229def build_ova():
230 '''
231 Builds ova image :-)
232 '''
233 print '=> Validating packer template'
234 result = run('/usr/local/bin/packer validate %s'%(JSON_PATH))
235 if result.failed:
236 print 'Error validating packer.json'
237 sys.exit(1)
238
239 print '=> Building ova image'
240 with cd(PACKER_TMP):
241 run('export PACKER_LOG=1; /usr/local/bin/packer build packer.json')
242 return
243
244
245def main():
246 if len(sys.argv) < 4:
247 print 'Input arguments incomplete'
248 print ' %s [product] [iso-url] [regions]'%(sys.argv[0])
249 sys.exit(1)
250
251 product = sys.argv[1]
252 url = sys.argv[2]
253 regions = sys.argv[3]
254 size = sys.argv[4]
255
256 try:
257 msize = size_dict[size]
258 except:
259 print 'Unsupported size: %s'%(size)
260 sys.exit(1)
261
262
263 global PACKER_TMP
264 global JSON_PATH
265 PACKER_TMP = os.path.join('/var', 'tmp', 'packer', product, 'ami')
266 JSON_PATH = os.path.join(PACKER_TMP, JSON_CFG)
267
268 esxi = ESXI(esxi_host, esxi_user, esxi_passwd, esxi_datastore)
269 esxi.enable_guestiphack()
270 esxi.delete_packer_cache()
271
272 download_iso(url)
273 generate_packer_json(product, regions, msize)
274 build_ova()
275 esxi.delete_packer_cache()
276 return
277
278
279if __name__ == '__main__':
280 main()