def get_metadata(self): metadata = cloudformation.Metadata( cloudformation.Init( cloudformation.InitConfigSets(default=['install_and_run']), install_and_run=cloudformation.InitConfig(commands={ '01-startup': { 'command': 'echo hello world' }, }))) return metadata
def get_metadata(self): metadata = cloudformation.Metadata( cloudformation.Init( cloudformation.InitConfigSets(default=['install_and_run']), install_and_run=cloudformation.InitConfig( commands={ '01-startup': { 'command': 'nohup python -m SimpleHTTPServer 8000 &' }, }))) return metadata
def add_cfn_init(): return cloudformation.Metadata( cloudformation.Init( cloudformation.InitConfigSets(ascending=['config'], descending=['config']), config=cloudformation.InitConfig( commands={ 'test': { 'command': 'echo "$CFNTEST" > text.txt', 'env': { 'CFNTEST': 'I come from config.' }, 'cwd': '~' } })))
def Meta(name, private_ip): return cfn.Metadata( cfn.Authentication({ "default": cfn.AuthenticationBlock(type="S3", roleName=Ref(InstanceRole), buckets=[ Ref(Bucket) ]) }), cfn.Init( cfn.InitConfigSets(default = ['SetupHost','SetupWebsite']), SetupHost = cfn.InitConfig( files = { "/etc/hostname":{ "content": Join(".",[ name, Ref(HostedZone) ]) }, "/root/set-hostname.sh":{ "content": Join("",[ "#!/bin/bash\n", "hostname --file /etc/hostname\n", "h=$(cat /etc/hostname)\n", "sed -i s/HOSTNAME=.*/HOSTNAME=$h/g /etc/sysconfig/network\n", "echo ", private_ip , " $h >>/etc/hosts \n", "service network restart" ]), "mode": "755" }, }, commands={ "1-set-hostname": { "command": "/root/set-hostname.sh " } } ), SetupWebsite = cfn.InitConfig( packages = { "yum" : { 'httpd' : []} }, sources = { "/var/www/html/": Join("", [ "https://", Ref(Bucket), ".s3.amazonaws.com/3dstreetartindia.zip" ]) }, services = { "sysvinit" : { "httpd" : { "enabled" : "true", "ensureRunning" : "true" }, } } ) ))
def add_init(target, *configs): assert isinstance(target, (ec2.Instance, au.LaunchConfiguration)) params = Join('', [ 'export CFN_PARAMS=\'', ' --region ', Ref('AWS::Region'), ' --stack ', Ref('AWS::StackName'), ' --resource ' + target.title + '\'', ]) target.UserData = Base64( Join('\n', [ '#!/bin/bash -xe', 'yum update -y', params, '/opt/aws/bin/cfn-init -v -c default $CFN_PARAMS', '/opt/aws/bin/cfn-signal -e 0 $CFN_PARAMS' ])) configs = [callable(c) and c() or c for c in configs] target.Metadata = cf.Init( cf.InitConfigSets(default=[c.title for c in configs]), **{c.title: c for c in configs}) return target
def buildInstance(t, args): t.add_resource( ec2.SecurityGroup('WebserverSG', GroupDescription='Global Webserver Access', VpcId=Ref('VPC'), Tags=Tags(Name='Global Webserver Access'))) t.add_resource( ec2.SecurityGroupIngress('WebserverSGIngress1', GroupId=Ref('WebserverSG'), IpProtocol='tcp', CidrIp='0.0.0.0/0', FromPort='22', ToPort='22')) t.add_resource( ec2.SecurityGroupIngress('WebserverSGIngress2', GroupId=Ref('WebserverSG'), IpProtocol='tcp', CidrIp='0.0.0.0/0', FromPort='80', ToPort='80')) t.add_resource( ec2.SecurityGroupIngress('WebserverSGIngress3', GroupId=Ref('WebserverSG'), IpProtocol='tcp', CidrIp='0.0.0.0/0', FromPort='443', ToPort='443')) rolePolicyStatements = [{ "Sid": "Stmt1500699052003", "Effect": "Allow", "Action": ["s3:ListBucket"], "Resource": [Join("", ["arn:aws:s3:::", Ref('S3Bucket')])] }, { "Sid": "Stmt1500699052000", "Effect": "Allow", "Action": ["s3:PutObject", "s3:GetObject", "s3:DeleteObject"], "Resource": [Join("", ["arn:aws:s3:::", Ref('S3Bucket'), '/Backup/*'])] }, { "Sid": "Stmt1500612724002", "Effect": "Allow", "Action": ["kms:Encrypt", "kms:Decrypt", "kms:GenerateDataKey*"], "Resource": [OpenEMRKeyARN] }] t.add_resource( iam.ManagedPolicy('WebserverPolicy', Description='Policy for webserver instance', PolicyDocument={ "Version": "2012-10-17", "Statement": rolePolicyStatements })) t.add_resource( iam.Role('WebserverRole', AssumeRolePolicyDocument={ "Version": "2012-10-17", "Statement": [{ "Effect": "Allow", "Principal": { "Service": ["ec2.amazonaws.com"] }, "Action": ["sts:AssumeRole"] }] }, Path='/', ManagedPolicyArns=[Ref('WebserverPolicy')])) t.add_resource( iam.InstanceProfile('WebserverInstanceProfile', Path='/', Roles=[Ref('WebserverRole')])) t.add_resource( ec2.Volume('DockerVolume', DeletionPolicy='Delete' if args.dev else 'Snapshot', Size=Ref('PracticeStorage'), AvailabilityZone=Select("0", GetAZs("")), VolumeType='gp2', Encrypted=True, KmsKeyId=OpenEMRKeyID, Tags=Tags(Name="OpenEMR Practice"))) bootstrapScript = [ "#!/bin/bash -x\n", "exec > /tmp/part-001.log 2>&1\n", "apt-get -y update\n", "apt-get -y install python-pip\n", "pip install https://s3.amazonaws.com/cloudformation-examples/aws-cfn-bootstrap-latest.tar.gz\n", "cfn-init -v ", " --stack ", ref_stack_name, " --resource WebserverInstance ", " --configsets Setup ", " --region ", ref_region, "\n", "cfn-signal -e $? ", " --stack ", ref_stack_name, " --resource WebserverInstance ", " --region ", ref_region, "\n" ] setupScript = [ "#!/bin/bash -xe\n", "exec > /tmp/cloud-setup.log 2>&1\n", "DEBIAN_FRONTEND=noninteractive apt-get dist-upgrade -y -o Dpkg::Options::=\"--force-confdef\" -o Dpkg::Options::=\"--force-confold\" --force-yes\n", "mkfs -t ext4 /dev/xvdd\n", "mkdir /mnt/docker\n", "cat /root/fstab.append >> /etc/fstab\n", "mount /mnt/docker\n", "ln -s /mnt/docker /var/lib/docker\n", "apt-get -y install python-boto awscli\n", "S3=", Ref('S3Bucket'), "\n", "KMS=", OpenEMRKeyID, "\n", "touch /root/cloud-backups-enabled\n", "echo $S3 > /root/.cloud-s3.txt\n", "echo $KMS > /root/.cloud-kms.txt\n", "touch /tmp/mypass\n", "chmod 500 /tmp/mypass\n", "openssl rand -base64 32 >> /tmp/mypass\n", "aws s3 cp /tmp/mypass s3://$S3/Backup/passphrase.txt --sse aws:kms --sse-kms-key-id $KMS\n", "rm /tmp/mypass\n", "curl -L https://raw.githubusercontent.com/openemr/openemr-devops/master/packages/lightsail/launch.sh > /root/launch.sh\n", "chmod +x /root/launch.sh && /root/launch.sh -s 0\n" ] fstabFile = ["/dev/xvdd /mnt/docker ext4 defaults,nofail 0 0\n"] bootstrapInstall = cloudformation.InitConfig( files={ "/root/cloud-setup.sh": { "content": Join("", setupScript), "mode": "000500", "owner": "root", "group": "root" }, "/root/fstab.append": { "content": Join("", fstabFile), "mode": "000400", "owner": "root", "group": "root" } }, commands={"01_setup": { "command": "/root/cloud-setup.sh" }}) bootstrapMetadata = cloudformation.Metadata( cloudformation.Init(cloudformation.InitConfigSets(Setup=['Install']), Install=bootstrapInstall)) t.add_resource( ec2.Instance('WebserverInstance', Metadata=bootstrapMetadata, ImageId=FindInMap('RegionData', ref_region, 'UbuntuAMI'), InstanceType=Ref('InstanceSize'), NetworkInterfaces=[ ec2.NetworkInterfaceProperty( AssociatePublicIpAddress=True, DeviceIndex="0", GroupSet=[Ref('WebserverSG')], SubnetId=Ref('PublicSubnet1')) ], KeyName=Ref('EC2KeyPair'), IamInstanceProfile=Ref('WebserverInstanceProfile'), Volumes=[{ "Device": "/dev/sdd", "VolumeId": Ref('DockerVolume') }], Tags=Tags(Name='OpenEMR Express Plus'), InstanceInitiatedShutdownBehavior='stop', UserData=Base64(Join('', bootstrapScript)), CreationPolicy={"ResourceSignal": { "Timeout": "PT25M" }})) return t
def buildInstance(t, args): t.add_resource( ec2.SecurityGroup('WebserverIngressSG', GroupDescription='Global Webserver Access', VpcId=Ref('VPC'), Tags=Tags(Name='Global Webserver Access'))) t.add_resource( ec2.SecurityGroupIngress('WebserverIngressSG80', GroupId=Ref('WebserverIngressSG'), IpProtocol='tcp', CidrIp='0.0.0.0/0', FromPort='80', ToPort='80')) t.add_resource( ec2.SecurityGroupIngress('WebserverIngress443', GroupId=Ref('WebserverIngressSG'), IpProtocol='tcp', CidrIp='0.0.0.0/0', FromPort='443', ToPort='443')) t.add_resource( ec2.SecurityGroup('SysAdminAccessSG', GroupDescription='System Administrator Access', VpcId=Ref('VPC'), Tags=Tags(Name='System Administrator Access'))) if (args.dev): t.add_resource( ec2.SecurityGroupIngress('DevSysadminIngress22', GroupId=Ref('SysAdminAccessSG'), IpProtocol='tcp', CidrIp='0.0.0.0/0', FromPort='22', ToPort='22')) rolePolicyStatements = [{ "Sid": "Stmt1500699052003", "Effect": "Allow", "Action": ["s3:ListBucket"], "Resource": [Join("", ["arn:aws:s3:::", Ref('S3Bucket')])] }, { "Sid": "Stmt1500699052000", "Effect": "Allow", "Action": ["s3:PutObject", "s3:GetObject", "s3:DeleteObject"], "Resource": [Join("", ["arn:aws:s3:::", Ref('S3Bucket'), '/Backup/*'])] }, { "Sid": "Stmt1500612724002", "Effect": "Allow", "Action": ["kms:Encrypt", "kms:Decrypt", "kms:GenerateDataKey*"], "Resource": [OpenEMRKeyARN] }] if (args.recovery): rolePolicyStatements.extend([ { "Sid": "Stmt1500699052004", "Effect": "Allow", "Action": ["s3:ListBucket"], "Resource": [Join( "", ["arn:aws:s3:::", Ref('RecoveryS3Bucket')])] }, { "Sid": "Stmt1500699052005", "Effect": "Allow", "Action": [ "s3:GetObject", ], "Resource": [ Join("", [ "arn:aws:s3:::", Ref('RecoveryS3Bucket'), '/Backup/*' ]) ] }, ]) t.add_resource( iam.ManagedPolicy('WebserverPolicy', Description='Policy for webserver instance', PolicyDocument={ "Version": "2012-10-17", "Statement": rolePolicyStatements })) t.add_resource( iam.Role('WebserverRole', AssumeRolePolicyDocument={ "Version": "2012-10-17", "Statement": [{ "Effect": "Allow", "Principal": { "Service": ["ec2.amazonaws.com"] }, "Action": ["sts:AssumeRole"] }] }, Path='/', ManagedPolicyArns=[Ref('WebserverPolicy')])) t.add_resource( iam.InstanceProfile('WebserverInstanceProfile', Path='/', Roles=[Ref('WebserverRole')])) t.add_resource( ec2.Volume('DockerVolume', DeletionPolicy='Delete' if args.dev else 'Snapshot', Size=Ref('PracticeStorage'), AvailabilityZone=Select("0", GetAZs("")), VolumeType='gp2', Encrypted=True, KmsKeyId=OpenEMRKeyID, Tags=Tags(Name="OpenEMR Practice"))) bootstrapScript = [ "#!/bin/bash -x\n", "exec > /var/log/openemr-cfn-bootstrap 2>&1\n", "cfn-init -v ", " --stack ", ref_stack_name, " --resource WebserverInstance ", " --configsets Setup ", " --region ", ref_region, "\n", "cfn-signal -e $? ", " --stack ", ref_stack_name, " --resource WebserverInstance ", " --region ", ref_region, "\n" ] setupScript = [ "#!/bin/bash -xe\n", "exec > /tmp/cloud-setup.log 2>&1\n", "/root/openemr-devops/packages/standard/ami/ami-configure.sh\n" ] stackPassthroughFile = [ "S3=", Ref('S3Bucket'), "\n", "KMS=", OpenEMRKeyID, "\n" ] if (args.recovery): stackPassthroughFile.extend([ "RECOVERYS3=", Ref('RecoveryS3Bucket'), "\n", "RECOVERY_NEWRDS=", GetAtt('RDSInstance', 'Endpoint.Address'), "\n", ]) if (args.recovery): dockerComposeFile = [ "version: '3.1'\n", "services:\n", " openemr:\n", " restart: always\n", " image: openemr/openemr", docker_version, "\n", " ports:\n", " - 80:80\n", " - 443:443\n", " volumes:\n", " - logvolume01:/var/log\n", " - sitevolume:/var/www/localhost/htdocs/openemr/sites\n", " environment:\n", " MANUAL_SETUP: 1\n", "volumes:\n", " logvolume01: {}\n", " sitevolume: {}\n" ] else: dockerComposeFile = [ "version: '3.1'\n", "services:\n", " openemr:\n", " restart: always\n", " image: openemr/openemr", docker_version, "\n", " ports:\n", " - 80:80\n", " - 443:443\n", " volumes:\n", " - logvolume01:/var/log\n", " - sitevolume:/var/www/localhost/htdocs/openemr/sites\n", " environment:\n", " MYSQL_HOST: '", GetAtt('RDSInstance', 'Endpoint.Address'), "'\n", " MYSQL_ROOT_USER: openemr\n", " MYSQL_ROOT_PASS: '******'RDSPassword'), "'\n", " MYSQL_USER: openemr\n", " MYSQL_PASS: '******'RDSPassword'), "'\n", " OE_USER: admin\n", " OE_PASS: '******'AdminPassword'), "'\n", "volumes:\n", " logvolume01: {}\n", " sitevolume: {}\n" ] bootstrapInstall = cloudformation.InitConfig( files={ "/root/cloud-setup.sh": { "content": Join("", setupScript), "mode": "000500", "owner": "root", "group": "root" }, "/root/cloud-variables": { "content": Join("", stackPassthroughFile), "mode": "000500", "owner": "root", "group": "root" }, "/root/openemr-devops/packages/standard/docker-compose.yaml": { "content": Join("", dockerComposeFile), "mode": "000500", "owner": "root", "group": "root" } }, commands={"01_setup": { "command": "/root/cloud-setup.sh" }}) bootstrapMetadata = cloudformation.Metadata( cloudformation.Init(cloudformation.InitConfigSets(Setup=['Install']), Install=bootstrapInstall)) t.add_resource( ec2.Instance('WebserverInstance', Metadata=bootstrapMetadata, ImageId=FindInMap('RegionData', ref_region, 'OpenEMRMktPlaceAMI'), InstanceType=Ref('WebserverInstanceSize'), NetworkInterfaces=[ ec2.NetworkInterfaceProperty( AssociatePublicIpAddress=True, DeviceIndex="0", GroupSet=[ Ref('ApplicationSecurityGroup'), Ref('WebserverIngressSG'), Ref('SysAdminAccessSG') ], SubnetId=Ref('PublicSubnet1')) ], KeyName=Ref('EC2KeyPair'), IamInstanceProfile=Ref('WebserverInstanceProfile'), Volumes=[{ "Device": "/dev/sdd", "VolumeId": Ref('DockerVolume') }], Tags=Tags(Name='OpenEMR Cloud Standard'), InstanceInitiatedShutdownBehavior='stop', UserData=Base64(Join('', bootstrapScript)), CreationPolicy={"ResourceSignal": { "Timeout": "PT15M" }})) return t
--configsets Bootstrap \ --region ${AWS::Region} /opt/aws/bin/cfn-signal -e $? \ --stack ${AWS::StackName} \ --resource %(INSTANCE_NAME)s \ --region ${AWS::Region} ''' % {'INSTANCE_NAME': instance_resource_name})) instance_metadata = cloudformation.Metadata( cloudformation.Init( cloudformation.InitConfigSets( Bootstrap=[ 'ConfigCFNTools', # 'InstallPackages', ], Update=[ 'ConfigCFNTools', # 'InstallPackages', ], ), ConfigCFNTools=cloudformation.InitConfig( files={ '/etc/cfn/cfn-hup.conf': { 'content': Sub( '[main]\n' 'stack=${AWS::StackId}\n' 'region=${AWS::Region}\n' 'interval=5\n' 'verbose=false\n' ), 'mode': '000400',
def add_autoscaling_group(self): t = self.template self.asgLaunchConfig = t.add_resource( LaunchConfiguration( 'ASGLaunchConfig', ImageId='ami-0b33d91d', #TODO Mapping for different regions InstanceMonitoring=False, AssociatePublicIpAddress=False, InstanceType="t2.micro", SecurityGroups=[Ref(self.asgSg)], KeyName=Ref(self.keyPairParam), UserData=Base64( Join( "", [ "#!/bin/bash -xe\n", "yum update -y aws-cfn-bootstrap\n", "/opt/aws/bin/cfn-init -v ", " --stack ", { "Ref": "AWS::StackName" }, " --resource LaunchConfig ", " --configsets wordpress_install ", " --region ", { "Ref": "AWS::Region" }, "\n", # "/opt/aws/bin/cfn-signal -e $? ", # " --stack ", { "Ref" : "AWS::StackName" }, # " --resource WebServerGroup ", # " --region ", { "Ref" : "AWS::Region" }, "\n" ])), Metadata=cfn.Metadata( cfn.Init( cfn.InitConfigSets(wordpress_install=[ 'install_cfn', 'install_chefdk', "install_chef", "install_wordpress", "run_chef" ]), install_cfn=cfn.InitConfig( # Starts cfn-hup daemon which detects changes in metadata # and runs user-specified actions when a change is detected. # This allows configuration updates through UpdateStack. # The cfn-hup.conf file stores the name of the stack and # the AWS credentials that the cfn-hup daemon targets. # The cfn-hup daemon parses and loads each file in the /etc/cfn/hooks.d directory. files={ "/etc/cfn/cfn-hup.conf": { "content": { "Fn::Join": [ "", [ "[main]\n", "stack=", { "Ref": "AWS::StackId" }, "\n", "region=", { "Ref": "AWS::Region" }, "\n" ] ] }, "mode": "000400", "owner": "root", "group": "root" }, "/etc/cfn/hooks.d/cfn-auto-reloader.conf": { "content": { "Fn::Join": [ "", [ "[cfn-auto-reloader-hook]\n", "triggers=post.update\n", "path=Resources.LaunchConfig.Metadata.AWS::CloudFormation::Init\n", "action=/opt/aws/bin/cfn-init -v ", " --stack ", { "Ref": "AWS::StackName" }, " --resource LaunchConfig ", " --configsets wordpress_install ", " --region ", { "Ref": "AWS::Region" }, "\n" ] ] }, "mode": "000400", "owner": "root", "group": "root" } }, services={ "sysvinit": { "cfn-hup": { "enabled": "true", "ensureRunning": "true", "files": [ "/etc/cfn/cfn-hup.conf", "/etc/cfn/hooks.d/cfn-auto-reloader.conf" ] } } }), install_chefdk=cfn.InitConfig( packages={ "rpm": { "chefdk": "https://opscode-omnibus-packages.s3.amazonaws.com/el/6/x86_64/chefdk-0.2.0-2.el6.x86_64.rpm" } }), install_chef=cfn.InitConfig( sources={ # Set up a local Chef repository on the instance. "/var/chef/chef-repo": "http://github.com/opscode/chef-repo/tarball/master" }, files={ # Chef installation file. "/tmp/install.sh": { "source": "https://www.opscode.com/chef/install.sh", "mode": "000400", "owner": "root", "group": "root" }, # Knife configuration file. "/var/chef/chef-repo/.chef/knife.rb": { "content": { "Fn::Join": [ "", [ "cookbook_path [ '/var/chef/chef-repo/cookbooks' ]\n", "node_path [ '/var/chef/chef-repo/nodes' ]\n" ] ] }, "mode": "000400", "owner": "root", "group": "root" }, # Chef client configuration file. "/var/chef/chef-repo/.chef/client.rb": { "content": { "Fn::Join": [ "", [ "cookbook_path [ '/var/chef/chef-repo/cookbooks' ]\n", "node_path [ '/var/chef/chef-repo/nodes' ]\n" ] ] }, "mode": "000400", "owner": "root", "group": "root" } }, commands={ # make the /var/chef directory readable, run the # Chef installation, and then start Chef local mode # by using the client.rb file that was created. # The commands are run in alphanumeric order. "01_make_chef_readable": { "command": "chmod +rx /var/chef" }, "02_install_chef": { "command": "bash /tmp/install.sh", "cwd": "/var/chef" }, "03_create_node_list": { "command": "chef-client -z -c /var/chef/chef-repo/.chef/client.rb", "cwd": "/var/chef/chef-repo", "env": { "HOME": "/var/chef" } } }), install_wordpress=cfn.InitConfig( # Installs WordPress by using a WordPress cookbook. files={ # knife.rb and client.rb files are overwritten to # point to the cookbooks that are required to install WordPress. "/var/chef/chef-repo/.chef/knife.rb": { "content": { "Fn::Join": [ "", [ "cookbook_path [ '/var/chef/chef-repo/cookbooks/wordpress/berks-cookbooks' ]\n", "node_path [ '/var/chef/chef-repo/nodes' ]\n" ] ] }, "mode": "000400", "owner": "root", "group": "root" }, "/var/chef/chef-repo/.chef/client.rb": { "content": { "Fn::Join": [ "", [ "cookbook_path [ '/var/chef/chef-repo/cookbooks/wordpress/berks-cookbooks' ]\n", "node_path [ '/var/chef/chef-repo/nodes' ]\n" ] ] }, "mode": "000400", "owner": "root", "group": "root" }, # Specify the Amazon RDS database instance as the WordPress database "/var/chef/chef-repo/cookbooks/wordpress/attributes/aws_rds_config.rb": { "content": { "Fn::Join": [ "", [ "normal['wordpress']['db']['pass'] = '******'\n", "normal['wordpress']['db']['user'] = '******'\n", "normal['wordpress']['db']['host'] = '", GetAtt(self.rds, "Endpoint.Address"), "'\n", "normal['wordpress']['db']['name'] = '", Ref(self.dbNameParam), "'\n" ] ] }, "mode": "000400", "owner": "root", "group": "root" } }, commands={ "01_get_cookbook": { "command": "knife cookbook site download wordpress", "cwd": "/var/chef/chef-repo", "env": { "HOME": "/var/chef" } }, "02_unpack_cookbook": { "command": "tar xvfz /var/chef/chef-repo/wordpress*", "cwd": "/var/chef/chef-repo/cookbooks" }, "03_init_berkshelf": { "command": "berks init /var/chef/chef-repo/cookbooks/wordpress --skip-vagrant --skip-git", "cwd": "/var/chef/chef-repo/cookbooks/wordpress", "env": { "HOME": "/var/chef" } }, "04_vendorize_berkshelf": { "command": "berks vendor", "cwd": "/var/chef/chef-repo/cookbooks/wordpress", "env": { "HOME": "/var/chef" } }, "05_configure_node_run_list": { "command": "knife node run_list add -z `knife node list -z` recipe[wordpress]", "cwd": "/var/chef/chef-repo", "env": { "HOME": "/var/chef" } } }), run_chef=cfn.InitConfig( commands={ "01_run_chef_client": { "command": "chef-client -z -c /var/chef/chef-repo/.chef/client.rb", "cwd": "/var/chef/chef-repo", "env": { "HOME": "/var/chef" } } }))))) webserverSubnetIds = [ self.sceptreUserData['subnets']['privateWebAZ1Id'], self.sceptreUserData['subnets']['privateWebAZ2Id'], self.sceptreUserData['subnets']['privateWebAZ3Id'] ] self.webServerASG = t.add_resource( AutoScalingGroup( 'WebServerASG', LaunchConfigurationName=Ref(self.asgLaunchConfig), LoadBalancerNames=[Ref(self.elb)], MinSize='1', DesiredCapacity='2', Cooldown='1', MaxSize='5', UpdatePolicy=UpdatePolicy( AutoScalingRollingUpdate=AutoScalingRollingUpdate( MinInstancesInService="1")), VPCZoneIdentifier=webserverSubnetIds, Tags=[ ASTag('Contact', Ref(self.ownerEmailParam), True), ASTag('Name', Join("", [self.namePrefix, 'ASG']), True) ])) return 0
def add_launch_template(template, hosts_sg): """Function to create a launch template. :param template: ECS Cluster template :type template: troposphere.Template :param hosts_sg: security group for the EC2 hosts :type hosts_sg: troposphere.ec2.SecurityGroup :return: launch_template :rtype: troposphere.ec2.LaunchTemplate """ # from troposphere.cloudformation import ( # WaitCondition, WaitConditionHandle # ) # Deactivated conditions given you could run with no EC2 at all. # Tricky condition to do as the WaitCondition and Handler cannot be created on a CFN Update, but only at the # very creation of the stack. # wait_handle = WaitConditionHandle( # 'BootstrapHandle', # template=template # ) # WaitCondition( # 'BootStrapCondition', # template=template, # DependsOn=[hosts_role], # Handle=Ref(wait_handle), # Timeout='900' # ) launch_template = LaunchTemplate( "LaunchTemplate", template=template, Metadata=cloudformation.Metadata( cloudformation.Init( cloudformation.InitConfigSets( default=["awspackages", "dockerconfig", "ecsconfig", "awsservices"] ), awspackages=cloudformation.InitConfig( packages={"yum": {"awslogs": [], "amazon-ssm-agent": []}}, commands={ "001-check-packages": {"command": "rpm -qa | grep amazon"}, "002-check-packages": {"command": "rpm -qa | grep aws"}, }, ), awsservices=cloudformation.InitConfig( services={ "sysvinit": { "amazon-ssm-agent": {"enabled": True, "ensureRunning": True} } } ), dockerconfig=cloudformation.InitConfig( commands={ "001-stop-docker": {"command": "systemctl stop docker"}, "098-reload-systemd": {"command": "systemctl daemon-reload"}, }, files={ "/etc/sysconfig/docker": { "owner": "root", "group": "root", "mode": "644", "content": Join( "\n", [ "DAEMON_MAXFILES=1048576", Join( " ", ["OPTIONS=--default-ulimit nofile=1024:4096"], ), "DAEMON_PIDFILE_TIMEOUT=10", "#EOF", "", ], ), } }, services={ "sysvinit": { "docker": { "enabled": True, "ensureRunning": True, "files": ["/etc/sysconfig/docker"], "commands": ["098-reload-systemd"], } } }, ), ecsconfig=cloudformation.InitConfig( files={ "/etc/ecs/ecs.config": { "owner": "root", "group": "root", "mode": "644", "content": Join( "\n", [ Sub(f"ECS_CLUSTER=${{{CLUSTER_NAME_T}}}"), "ECS_ENABLE_TASK_IAM_ROLE=true", "ECS_ENABLE_SPOT_INSTANCE_DRAINING=true", "ECS_ENABLE_TASK_IAM_ROLE_NETWORK_HOST=true", "ECS_ENABLE_CONTAINER_METADATA=true", "ECS_ENABLE_UNTRACKED_IMAGE_CLEANUP=true", "ECS_UPDATES_ENABLED=true", "ECS_ENGINE_TASK_CLEANUP_WAIT_DURATION=15m", "ECS_IMAGE_CLEANUP_INTERVAL=10m", "ECS_NUM_IMAGES_DELETE_PER_CYCLE=100", "ECS_ENABLE_TASK_ENI=true", "ECS_AWSVPC_BLOCK_IMDS=true", "ECS_TASK_METADATA_RPS_LIMIT=300,400", "ECS_ENABLE_AWSLOGS_EXECUTIONROLE_OVERRIDE=true", 'ECS_AVAILABLE_LOGGING_DRIVERS=["awslogs", "json-file"]', "#EOF", ], ), } }, commands={ "0001-restartecs": { "command": "systemctl --no-block restart ecs" } }, ), ) ), LaunchTemplateData=LaunchTemplateData( BlockDeviceMappings=[ LaunchTemplateBlockDeviceMapping( DeviceName="/dev/xvda", Ebs=EBSBlockDevice(DeleteOnTermination=True, Encrypted=True), ) ], ImageId=Ref(compute_params.ECS_AMI_ID), InstanceInitiatedShutdownBehavior="terminate", IamInstanceProfile=IamInstanceProfile( Arn=Sub(f"${{{HOST_PROFILE_T}.Arn}}") ), TagSpecifications=[ TagSpecifications( ResourceType="instance", Tags=Tags( Name=Sub(f"EcsNodes-${{{CLUSTER_NAME_T}}}"), StackName=Ref("AWS::StackName"), StackId=Ref("AWS::StackId"), ), ) ], InstanceType="m5a.large", Monitoring=Monitoring(Enabled=True), SecurityGroupIds=[GetAtt(hosts_sg, "GroupId")], UserData=Base64( Join( "\n", [ "#!/usr/bin/env bash", "export PATH=$PATH:/opt/aws/bin", "cfn-init -v || yum install aws-cfn-bootstrap -y", Sub( f"cfn-init --region ${{AWS::Region}} -r LaunchTemplate -s ${{AWS::StackName}}" ), # 'if [ $? -ne 0 ]; then', # Sub(f'cfn-signal -e 1 -r "Failed to bootstrap" \'${{{wait_handle.title}}}\''), # 'halt', # 'else', # Sub(f'cfn-signal -e 0 -r "Successfully bootstrapped" \'${{{wait_handle.title}}}\''), # 'fi', "# EOF", ], ) ), ), LaunchTemplateName=Ref(CLUSTER_NAME_T), ) return launch_template
def to_cloudformation_template(self, base_template): instance = ec2.Instance(self.name) instance.InstanceType = 't2.nano' instance.ImageId = IMAGE_ID base_template.add_resource(instance) if self.bootstrap_file_contents: newrelic_license_param = base_template.add_parameter(Parameter( "NewRelicLicenseKey", Description="Value of your New Relic License Key", Type="String", )) instance.UserData = CloudFormationHelper.create_user_data(self.bootstrap_file_contents, self.name) instance.Metadata = cloudformation.Metadata( cloudformation.Init( cloudformation.InitConfigSets( default=['new_relic'] ), new_relic=cloudformation.InitConfig( commands={ 'write_dollop_version': { 'command': 'echo "$DOLLOP_VERSION" > dollop_init.txt', 'env': { 'DOLLOP_VERSION': __version__ }, 'cwd': '~' }, 'configure_new_relic': { 'command': Join('', ['nrsysmond-config --set license_key=', Ref(newrelic_license_param)]) } }, services={ 'sysvinit': { 'newrelic-sysmond': { 'enabled': 'true', 'ensureRunning': 'true' } } } ) ) ) if SSH_PORT in self.open_ports: keyname_param = base_template.add_parameter(Parameter( "EC2KeyPair", Description="Name of an existing EC2 KeyPair to enable SSH access to the instance", Type="AWS::EC2::KeyPair::KeyName", )) security_group = base_template.add_resource(ec2.SecurityGroup( 'DollopServerSecurityGroup', GroupDescription='Dollop-generated port access rules for an EC2 instance', SecurityGroupIngress=CloudFormationHelper.create_security_group_rules(self.open_ports), Tags=Tags(Name='ops.dollop.resource.sg')) ) instance.KeyName = Ref(keyname_param) instance.SecurityGroups = [Ref(security_group)] # Template Output base_template.add_output([ Output( "InstanceId", Description="InstanceId of the newly created EC2 instance", Value=Ref(instance), ), Output( "AZ", Description="Availability Zone of the newly created EC2 instance", Value=GetAtt(instance, "AvailabilityZone"), ), Output( "PublicIP", Description="Public IP address of the newly created EC2 instance", Value=GetAtt(instance, "PublicIp"), ), Output( "PrivateIP", Description="Private IP address of the newly created EC2 instance", Value=GetAtt(instance, "PrivateIp"), ), Output( "PublicDNS", Description="Public DNS Name of the newly created EC2 instance", Value=GetAtt(instance, "PublicDnsName"), ), Output( "PrivateDNS", Description="Private DNS Name of the newly created EC2 instance", Value=GetAtt(instance, "PrivateDnsName"), ), ]) instance.Tags = Tags(Name=DollopServer.DefaultTag) return base_template
def add_ec2_instance(self): self._resources.update({ 'Ec2Instance': ec2.Instance( 'Ec2Instance', ImageId=FindInMap("RegionMap", Ref("AWS::Region"), "AMI"), InstanceType=Ref(self._parameters['Ec2InstanceType']), KeyName=Ref(self._parameters['SshKeyName']), NetworkInterfaces=[ ec2.NetworkInterfaceProperty( GroupSet=[ Ref(self._resources['Ec2InstanceSecurityGroup']), ], AssociatePublicIpAddress='true', DeviceIndex='0', DeleteOnTermination='true', SubnetId=Ref(self._parameters['SubnetId']), ), ], UserData=Base64(Join( '', [ '#!/bin/bash\n', '# Install the files and packages from the metadata\n', '/usr/local/bin/cfn-init -v ', ' --stack ', self._stack_name, ' --resource Ec2Instance ', ' --configsets InstallAndConfigure ', ' --region ', self._region, '\n', # Add a temporary /usr/local/bin/streamlit so # user knows its still installing. 'echo -e \'#!/bin/sh\necho Streamlit is still installing. Please try again in a few minutes.\n\' > /usr/local/bin/streamlit \n', 'chmod +x /usr/local/bin/streamlit \n', # Create ~/sshfs dir which is the target of the sshfs mount commmand 'install -o ubuntu -g ubuntu -m 755 -d ~ubuntu/sshfs \n', # Install streamlit. '/home/ubuntu/anaconda3/bin/pip install streamlit \n', # Install rmate. 'curl -o /usr/local/bin/rmate https://raw.githubusercontent.com/aurora/rmate/master/rmate \n', 'chmod +x /usr/local/bin/rmate \n', # After streamlit is installed, remove the # temporary script and add a link to point to # streamlit in the anaconda directory. This is # needed so we dont have to make the user to # `rehash` in order to pick up the new location. 'rm -f /usr/local/bin/streamlit \n', 'ln -fs /home/ubuntu/anaconda3/bin/streamlit /usr/local/bin/streamlit \n', # Get streamlit config which has the proxy wait # for 2 minutes and any other options we added. 'curl -o /tmp/config.toml https://streamlit.io/cf/config.toml \n', 'install -m 755 -o ubuntu -g ubuntu -d ~ubuntu/.streamlit \n', 'install -m 600 -o ubuntu -g ubuntu -t ~ubuntu/.streamlit /tmp/config.toml \n', ] )), Metadata=cloudformation.Metadata( cloudformation.Init( cloudformation.InitConfigSets(InstallAndConfigure=['config']), config=cloudformation.InitConfig( files={ '/usr/local/bin/deletestack.sh' : { 'content' : Join('\n', [ Sub('aws cloudformation delete-stack --region ${AWS::Region} --stack-name ${AWS::StackName}'), ]), 'mode' : '000444', 'owner' : 'root', 'group' : 'root' }, }, commands={ 'schedule_stack_deletion': { 'command': Join('', [ 'at -f /usr/local/bin/deletestack.sh "now + ', Ref(self._parameters['StackTTL']), ' ', Ref(self._parameters['StackTTLUnits']), '"' ]), } } ) ) ), Tags=Tags( Application=self._stack_id, Name=Sub('Streamlit EC2 Instance (${AWS::StackName})'), ), IamInstanceProfile=Ref(self._resources['Ec2IamInstanceProfile']), DependsOn='StackDeletorRole', ), }) self._resources.update({ 'IPAddress': ec2.EIP( 'IPAddress', Domain='vpc', InstanceId=Ref(self._resources['Ec2Instance']), DependsOn='StackDeletorRole', ), }) self._outputs.update({ 'SshIp': Output( 'SshIp', Description='SshIp', Value=GetAtt('Ec2Instance', 'PublicIp'), ), 'SshCommand': Output( 'SshCommand', Description='SshCommand', Value=Join('', [ 'ssh ubuntu@', GetAtt('Ec2Instance', 'PublicIp'), ] ) ), 'StreamlitEndpoint': Output( 'StreamlitEndpoint', Description='Streamlit endpoint', Value=Join('', [ GetAtt('Ec2Instance', 'PublicIp'), ':8501', ] ) ), })
[ "#!/bin/bash\n", "sudo apt-get update\n", "sudo apt-get -y install python-setuptools\n", "sudo apt-get -y install python-pip\n", "sudo pip install https://s3.amazonaws.com/cloudformation-examples/", "aws-cfn-bootstrap-latest.tar.gz\n", "cfn-init -s '", Ref("AWS::StackName"), "' -r Ec2Instance -c ascending", ], )), Metadata=cloudformation.Metadata( cloudformation.Init( cloudformation.InitConfigSets( ascending=["config1", "config2"], descending=["config2", "config1"]), config1=cloudformation.InitConfig( commands={ "test": { "command": 'echo "$CFNTEST" > text.txt', "env": { "CFNTEST": "I come from config1." }, "cwd": "~", } }), config2=cloudformation.InitConfig( commands={ "test": { "command": 'echo "$CFNTEST" > text.txt',
def template(): t = Template() keyname_param = t.add_parameter( Parameter( "KeyName", Description= "Name of an existing EC2 KeyPair to enable SSH access to the instance", Type="String")) image_id_param = t.add_parameter( Parameter("ImageId", Description="ImageId of the EC2 instance", Type="String")) instance_type_param = t.add_parameter( Parameter("InstanceType", Description="Type of the EC2 instance", Type="String")) ScaleCapacity = t.add_parameter( Parameter( "ScaleCapacity", Default="1", Type="String", Description="Number of api servers to run", )) VPCAvailabilityZone2 = t.add_parameter( Parameter( "VPCAvailabilityZone2", MinLength="1", Type="String", Description="Second availability zone", MaxLength="255", )) VPCAvailabilityZone1 = t.add_parameter( Parameter( "VPCAvailabilityZone1", MinLength="1", Type="String", Description="First availability zone", MaxLength="255", )) SecurityGroup = t.add_parameter( Parameter( "SecurityGroup", Type="String", Description="Security group.", )) RootStackName = t.add_parameter( Parameter( "RootStackName", Type="String", Description="The root stack name", )) ApiSubnet2 = t.add_parameter( Parameter( "ApiSubnet2", Type="String", Description="Second private VPC subnet ID for the api app.", )) ApiSubnet1 = t.add_parameter( Parameter( "ApiSubnet1", Type="String", Description="First private VPC subnet ID for the api app.", )) ##################################################### # Launch Configuration ##################################################### LaunchConfig = t.add_resource( LaunchConfiguration( "LaunchConfiguration", Metadata=autoscaling.Metadata( cloudformation.Init( cloudformation.InitConfigSets(InstallAndRun=['Install']), Install=cloudformation.InitConfig( packages={ "apt": { "curl": [], "zip": [], "unzip": [], "git": [], "supervisor": [], "sqlite3": [], "nginx": [], "php7.2-fpm": [], "php7.2-cli": [], "php7.2-pgsql": [], "php7.2-sqlite3": [], "php7.2-gd": [], "php7.2-curl": [], "php7.2-memcached": [], "php7.2-imap": [], "php7.2-mysql": [], "php7.2-mbstring": [], "php7.2-xml": [], "php7.2-zip": [], "php7.2-bcmath": [], "php7.2-soap": [], "php7.2-intl": [], "php7.2-readline": [], "php-msgpack": [], "php-igbinary": [] } }, files=cloudformation.InitFiles({ "/etc/nginx/sites-available/default": cloudformation. InitFile(content=Join('', [ "server {\n", " listen 80 default_server;\n", " root /var/www/html/public;\n", " index index.html index.htm index.php;\n", " server_name _;\n", " charset utf-8;\n", " location = /favicon.ico { log_not_found off; access_log off; }\n", " location = /robots.txt { log_not_found off; access_log off; }\n", " location / {\n", " try_files $uri $uri/ /index.php$is_args$args;\n", " }\n", " location ~ \.php$ {\n", " include snippets/fastcgi-php.conf;\n", " fastcgi_pass unix:/run/php/php7.2-fpm.sock;\n", " }\n", " error_page 404 /index.php;\n", "}\n" ])), "/etc/supervisor/conf.d/supervisord.conf": cloudformation. InitFile(content=Join('', [ "[supervisord]\n", "nodaemon=true\n", "[program:nginx]\n", "command=nginx\n", "stdout_logfile=/dev/stdout\n", "stdout_logfile_maxbytes=0\n", "stderr_logfile=/dev/stderr\n", "stderr_logfile_maxbytes=0\n", "[program:php-fpm]\n", "command=php-fpm7.2\n", "stdout_logfile=/dev/stdout\n", "stdout_logfile_maxbytes=0\n", "stderr_logfile=/dev/stderr\n", "stderr_logfile_maxbytes=0\n", "[program:horizon]\n", "process_name=%(program_name)s\n", "command=php /var/www/html/artisan horizon\n", "autostart=true\n", "autorestart=true\n", "user=root\n", "redirect_stderr=true\n", "stdout_logfile=/var/www/html/storage/logs/horizon.log\n", ])), "/etc/php/7.2/fpm/php-fpm.conf": cloudformation.InitFile( content=Join('', [ "[global]\n", "pid = /run/php/php7.2-fpm.pid\n", "error_log = /proc/self/fd/2\n", "include=/etc/php/7.2/fpm/pool.d/*.conf\n" ])) }))), ), UserData=Base64( Join('', [ "#!/bin/bash -xe\n", "apt-get update -y\n", "apt-get install -y language-pack-en-base\n", "export LC_ALL=en_US.UTF-8\n", "export LANG=en_US.UTF-8\n", "apt-get install -y ruby\n", "wget https://aws-codedeploy-ap-south-1.s3.amazonaws.com/latest/install\n", "chmod +x ./install\n", "./install auto\n", "service codedeploy-agent start\n", "apt-get install -y software-properties-common python-software-properties\n", "add-apt-repository -y ppa:ondrej/php\n", "apt-get update -y\n", "apt-get install -y python-setuptools\n", "mkdir -p /opt/aws/bin\n", "wget https://s3.amazonaws.com/cloudformation-examples/aws-cfn-bootstrap-latest.tar.gz\n", "easy_install --script-dir /opt/aws/bin aws-cfn-bootstrap-latest.tar.gz\n", "# Install the files and packages from the metadata\n", "/opt/aws/bin/cfn-init -v ", " --stack ", Ref("AWS::StackName"), " --resource LaunchConfiguration", " --configsets InstallAndRun ", " --region ", Ref("AWS::Region"), "\n" ])), ImageId=Ref("ImageId"), KeyName=Ref(keyname_param), BlockDeviceMappings=[ ec2.BlockDeviceMapping(DeviceName="/dev/sda1", Ebs=ec2.EBSBlockDevice(VolumeSize="8")), ], InstanceType=Ref("InstanceType"), IamInstanceProfile="CodeDeployDemo-EC2-Instance-Profile", SecurityGroups=[Ref(SecurityGroup)])) ##################################################### # AutoScaling Groups ##################################################### AutoscalingGroup = t.add_resource( AutoScalingGroup( "AutoscalingGroup", DesiredCapacity=Ref(ScaleCapacity), Tags=[ Tag("App", "cc-worker", True), Tag("Name", "cc-worker", True) ], LaunchConfigurationName=Ref(LaunchConfig), MinSize=Ref(ScaleCapacity), MaxSize=Ref(ScaleCapacity), VPCZoneIdentifier=[Ref(ApiSubnet1), Ref(ApiSubnet2)], AvailabilityZones=[ Ref(VPCAvailabilityZone1), Ref(VPCAvailabilityZone2) ], HealthCheckType="EC2", UpdatePolicy=UpdatePolicy( AutoScalingReplacingUpdate=AutoScalingReplacingUpdate( WillReplace=True, ), AutoScalingRollingUpdate=AutoScalingRollingUpdate( PauseTime='PT5M', MinInstancesInService="1", MaxBatchSize='1', WaitOnResourceSignals=True)))) return t.to_json()
KeyName=Ref(key_name), SecurityGroups=[Ref(security_group)], IamInstanceProfile='PullCredentials', UserData=Base64( Join('', [ '#!/bin/bash\n', 'sudo apt-get update\n', 'sudo apt-get -y install python-setuptools\n', 'sudo apt-get -y install python-pip\n', 'sudo pip install https://s3.amazonaws.com/cloudformation-examples/', 'aws-cfn-bootstrap-latest.tar.gz\n', 'cfn-init -s \'', Ref('AWS::StackName'), '\' -r Ec2Instance -c ascending' ])), Metadata=cloudformation.Metadata( cloudformation.Init( cloudformation.InitConfigSets( ascending=['config1', 'config2'], descending=['config2', 'config1']), config1=cloudformation.InitConfig( commands={ 'test': { 'command': 'echo "$CFNTEST" > text.txt', 'env': { 'CFNTEST': 'I come from config1.' }, 'cwd': '~' } }), config2=cloudformation.InitConfig( commands={ 'test': { 'command': 'echo "$CFNTEST" > text.txt',
VPCGatewayAttachment( "VPCGatewayAttachment", VpcId=Ref("VPC"), InternetGatewayId=Ref("InternetGateway"), )) AppInstance = t.add_resource( Instance( "AppInstance", # Incorrect interpretation from cfn2py # Metadata=Init( # { "SaltMinion": { "files": { "/tmp/init.sh": { "source": "https://s3-us-west-2.amazonaws.com/perforce-ami-us-west-2/init.sh", "mode": "0755" } }, "commands": { "setupMinion": { "command": "/tmp/init.sh 10.0.0.101 p4d-host" } } }, "configSets": { "All": ["SaltMinion"] } }, # ), Metadata=cloudformation.Metadata( cloudformation.Init( cloudformation.InitConfigSets(DeploySalt=['SaltMinion'], ), SaltMinion=cloudformation.InitConfig(commands={ "SaltMinion": { "files": { "/tmp/init.sh": { "source": "https://s3-us-west-2.amazonaws.com/perforce-ami-us-west-2/init.sh", "mode": "0755" } }, "commands": { "setupMinion": { "command": "/tmp/init.sh 10.0.0.101 app-host" } } },
UserData=Base64( Join("", [ "#!/bin/bash\n", "yum clean all\n", "yum update -y\n", "yum install pystache python-daemon -y\n", "/bin/rpm -U https://s3.amazonaws.com/cloudformation-examples/aws-cfn-bootstrap-latest.amzn1.noarch.rpm\n", "/opt/aws/bin/cfn-init ", " --stack ", { "Ref": "AWS::StackName" }, " --resource myLaunchConfig", " --configsets InstallandRun", " --region ", { "Ref": "AWS::Region" }, "\n" ])), Metadata=Metadata( cf.Init({ "configsets": cf.InitConfigSets(InstallandRun=["install", "config"]), "install": cf.InitConfig(packages={"yum": { "git": [], "wget": [] }}), "config": cf.InitConfig(files=cf.InitFiles({ "/tmp/example.txt": cf.InitFile(content=Join('', [ "This is a file example.\n", "See another examples in:\n", "https://github.com/rabeloo/cf-templates\n" ]), owner="root", group="root",
def attach(self): """Attaches a bootstrapped Chef Node EC2 instance to an AWS CloudFormation template and returns the template. """ parameters = ec2_parameters.EC2Parameters(self.template) parameters.attach() resources = ec2_resources.EC2Resources(self.template) resources.attach() security_group = self.template.add_resource(ec2.SecurityGroup( 'SecurityGroup', GroupDescription='Allows SSH access from anywhere', SecurityGroupIngress=[ ec2.SecurityGroupRule( IpProtocol='tcp', FromPort=22, ToPort=22, CidrIp=Ref(self.template.parameters['SSHLocation']) ), ec2.SecurityGroupRule( IpProtocol='tcp', FromPort=80, ToPort=80, CidrIp='0.0.0.0/0' ), ec2.SecurityGroupRule( IpProtocol='tcp', FromPort=8080, ToPort=8080, CidrIp='0.0.0.0/0' ) ], VpcId=ImportValue("prod2-VPCID"), Tags=Tags( Name='{0}SecurityGroup'.format(EC2_INSTANCE_NAME) ) )) self.template.add_resource(ec2.Instance( EC2_INSTANCE_NAME, ImageId=If( 'IsCentos7', FindInMap( "AWSRegionArch2Centos7LinuxAMI", Ref("AWS::Region"), FindInMap("AWSInstanceType2Arch", Ref(self.template.parameters['InstanceType']), "Arch")), FindInMap( "AWSRegionArch2AmazonLinuxAMI", Ref("AWS::Region"), FindInMap("AWSInstanceType2Arch", Ref(self.template.parameters['InstanceType']), "Arch")) ), InstanceType=Ref(self.template.parameters['InstanceType']), KeyName=FindInMap('Region2KeyPair', Ref('AWS::Region'), 'key'), SecurityGroupIds=[Ref(security_group)], SubnetId=ImportValue("prod2-SubnetPublicAZ2"), IamInstanceProfile=Ref( self.template.resources['InstanceProfileResource']), UserData=Base64(Join('', [ If('IsCentos7', Join('\n', [ '#!/bin/bash ', 'sudo yum update -y ', 'sudo yum install -y vim ', 'sudo yum install -y epel-release ', 'sudo yum install -y awscli ', '# Install CFN-BootStrap ', ('/usr/bin/easy_install --script-dir /opt/aws/bin ' 'https://s3.amazonaws.com/cloudformation-examples/' 'aws-cfn-bootstrap-latest.tar.gz '), ('cp -v /usr/lib/python2*/site-packages/aws_cfn_' 'bootstrap*/init/redhat/cfn-hup /etc/init.d '), 'chmod +x /etc/init.d/cfn-hup ', ]), Join('\n', [ '#!/bin/bash -xe ', 'yum update -y ', '# Update CFN-BootStrap ', 'yum update -y aws-cfn-bootstrap', 'sudo yum install -y awslogs ', ])), Join('', [ '# Install the files and packages from the metadata\n' '/opt/aws/bin/cfn-init -v ', ' --stack ', Ref('AWS::StackName'), ' --resource ', EC2_INSTANCE_NAME, ' --configsets InstallAndRun', ' --region ', Ref('AWS::Region'), ' --role ', Ref(self.template.resources['RoleResource']), '\n', '# Signal the status from cfn-init\n', '/opt/aws/bin/cfn-signal -e $? ' ' --stack ', Ref('AWS::StackName'), ' --resource ', EC2_INSTANCE_NAME, ' --region ', Ref('AWS::Region'), ' --role ', Ref(self.template.resources['RoleResource']), '\n' ]), ] ) ), Metadata=cloudformation.Metadata( cloudformation.Init( cloudformation.InitConfigSets( InstallAndRun=['Install', 'InstallLogs', 'InstallChef', 'Configure'] ), Install=cloudformation.InitConfig( packages={ 'yum': { 'stress': [], 'docker': [] } }, files={ '/etc/cfn/cfn-hup.conf': { 'content': Join('\n', [ '[main]', 'stack={{stackid}}', 'region={{region}}', 'interval=1' ]), 'context': { 'stackid': Ref('AWS::StackId'), 'region': Ref('AWS::Region') }, 'mode': '000400', 'owner': 'root', 'group': 'root' }, '/etc/cfn/hooks.d/cfn-auto-reloader.conf': { 'content': Join('\n', [ '[cfn-auto-reloader-hook]', 'triggers=post.update', ('path=Resources.{{instance_name}}' '.Metadata' '.AWS::CloudFormation::Init'), ('action=/opt/aws/bin/cfn-init -v ' ' --stack {{stack_name}} ' ' --resource {{instance_name}} ' ' --configsets {{config_sets}} ' ' --region {{region}} '), 'runas={{run_as}}' ]), 'context': { 'instance_name': EC2_INSTANCE_NAME, 'stack_name': Ref('AWS::StackName'), 'region': Ref('AWS::Region'), 'config_sets': 'InstallAndRun', 'run_as': 'root' } } }, services={ 'sysvinit': { 'docker': { 'enabled': 'true', 'ensureRunning': 'true' }, 'cfn-hup': { 'enabled': 'true', 'ensureRunning': 'true' } } }, commands={ '01_test': { 'command': 'echo "$CFNTEST" > Install.txt', 'env': { 'CFNTEST': 'I come from Install.' }, 'cwd': '~' } } ), InstallLogs=cloudformation.InitConfig( files={ '/etc/awslogs/awslogs.conf': { 'content': Join('\n', [ '[general]', ('state_file= /var/awslogs/' 'state/agent-state'), '', '[/var/log/cloud-init.log]', 'file = /var/log/cloud-init.log', 'log_group_name = {{log_group_name}}', ('log_stream_name = ' '{instance_id}/cloud-init.log'), 'datetime_format = {{datetime_format}}', '', '[/var/log/cloud-init-output.log]', 'file = /var/log/cloud-init-output.log', 'log_group_name = {{log_group_name}}', ('log_stream_name = ' '{instance_id}/cloud-init-output.log'), 'datetime_format = {{datetime_format}}', '', '[/var/log/cfn-init.log]', 'file = /var/log/cfn-init.log', 'log_group_name = {{log_group_name}}', ('log_stream_name = ' '{instance_id}/cfn-init.log'), 'datetime_format = {{datetime_format}}', '', '[/var/log/cfn-hup.log]', 'file = /var/log/cfn-hup.log', 'log_group_name = {{log_group_name}}', ('log_stream_name = ' '{instance_id}/cfn-hup.log'), 'datetime_format = {{datetime_format}}', '', '[/var/log/cfn-wire.log]', 'file = /var/log/cfn-wire.log', 'log_group_name = {{log_group_name}}', ('log_stream_name = ' '{instance_id}/cfn-wire.log'), 'datetime_format = {{datetime_format}}', '', '[/var/log/httpd]', 'file = /var/log/httpd/*', 'log_group_name = {{log_group_name}}', ('log_stream_name = ' '{instance_id}/httpd'), 'datetime_format = {{datetime_format}}' ]), 'context': { 'log_group_name': Ref( self.template.resources[ 'LogGroupResource']), 'datetime_format': '%d/%b/%Y:%H:%M:%S' } }, '/etc/awslogs/awscli.conf': { 'content': Join('\n', [ '[plugins]', 'cwlogs = cwlogs', '[default]', 'region = {{region}}' ]), 'context': { 'region': Ref('AWS::Region') }, 'mode': '000444', 'owner': 'root', 'group': 'root' } }, commands={ '01_create_state_directory': { 'command' : 'mkdir -p /var/awslogs/state' }, '02_test': { 'command': 'echo "$CFNTEST" > InstallLogs.txt', 'env': { 'CFNTEST': 'I come from install_logs.' }, 'cwd': '~' }, '03_install_aws_logs_if_centos': { 'command': If('IsCentos7', Join('\n', [ ('curl https://s3.amazonaws.com/aws-' 'cloudwatch/downloads/latest/awslogs-' 'agent-setup.py -O'), Join('', [ 'sudo python ./awslogs-agent-setup.py', ' --configfile /etc/awslogs/awslogs', '.conf --non-interactive --region ', Ref('AWS::Region')]) ]), Join('', [ 'echo "not installing awslogs from ', 'from source"' ])) } }, services={ 'sysvinit': { 'awslogs': { 'enabled': 'true', 'ensureRunning': 'true', 'files': ['/etc/awslogs/awslogs.conf'] } } } ), InstallChef=cloudformation.InitConfig( commands={ '01_invoke_omnitruck_install': { 'command': ( 'curl -L ' 'https://omnitruck.chef.io/install.sh | ' 'bash' ), } }, files={ '/etc/chef/client.rb': { 'source': S3_CLIENT_RB, 'mode': '000600', 'owner': 'root', 'group': 'root', 'authentication': 'S3AccessCreds' }, '/etc/chef/jasondebolt-validator.pem': { 'source': S3_VALIDATOR_PEM, 'mode': '000600', 'owner': 'root', 'group': 'root', 'authentication': 'S3AccessCreds' }, '/etc/chef/first-run.json': { 'source': S3_FIRST_RUN, 'mode': '000600', 'owner': 'root', 'group': 'root', 'authentication': 'S3AccessCreds' } } ), Configure=cloudformation.InitConfig( commands={ '01_test': { 'command': 'echo "$CFNTEST" > Configure.txt', 'env': { 'CFNTEST': 'I come from Configure.' }, 'cwd': '~' }, '02_chef_bootstrap': { 'command': ( 'chef-client -j ' '/etc/chef/first-run.json' ) } } ) ), cloudformation.Authentication({ 'S3AccessCreds': cloudformation.AuthenticationBlock( type='S3', roleName=Ref(self.template.resources['RoleResource'])) }) ), Tags=Tags( Name=Ref('AWS::StackName'), env='ops' ) )) self.template.add_output(Output( 'PublicIp', Description='Public IP of the newly created EC2 instance', Value=GetAtt(EC2_INSTANCE_NAME, 'PublicIp') )) self.template.add_output(Output( 'LinuxType', Description='The linux type of the EC2 instance.', Value=If('IsCentos7', 'centos_7', 'amazon_linux') )) return self.template
Ref('AWS::StackName'), '" --region=', Ref('AWS::Region'), ' -r %s -c on_first_boot\n' % ec2_instance_name, # send the exit code from cfn-init to our CreationPolicy: 'cfn-signal -e $? --stack="', Ref('AWS::StackName'), '" --region=', Ref('AWS::Region'), ' --resource %s\n' % ec2_instance_name, ])), Metadata=cloudformation.Metadata( cloudformation.Init( cloudformation.InitConfigSets( on_first_boot=[ 'install_dokku', 'set_dokku_env', 'start_cfn_hup' ], on_metadata_update=['set_dokku_env'], ), # TODO: figure out how to reinstall Dokku if the version is changed (?) install_dokku=cloudformation.InitConfig( commands={ '01_fetch': { 'command': Join('', [ 'wget https://raw.githubusercontent.com/dokku/dokku/', Ref(dokku_version), '/bootstrap.sh', ]), 'cwd': '~', },
def get_metadata(instance, volume): return cloudformation.Init( cloudformation.InitConfigSets(install=["install_cfn"], update=["resize"]), install_cfn=cloudformation.InitConfig( files={ "/etc/cfn/cfn-hup.conf": { "content": Join("", [ "[main]\n", "stack=", Ref("AWS::StackId"), "\n", "region=", Ref("AWS::Region"), "\n", "interval=1\n", "verbose=true\n" ]), "mode": "000400", "owner": "root", "group": "root" }, "/etc/cfn/hooks.d/cfn-auto-reloader.conf": { "content": Join("", [ "[cfn-auto-reloader-hook]\n", "triggers=post.update\n", "path=Resources.{}\n".format(volume), "action=/opt/aws/bin/cfn-init ", " --stack ", Ref("AWS::StackName"), " --resource {} ".format(instance), " --configsets update ", " --region ", Ref("AWS::Region") ]), "mode": "000400", "owner": "root", "group": "root" }, }, services={ "sysvinit": { "cfn-hup": { "enabled": "true", "ensureRunning": "true", "files": [ "/etc/cfn/cfn-hup.conf", "/etc/cfn/hooks.d/cfn-auto-reloader.conf" ] } } }), resize=cloudformation.InitConfig( commands={ "resize": { "command": "/sbin/resize2fs /dev/xvdh", "env": { "HOME": "/root" } } }), )