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