def create_ami(host_instance, args, config, instance_config, ssh_key, key_filename, instance_data, deploypass, cert, pkey, ami_name_prefix): connection = host_instance.connection setup_fabric_env(instance=host_instance, abort_on_prompts=True, disable_known_hosts=True, key_filename=key_filename) target_name = args.config virtualization_type = config.get("virtualization_type") config_dir = "%s/%s" % (AMI_CONFIGS_DIR, target_name) if ami_name_prefix: prefix = ami_name_prefix else: prefix = args.config dated_target_name = "{}-{}".format( prefix, time.strftime("%Y-%m-%d-%H-%M", time.gmtime())) if config.get('distro') in ('debian', 'ubuntu'): ubuntu_release = config.get("release", "precise") int_dev_name = config['target']['int_dev_name'] mount_dev = int_dev_name grub_dev = int_dev_name mount_point = config['target']['mount_point'] boot_mount_dev = None host_packages_file = os.path.join(config_dir, "host_packages") packages_file = os.path.join(config_dir, "packages") if os.path.exists(host_packages_file): install_packages(host_packages_file, config.get('distro')) v = attach_and_wait(host_instance, config['target']['size'], config['target']['aws_dev_name'], int_dev_name) # Step 0: install required packages if config.get('distro') == "centos": run('which MAKEDEV >/dev/null || yum -d 1 install -y MAKEDEV') # Step 1: prepare target FS run('mkdir -p %s' % mount_point) if config.get("root_device_type") == "instance-store": # Use file image mount_dev = "/dev/cloud_root/lv_root" grub_dev = "/dev/loop0" boot_mount_dev = "/dev/mapper/loop0p1" img_file = dated_target_name partition_image(mount_dev=mount_dev, int_dev_name=int_dev_name, img_file=img_file) elif virtualization_type == "hvm": # use EBS volume mount_dev = "/dev/cloud_root/lv_root" boot_mount_dev = "%s1" % int_dev_name partition_ebs_volume(int_dev_name=int_dev_name) run('/sbin/mkfs.{fs_type} {args} {dev}'.format( fs_type=config['target']['fs_type'], args=config['target'].get("mkfs_args", ""), dev=mount_dev)) run('/sbin/e2label {dev} {label}'.format( dev=mount_dev, label=config['target']['e2_label'])) run('mount {dev} {mount_point}'.format(dev=mount_dev, mount_point=mount_point)) run('mkdir {0}/dev {0}/proc {0}/etc {0}/boot {0}/sys'.format(mount_point)) run('mount -t sysfs sys %s/sys' % mount_point) if config.get('distro') not in ('debian', 'ubuntu'): run('mount -t proc proc %s/proc' % mount_point) run('for i in console null zero random urandom; ' 'do /sbin/MAKEDEV -d %s/dev -x $i ; done' % mount_point) if boot_mount_dev: run('mount {} {}/boot'.format(boot_mount_dev, mount_point)) # Step 2: install base system if config.get('distro') in ('debian', 'ubuntu'): run("debootstrap %s %s " "http://puppet/repos/apt/ubuntu/" % (ubuntu_release, mount_point)) run('chroot %s mount -t proc none /proc' % mount_point) run('mount -o bind /dev %s/dev' % mount_point) put('%s/releng-public-%s.list' % (AMI_CONFIGS_DIR, ubuntu_release), '%s/etc/apt/sources.list' % mount_point) with lcd(config_dir): put('usr/sbin/policy-rc.d', '%s/usr/sbin/' % mount_point, mirror_local_mode=True) install_packages(packages_file, config.get('distro'), chroot=mount_point) else: with lcd(config_dir): put('etc/yum-local.cfg', '%s/etc/yum-local.cfg' % mount_point) yum = 'yum -d 1 -c {0}/etc/yum-local.cfg -y --installroot={0} '.format( mount_point) # this groupinstall emulates the %packages section of the kickstart # config, which defaults to Core and Base. run('%s groupinstall Core Base' % yum) run('%s clean packages' % yum) # Rebuild RPM DB for cases when versions mismatch run('chroot %s rpmdb --rebuilddb || :' % mount_point) # Step 3: upload custom configuration files run('chroot %s mkdir -p /boot/grub' % mount_point) for directory in ('boot', 'etc', 'usr'): local_directory = os.path.join(config_dir, directory) remote_directory = os.path.join(mount_point, directory) if not os.path.exists(local_directory): pass sync(local_directory, remote_directory) # Step 4: tune configs run('sed -i -e s/@ROOT_DEV_LABEL@/{label}/g -e s/@FS_TYPE@/{fs}/g ' '{mnt}/etc/fstab'.format(label=config['target']['e2_label'], fs=config['target']['fs_type'], mnt=mount_point)) if config.get('distro') in ('debian', 'ubuntu'): if virtualization_type == "hvm": run("chroot {mnt} grub-install {int_dev_name}".format( mnt=mount_point, int_dev_name=int_dev_name)) run("chroot {mnt} update-grub".format(mnt=mount_point)) else: run("chroot {mnt} update-grub -y".format(mnt=mount_point)) run("sed -i 's/^# groot.*/# groot=(hd0)/g' " "{mnt}/boot/grub/menu.lst".format(mnt=mount_point)) run("chroot {mnt} update-grub".format(mnt=mount_point)) else: run('ln -s grub.conf %s/boot/grub/menu.lst' % mount_point) run('ln -s ../boot/grub/grub.conf %s/etc/grub.conf' % mount_point) if config.get('kernel_package') == 'kernel-PAE': run('sed -i s/@VERSION@/`chroot %s rpm -q ' '--queryformat "%%{version}-%%{release}.%%{arch}.PAE" ' '%s | tail -n1`/g %s/boot/grub/grub.conf' % (mount_point, config.get('kernel_package', 'kernel'), mount_point)) else: run('sed -i s/@VERSION@/`chroot %s rpm -q ' '--queryformat "%%{version}-%%{release}.%%{arch}" ' '%s | tail -n1`/g %s/boot/grub/grub.conf' % (mount_point, config.get('kernel_package', 'kernel'), mount_point)) if config.get("root_device_type") == "instance-store": # files normally copied by grub-install run("cp -va /usr/share/grub/x86_64-redhat/* /mnt/boot/grub/") put(os.path.join(config_dir, "grub.cmd"), "/tmp/grub.cmd") run("sed -i s/@IMG@/{}/g /tmp/grub.cmd".format(img_file)) run("cat /tmp/grub.cmd | grub --device-map=/dev/null") elif virtualization_type == "hvm": # See https://bugs.archlinux.org/task/30241 for the details, # grub-nstall doesn't handle /dev/xvd* devices properly grub_install_patch = os.path.join(config_dir, "grub-install.diff") if os.path.exists(grub_install_patch): put(grub_install_patch, "/tmp/grub-install.diff") run('which patch >/dev/null || yum -d 1 install -y patch') run('patch -p0 -i /tmp/grub-install.diff /sbin/grub-install') run("grub-install --root-directory=%s --no-floppy %s" % (mount_point, grub_dev)) run("sed -i -e '/PermitRootLogin/d' -e '/UseDNS/d' " "-e '$ a PermitRootLogin without-password' " "-e '$ a UseDNS no' " "%s/etc/ssh/sshd_config" % mount_point) if config.get('distro') in ('debian', 'ubuntu'): pass else: manage_service("network", mount_point, "on") manage_service("rc.local", mount_point, "on") if config.get("root_device_type") == "instance-store" and \ config.get("distro") == "centos": instance_data = instance_data.copy() instance_data['name'] = host_instance.tags.get("Name") instance_data['hostname'] = host_instance.tags.get("FQDN") run("cp /etc/resolv.conf {}/etc/resolv.conf".format(mount_point)) # make puppet happy # disable ipv6 run("/sbin/service ip6tables stop") # mount /dev to let sshd start run('mount -o bind /dev %s/dev' % mount_point) assimilate_instance(host_instance, instance_config, ssh_key, instance_data, deploypass, chroot=mount_point, reboot=False) ami_cleanup(mount_point=mount_point, distro=config["distro"]) # kill chroot processes put('%s/kill_chroot.sh' % AMI_CONFIGS_DIR, '/tmp/kill_chroot.sh') run('bash /tmp/kill_chroot.sh {}'.format(mount_point)) run('swapoff -a') run('umount %s/dev || :' % mount_point) if config.get("distro") == "ubuntu": run('rm -f %s/usr/sbin/policy-rc.d' % mount_point) run('chroot %s ln -s /sbin/MAKEDEV /dev/' % mount_point) for dev in ('zero', 'null', 'console', 'generic'): run('chroot %s sh -c "cd /dev && ./MAKEDEV %s"' % (mount_point, dev)) run('umount %s/sys || :' % mount_point) run('umount %s/proc || :' % mount_point) run('umount %s/dev || :' % mount_point) run('umount %s/boot || :' % mount_point) run('umount %s' % mount_point) if config.get("root_device_type") == "instance-store" \ and config.get("distro") == "centos": # create bundle run("yum -d 1 install -y ruby " "http://s3.amazonaws.com/ec2-downloads/ec2-ami-tools.noarch.rpm") bundle_location = "{b}/{d}/{t}/{n}".format( b=config["bucket"], d=config["bucket_dir"], t=config["target"]["tags"]["moz-type"], n=dated_target_name) manifest_location = "{}/{}.manifest.xml".format(bundle_location, dated_target_name) run("mkdir -p /mnt-tmp/out") put(cert, "/mnt-tmp/cert.pem") put(pkey, "/mnt-tmp/pk.pem") run("ec2-bundle-image -c /mnt-tmp/cert.pem -k /mnt-tmp/pk.pem " "-u {uid} -i /mnt-tmp/{img_file} -d /mnt-tmp/out -r x86_64".format( img_file=img_file, uid=config["aws_user_id"])) with hide('running', 'stdout', 'stderr'): log.info("uploading bundle") run("ec2-upload-bundle -b {bundle_location}" " --access-key {access_key} --secret-key {secret_key}" " --region {region}" " -m /mnt-tmp/out/{img_file}.manifest.xml --retry".format( bundle_location=bundle_location, access_key=boto.config.get("Credentials", "aws_access_key_id"), secret_key=boto.config.get("Credentials", "aws_secret_access_key"), region=connection.region.name, img_file=img_file)) v.detach(force=True) wait_for_status(v, "status", "available", "update") if not config.get("root_device_type") == "instance-store": # Step 5: Create a snapshot log.info('Creating a snapshot') snapshot = v.create_snapshot(dated_target_name) wait_for_status(snapshot, "status", "completed", "update") snapshot.add_tag('Name', dated_target_name) snapshot.add_tag('moz-created', str(int(time.mktime(time.gmtime())))) # Step 6: Create an AMI log.info('Creating AMI') if config.get("root_device_type") == "instance-store": ami_id = connection.register_image( dated_target_name, '%s AMI' % dated_target_name, architecture=config['arch'], virtualization_type=virtualization_type, image_location=manifest_location, ) else: host_img = connection.get_image(config['ami']) block_map = BlockDeviceMapping() block_map[host_img.root_device_name] = BlockDeviceType( snapshot_id=snapshot.id) root_device_name = host_img.root_device_name if virtualization_type == "hvm": kernel_id = None ramdisk_id = None else: kernel_id = host_img.kernel_id ramdisk_id = host_img.ramdisk_id ami_id = connection.register_image( dated_target_name, '%s AMI' % dated_target_name, architecture=config['arch'], kernel_id=kernel_id, ramdisk_id=ramdisk_id, root_device_name=root_device_name, block_device_map=block_map, virtualization_type=virtualization_type, ) while True: try: ami = connection.get_image(ami_id) ami.add_tag('Name', dated_target_name) ami.add_tag('moz-created', str(int(time.mktime(time.gmtime())))) if config["target"].get("tags"): for tag, value in config["target"]["tags"].items(): log.info("Tagging %s: %s", tag, value) ami.add_tag(tag, value) log.info('AMI created') log.info('ID: {id}, name: {name}'.format(id=ami.id, name=ami.name)) break except: log.info('Wating for AMI') time.sleep(10) # Step 7: Cleanup if not args.keep_volume: log.info('Deleting volume') v.delete() if not args.keep_host_instance: log.info('Terminating host instance') host_instance.terminate() return ami
def create_ami(host_instance, args, config, instance_config, ssh_key, key_filename, instance_data, deploypass, cert, pkey, ami_name_prefix): connection = host_instance.connection setup_fabric_env(instance=host_instance, abort_on_prompts=True, disable_known_hosts=True, key_filename=key_filename) target_name = args.config virtualization_type = config.get("virtualization_type") config_dir = "%s/%s" % (AMI_CONFIGS_DIR, target_name) if ami_name_prefix: prefix = ami_name_prefix else: prefix = args.config dated_target_name = "{}-{}".format( prefix, time.strftime("%Y-%m-%d-%H-%M", time.gmtime())) int_dev_name = config['target']['int_dev_name'] mount_dev = int_dev_name grub_dev = int_dev_name mount_point = config['target']['mount_point'] boot_mount_dev = None host_packages_file = os.path.join(config_dir, "host_packages") packages_file = os.path.join(config_dir, "packages") if os.path.exists(host_packages_file): install_packages(host_packages_file, config.get('distro')) v = attach_and_wait(host_instance, config['target']['size'], config['target']['aws_dev_name'], int_dev_name) # Step 0: install required packages if config.get('distro') == "centos": run('which MAKEDEV >/dev/null || yum -d 1 install -y MAKEDEV') # Step 1: prepare target FS run('mkdir -p %s' % mount_point) if config.get("root_device_type") == "instance-store": # Use file image mount_dev = "/dev/cloud_root/lv_root" grub_dev = "/dev/loop0" boot_mount_dev = "/dev/mapper/loop0p1" img_file = dated_target_name partition_image(mount_dev=mount_dev, int_dev_name=int_dev_name, img_file=img_file) elif virtualization_type == "hvm": # use EBS volume mount_dev = "/dev/cloud_root/lv_root" boot_mount_dev = "%s1" % int_dev_name partition_ebs_volume(int_dev_name=int_dev_name) run('/sbin/mkfs.{fs_type} {args} {dev}'.format( fs_type=config['target']['fs_type'], args=config['target'].get("mkfs_args", ""), dev=mount_dev)) run('/sbin/e2label {dev} {label}'.format( dev=mount_dev, label=config['target']['e2_label'])) run('mount {dev} {mount_point}'.format(dev=mount_dev, mount_point=mount_point)) run('mkdir {0}/dev {0}/proc {0}/etc {0}/boot {0}/sys'.format(mount_point)) run('mount -t sysfs sys %s/sys' % mount_point) if config.get('distro') not in ('debian', 'ubuntu'): run('mount -t proc proc %s/proc' % mount_point) run('for i in console null zero random urandom; ' 'do /sbin/MAKEDEV -d %s/dev -x $i ; done' % mount_point) if boot_mount_dev: run('mount {} {}/boot'.format(boot_mount_dev, mount_point)) # Step 2: install base system if config.get('distro') in ('debian', 'ubuntu'): run("debootstrap precise %s " "http://puppetagain.pub.build.mozilla.org/data/repos/apt/ubuntu/" % mount_point) run('chroot %s mount -t proc none /proc' % mount_point) run('mount -o bind /dev %s/dev' % mount_point) put('%s/releng-public.list' % AMI_CONFIGS_DIR, '%s/etc/apt/sources.list' % mount_point) with lcd(config_dir): put('usr/sbin/policy-rc.d', '%s/usr/sbin/' % mount_point, mirror_local_mode=True) install_packages(packages_file, config.get('distro'), chroot=mount_point) else: with lcd(config_dir): put('etc/yum-local.cfg', '%s/etc/yum-local.cfg' % mount_point) yum = 'yum -d 1 -c {0}/etc/yum-local.cfg -y --installroot={0} '.format( mount_point) # this groupinstall emulates the %packages section of the kickstart # config, which defaults to Core and Base. run('%s groupinstall Core Base' % yum) run('%s clean packages' % yum) # Rebuild RPM DB for cases when versions mismatch run('chroot %s rpmdb --rebuilddb || :' % mount_point) # Step 3: upload custom configuration files run('chroot %s mkdir -p /boot/grub' % mount_point) for directory in ('boot', 'etc', 'usr'): local_directory = os.path.join(config_dir, directory) remote_directory = os.path.join(mount_point, directory) if not os.path.exists(local_directory): pass sync(local_directory, remote_directory) # Step 4: tune configs run('sed -i -e s/@ROOT_DEV_LABEL@/{label}/g -e s/@FS_TYPE@/{fs}/g ' '{mnt}/etc/fstab'.format(label=config['target']['e2_label'], fs=config['target']['fs_type'], mnt=mount_point)) if config.get('distro') in ('debian', 'ubuntu'): if virtualization_type == "hvm": run("chroot {mnt} grub-install {int_dev_name}".format( mnt=mount_point, int_dev_name=int_dev_name)) run("chroot {mnt} update-grub".format(mnt=mount_point)) else: run("chroot {mnt} update-grub -y".format(mnt=mount_point)) run("sed -i 's/^# groot.*/# groot=(hd0)/g' " "{mnt}/boot/grub/menu.lst".format(mnt=mount_point)) run("chroot {mnt} update-grub".format(mnt=mount_point)) else: run('ln -s grub.conf %s/boot/grub/menu.lst' % mount_point) run('ln -s ../boot/grub/grub.conf %s/etc/grub.conf' % mount_point) if config.get('kernel_package') == 'kernel-PAE': run('sed -i s/@VERSION@/`chroot %s rpm -q ' '--queryformat "%%{version}-%%{release}.%%{arch}.PAE" ' '%s | tail -n1`/g %s/boot/grub/grub.conf' % (mount_point, config.get('kernel_package', 'kernel'), mount_point)) else: run('sed -i s/@VERSION@/`chroot %s rpm -q ' '--queryformat "%%{version}-%%{release}.%%{arch}" ' '%s | tail -n1`/g %s/boot/grub/grub.conf' % (mount_point, config.get('kernel_package', 'kernel'), mount_point)) if config.get("root_device_type") == "instance-store": # files normally copied by grub-install run("cp -va /usr/share/grub/x86_64-redhat/* /mnt/boot/grub/") put(os.path.join(config_dir, "grub.cmd"), "/tmp/grub.cmd") run("sed -i s/@IMG@/{}/g /tmp/grub.cmd".format(img_file)) run("cat /tmp/grub.cmd | grub --device-map=/dev/null") elif virtualization_type == "hvm": # See https://bugs.archlinux.org/task/30241 for the details, # grub-nstall doesn't handle /dev/xvd* devices properly grub_install_patch = os.path.join(config_dir, "grub-install.diff") if os.path.exists(grub_install_patch): put(grub_install_patch, "/tmp/grub-install.diff") run('which patch >/dev/null || yum -d 1 install -y patch') run('patch -p0 -i /tmp/grub-install.diff /sbin/grub-install') run("grub-install --root-directory=%s --no-floppy %s" % (mount_point, grub_dev)) run("sed -i -e '/PermitRootLogin/d' -e '/UseDNS/d' " "-e '$ a PermitRootLogin without-password' " "-e '$ a UseDNS no' " "%s/etc/ssh/sshd_config" % mount_point) if config.get('distro') in ('debian', 'ubuntu'): pass else: manage_service("network", mount_point, "on") manage_service("rc.local", mount_point, "on") if config.get("root_device_type") == "instance-store" and \ config.get("distro") == "centos": instance_data = instance_data.copy() instance_data['name'] = host_instance.tags.get("Name") instance_data['hostname'] = host_instance.tags.get("FQDN") run("cp /etc/resolv.conf {}/etc/resolv.conf".format(mount_point)) # make puppet happy # disable ipv6 run("/sbin/service ip6tables stop") # mount /dev to let sshd start run('mount -o bind /dev %s/dev' % mount_point) assimilate_instance(host_instance, instance_config, ssh_key, instance_data, deploypass, chroot=mount_point, reboot=False) ami_cleanup(mount_point=mount_point, distro=config["distro"]) # kill chroot processes put('%s/kill_chroot.sh' % AMI_CONFIGS_DIR, '/tmp/kill_chroot.sh') run('bash /tmp/kill_chroot.sh {}'.format(mount_point)) run('swapoff -a') run('umount %s/dev || :' % mount_point) if config.get("distro") == "ubuntu": run('rm -f %s/usr/sbin/policy-rc.d' % mount_point) run('chroot %s ln -s /sbin/MAKEDEV /dev/' % mount_point) for dev in ('zero', 'null', 'console', 'generic'): run('chroot %s sh -c "cd /dev && ./MAKEDEV %s"' % (mount_point, dev)) run('umount %s/sys || :' % mount_point) run('umount %s/proc || :' % mount_point) run('umount %s/dev || :' % mount_point) run('umount %s/boot || :' % mount_point) run('umount %s' % mount_point) if config.get("root_device_type") == "instance-store" \ and config.get("distro") == "centos": # create bundle run("yum -d 1 install -y ruby " "http://s3.amazonaws.com/ec2-downloads/ec2-ami-tools.noarch.rpm") bundle_location = "{b}/{d}/{t}/{n}".format( b=config["bucket"], d=config["bucket_dir"], t=config["target"]["tags"]["moz-type"], n=dated_target_name) manifest_location = "{}/{}.manifest.xml".format(bundle_location, dated_target_name) run("mkdir -p /mnt-tmp/out") put(cert, "/mnt-tmp/cert.pem") put(pkey, "/mnt-tmp/pk.pem") run("ec2-bundle-image -c /mnt-tmp/cert.pem -k /mnt-tmp/pk.pem " "-u {uid} -i /mnt-tmp/{img_file} -d /mnt-tmp/out -r x86_64".format( img_file=img_file, uid=config["aws_user_id"])) with hide('running', 'stdout', 'stderr'): log.info("uploading bundle") run("ec2-upload-bundle -b {bundle_location}" " --access-key {access_key} --secret-key {secret_key}" " --region {region}" " -m /mnt-tmp/out/{img_file}.manifest.xml --retry".format( bundle_location=bundle_location, access_key=boto.config.get("Credentials", "aws_access_key_id"), secret_key=boto.config.get("Credentials", "aws_secret_access_key"), region=connection.region.name, img_file=img_file)) v.detach(force=True) wait_for_status(v, "status", "available", "update") if not config.get("root_device_type") == "instance-store": # Step 5: Create a snapshot log.info('Creating a snapshot') snapshot = v.create_snapshot(dated_target_name) wait_for_status(snapshot, "status", "completed", "update") snapshot.add_tag('Name', dated_target_name) snapshot.add_tag('moz-created', str(int(time.mktime(time.gmtime())))) # Step 6: Create an AMI log.info('Creating AMI') if config.get("root_device_type") == "instance-store": ami_id = connection.register_image( dated_target_name, '%s AMI' % dated_target_name, architecture=config['arch'], virtualization_type=virtualization_type, image_location=manifest_location, ) else: host_img = connection.get_image(config['ami']) block_map = BlockDeviceMapping() block_map[host_img.root_device_name] = BlockDeviceType( snapshot_id=snapshot.id) root_device_name = host_img.root_device_name if virtualization_type == "hvm": kernel_id = None ramdisk_id = None else: kernel_id = host_img.kernel_id ramdisk_id = host_img.ramdisk_id ami_id = connection.register_image( dated_target_name, '%s AMI' % dated_target_name, architecture=config['arch'], kernel_id=kernel_id, ramdisk_id=ramdisk_id, root_device_name=root_device_name, block_device_map=block_map, virtualization_type=virtualization_type, ) while True: try: ami = connection.get_image(ami_id) ami.add_tag('Name', dated_target_name) ami.add_tag('moz-created', str(int(time.mktime(time.gmtime())))) if config["target"].get("tags"): for tag, value in config["target"]["tags"].items(): log.info("Tagging %s: %s", tag, value) ami.add_tag(tag, value) log.info('AMI created') log.info('ID: {id}, name: {name}'.format(id=ami.id, name=ami.name)) break except: log.info('Wating for AMI') time.sleep(10) # Step 7: Cleanup if not args.keep_volume: log.info('Deleting volume') v.delete() if not args.keep_host_instance: log.info('Terminating host instance') host_instance.terminate() return ami
def test_public(): instance = mock.Mock() instance.vpc_id = None instance.public_dns_name = "a2" setup_fabric_env(instance=instance, user="******", key_filename="k1") assert env.host_string == "a2"
def test_generic(): instance = mock.Mock() setup_fabric_env(instance=instance, user="******", key_filename="k1") assert env.abort_on_prompts assert env.disable_known_hosts
def test_vpc(): instance = mock.Mock() instance.vpc_id = "vpc1" instance.private_ip_address = "a1" setup_fabric_env(instance=instance, user="******", key_filename="k1") assert env.host_string == "a1"