class MU::Cloud::CloudFormation::Server
A server as configured in {MU::Config::BasketofKittens::servers}
Attributes
Public Class Methods
Insert a Server's standard IAM role needs into an arbitrary IAM profile
# File modules/mu/providers/cloudformation/server.rb, line 259 def self.addStdPoliciesToIAMProfile(rolename, cloudformation_data: {}) policies = Hash.new aws_str = MU::Cloud::AWS.isGovCloud?(region) ? "aws-us-gov" : "aws" policies['Mu_Bootstrap_Secret_'+MU.deploy_id] ='{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Action":["s3:GetObject"],"Resource":"arn:'+aws_str+':s3:::'+MU.adminBucketName+'/'+"#{MU.deploy_id}-secret"+'"}]}' # XXX this doesn't work unless we can deliver the stack name somehow, and also make the ARN look like arn:aws:cloudformation:us-east-1:144333873908:stack/CATAPULT/* # policies['Mu_Describe_Own_CloudFormation_Stack'] ='{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Action":["cloudformation:DescribeStacks", "cloudformation:ListStacks"],"Resource": {"Ref":"AWS::StackId"}}]}' policies['Mu_Describe_Own_CloudFormation_Stack'] ='{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Action":["cloudformation:DescribeStacks", "cloudformation:ListStacks"],"Resource": "*"}]}' # XXX and then there's this. Doesn't seem to be an easy way to prevent an # instance from just generating volumes at random, tagging other peoples' # stuff, etc. # policies['Mu_Volume_Management'] ='{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Action":["ec2:CreateTags","ec2:CreateVolume","ec2:AttachVolume","ec2:DescribeInstanceAttribute","ec2:DescribeVolumeAttribute","ec2:DescribeVolumeStatus","ec2:DescribeVolumes"],"Resource":"*"}]}' policies.each_pair { |name, doc| MU::Cloud::CloudFormation.setCloudFormationProp( cloudformation_data[rolename], "Policies", { "PolicyName" => name, "PolicyDocument" => JSON.parse(doc) } ) } return cloudformation_data end
Placeholder. This is a NOOP for CloudFormation
, which doesn't build resources directly.
# File modules/mu/providers/cloudformation/server.rb, line 339 def self.cleanup(*args) MU.log "cleanup() not implemented for CloudFormation layer", MU::DEBUG nil end
Create an Amazon IAM instance profile. One of these should get created for each class of instance (each {MU::Cloud::AWS::Server} or {MU::Cloud::AWS::ServerPool}), and will include both baseline Mu policies and whatever other policies are requested. @param rolename [String]: The name of the role to create, generally a {MU::Cloud::AWS::Server} mu_name
@return [String]: The name of the instance profile.
# File modules/mu/providers/cloudformation/server.rb, line 289 def self.createIAMProfile(rolename, base_profile: nil, extra_policies: nil, cloudformation_data: {}) policies = Hash.new cfm_role_name, role_cfm_template = MU::Cloud::CloudFormation.cloudFormationBase("iamrole", name: rolename) cfm_prof_name, prof_cfm_template = MU::Cloud::CloudFormation.cloudFormationBase("iamprofile", name: rolename) cloudformation_data.merge!(role_cfm_template) cloudformation_data.merge!(prof_cfm_template) if base_profile MU.log "Incorporating policies from existing IAM profile '#{base_profile}'" resp = MU::Cloud::AWS.iam.get_instance_profile(instance_profile_name: base_profile) resp.instance_profile.roles.each { |baserole| role_policies = MU::Cloud::AWS.iam.list_role_policies(role_name: baserole.role_name).policy_names role_policies.each { |name| resp = MU::Cloud::AWS.iam.get_role_policy( role_name: baserole.role_name, policy_name: name ) policies[name] = CGI.unescape(resp.policy_document) } } end if extra_policies MU.log "Incorporating other specified policies", details: extra_policies extra_policies.each { |policy_set| policy_set.each_pair { |name, policy| if policies.has_key?(name) MU.log "Attempt to add duplicate node policy '#{name}' to '#{rolename}'", MU::WARN, details: policy next end policies[name] = JSON.generate(policy) } } end policies.each_pair { |name, doc| MU::Cloud::CloudFormation.setCloudFormationProp(cloudformation_data[cfm_role_name], "Policies", { "PolicyName" => name, "PolicyDocument" => JSON.parse(doc) }) } MU::Cloud::CloudFormation.setCloudFormationProp(cloudformation_data[cfm_prof_name], "Roles", { "Ref" => cfm_role_name } ) MU::Cloud::CloudFormation.setCloudFormationProp(cloudformation_data[cfm_prof_name], "DependsOn", cfm_role_name) return [rolename, cfm_role_name, cfm_prof_name] end
Placeholder. This is a NOOP for CloudFormation
, which doesn't build resources directly.
# File modules/mu/providers/cloudformation/server.rb, line 333 def self.find(*args) MU.log "find() not implemented for CloudFormation layer", MU::DEBUG nil end
Return the date/time a machine image was created. @param ami_id [String]: AMI identifier of an Amazon Machine Image @param credentials [String] @return [DateTime]
# File modules/mu/providers/cloudformation/server.rb, line 348 def self.imageTimeStamp(ami_id, credentials: nil, region: nil) MU::Cloud::AWS.imageTimeStamp(ami_id, credentials: credentials, region: region) end
Does this resource type exist as a global (cloud-wide) artifact, or is it localized to a region/zone? @return [Boolean]
# File modules/mu/providers/cloudformation/server.rb, line 379 def self.isGlobal? MU::Cloud.resourceClass("AWS", "Server").isGlobal? end
@param mommacat [MU::MommaCat]: A {MU::Mommacat} object containing the deploy of which this resource is/will be a member. @param kitten_cfg [Hash]: The fully parsed and resolved {MU::Config} resource descriptor as defined in {MU::Config::BasketofKittens::servers}
# File modules/mu/providers/cloudformation/server.rb, line 35 def initialize(mommacat: nil, kitten_cfg: nil, mu_name: nil, cloud_id: nil) @deploy = mommacat @config = kitten_cfg @cloud_id = cloud_id @userdata = MU::Cloud.fetchUserdata( platform: @config["platform"], template_variables: { "deployKey" => Base64.urlsafe_encode64(@deploy.public_key), "deploySSHKey" => @deploy.ssh_public_key, "muID" => MU.deploy_id, "muUser" => MU.chef_user, "publicIP" => MU.mu_public_ip, "mommaCatPort" => MU.mommaCatPort, "skipApplyUpdates" => @config['skipinitialupdates'], "windowsAdminName" => @config['windows_admin_username'], "resourceName" => @config["name"], "resourceType" => "server" }, custom_append: @config['userdata_script'], scrub_mu_isms: @config['scrub_mu_isms'] ) @disk_devices = MU::Cloud.resourceClass("AWS", "Server").disk_devices @ephemeral_mappings = MU::Cloud.resourceClass("AWS", "Server").ephemeral_mappings if !mu_name.nil? @mu_name = mu_name @config['mu_name'] = @mu_name # describe @mu_windows_name = @deploydata['mu_windows_name'] if @mu_windows_name.nil? and @deploydata elsif @config['scrub_mu_isms'] @mu_name = @config['name'] else if kitten_cfg.has_key?("basis") @mu_name = @deploy.getResourceName(@config['name'], need_unique_string: true) else @mu_name = @deploy.getResourceName(@config['name']) end @config['mu_name'] = @mu_name @config['instance_secret'] = Password.random(50) end @groomer = MU::Groomer.new(self) end
Cloud-specific configuration properties. @param config [MU::Config]: The calling MU::Config
object @return [Array<Array,Hash>]: List of required fields, and json-schema Hash
of cloud-specific configuration parameters for this resource
# File modules/mu/providers/cloudformation/server.rb, line 355 def self.schema(config) MU::Cloud.resourceClass("AWS", "Server").schema(config) end
Cloud-specific pre-processing of {MU::Config::BasketofKittens::servers}, bare and unvalidated. @param server [Hash]: The resource to process and validate @param configurator [MU::Config]: The overall deployment configurator of which this resource is a member @return [Boolean]: True if validation succeeded, False otherwise
# File modules/mu/providers/cloudformation/server.rb, line 372 def self.validateConfig(server, configurator) MU::Cloud.resourceClass("AWS", "Server").validateConfig(server, configurator) end
Confirm that the given instance size is valid for the given region. If someone accidentally specified an equivalent size from some other cloud provider, return something that makes sense. If nothing makes sense, return nil. @param size [String]: Instance type to check @param region [String]: Region to check against @return [String,nil]
# File modules/mu/providers/cloudformation/server.rb, line 364 def self.validateInstanceType(size, region) MU::Cloud.resourceClass("AWS", "Server").validateInstanceType(size, region) end
Public Instance Methods
Placeholder. This is a NOOP for CloudFormation
, which doesn't build resources directly.
# File modules/mu/providers/cloudformation/server.rb, line 244 def active? end
Placeholder. This is a NOOP for CloudFormation
, which doesn't build resources directly.
# File modules/mu/providers/cloudformation/server.rb, line 234 def canonicalIP end
Populate @cfm_template with a resource description for this server in CloudFormation
language.
# File modules/mu/providers/cloudformation/server.rb, line 84 def create @cfm_name, @cfm_template = MU::Cloud::CloudFormation.cloudFormationBase(self.class.cfg_name, self, tags: @config['tags'], scrub_mu_isms: @config['scrub_mu_isms']) if @cfm_template.nil? @role_cfm_name = @prof_cfm_name = nil MU::Cloud::CloudFormation.setCloudFormationProp(@cfm_template[@cfm_name], "SourceDestCheck", @config['src_dst_check']) MU::Cloud::CloudFormation.setCloudFormationProp(@cfm_template[@cfm_name], "InstanceType", @config['size']) MU::Cloud::CloudFormation.setCloudFormationProp(@cfm_template[@cfm_name], "ImageId", @config['ami_id']) MU::Cloud::CloudFormation.setCloudFormationProp(@cfm_template[@cfm_name], "KeyName", { "Ref" => "SSHKeyName" }) if @config['generate_iam_role'] and !@role_generated @config['iam_role'], @cfm_role_name, @cfm_prof_name = MU::Cloud::CloudFormation::Server.createIAMProfile(@mu_name, base_profile: @config['iam_role'], extra_policies: @config['iam_policies'], cloudformation_data: @cfm_template) @role_generated = true end if !@config["iam_role"].nil? MU::Cloud::CloudFormation::Server.addStdPoliciesToIAMProfile(@cfm_role_name, cloudformation_data: @cfm_template, region: @config['region']) if !@config['scrub_mu_isms'] MU::Cloud::CloudFormation.setCloudFormationProp(@cfm_template[@cfm_name], "DependsOn", @cfm_role_name) MU::Cloud::CloudFormation.setCloudFormationProp(@cfm_template[@cfm_name], "DependsOn", @cfm_prof_name) MU::Cloud::CloudFormation.setCloudFormationProp(@cfm_template[@cfm_name], "IamInstanceProfile", { "Ref" => @cfm_prof_name }) end if @config['add_firewall_rules'] @config['add_firewall_rules'].each { |acl| if acl["rule_id"] MU::Cloud::CloudFormation.setCloudFormationProp(@cfm_template[@cfm_name], "SecurityGroupIds", acl["rule_id"]) else MU::Cloud::CloudFormation.setCloudFormationProp(@cfm_template[@cfm_name], "SecurityGroupIds", { "Ref" => @dependencies["firewall_rule"][acl["rule_name"]].cloudobj.cfm_name }) end } end if !@config['private_ip'].nil? MU::Cloud::CloudFormation.setCloudFormationProp(@cfm_template[@cfm_name], "PrivateIpAddress", config['private_ip']) end if !@vpc.nil? and @config.has_key?("vpc") if !@config["vpc"]["vpc_name"].nil? and @dependencies.has_key?("vpc") and @dependencies["vpc"].has_key?(@config["vpc"]["vpc_name"]) MU::Cloud::CloudFormation.setCloudFormationProp(@cfm_template[@cfm_name], "DependsOn", @dependencies["vpc"][@config["vpc"]["vpc_name"]].cloudobj.cfm_name) end if !@config['vpc']['subnet_id'].nil? MU::Cloud::CloudFormation.setCloudFormationProp(@cfm_template[@cfm_name], "SubnetId", @config['vpc']['subnet_id']) elsif @dependencies.has_key?("vpc") and @dependencies["vpc"].has_key?(@config["vpc"]["vpc_name"]) @dependencies["vpc"][@config["vpc"]["vpc_name"]].subnets.each { |subnet_obj| if subnet_obj.name == @config["vpc"]["subnet_name"] MU::Cloud::CloudFormation.setCloudFormationProp(@cfm_template[@cfm_name], "DependsOn", subnet_obj.cfm_name) MU::Cloud::CloudFormation.setCloudFormationProp(@cfm_template[@cfm_name], "SubnetId", { "Ref" => subnet_obj.cfm_name } ) end } end end if !@config['static_ip'].nil? eip_name = eip_template = nil eipassoc_name, eipassoc_template = MU::Cloud::CloudFormation.cloudFormationBase("eipassoc", name: @config['name']+"EIP", scrub_mu_isms: @config['scrub_mu_isms']) if @config['static_ip']['ip'].nil? eip_name, eip_template = MU::Cloud::CloudFormation.cloudFormationBase("eip", name: @config['name']+"EIP", scrub_mu_isms: @config['scrub_mu_isms']) MU::Cloud::CloudFormation.setCloudFormationProp(eipassoc_template[eipassoc_name], "DependsOn", eip_name) if !@config['vpc'].nil? MU::Cloud::CloudFormation.setCloudFormationProp(eip_template[eip_name], "Domain", "vpc") MU::Cloud::CloudFormation.setCloudFormationProp(eipassoc_template[eipassoc_name], "AllocationId", { "Fn::GetAtt" => [eip_name, "AllocationId"] }) if !@vpc.nil? and @config.has_key?("vpc") if !@config["vpc"]["vpc_name"].nil? and @dependencies.has_key?("vpc") and @dependencies["vpc"].has_key?(@config["vpc"]["vpc_name"]) igw_name, igw_template = MU::Cloud::CloudFormation.cloudFormationBase("vpcgwattach", name: @dependencies["vpc"][@config["vpc"]["vpc_name"]].cloudobj.mu_name, scrub_mu_isms: @config['scrub_mu_isms']) MU::Cloud::CloudFormation.setCloudFormationProp(eip_template[eip_name], "DependsOn", igw_name) end end # @cfm_template[@cfm_name]["DependsOn"].dup.each { |parent_dep| # MU::Cloud::CloudFormation.setCloudFormationProp(eip_template[eip_name], "DependsOn", parent_dep) # # } else MU::Cloud::CloudFormation.setCloudFormationProp(eipassoc_template[eipassoc_name], "EIP", @config['static_ip']['ip']) end else MU.log "Cannot currently target a pre-existing EIP by name when targeting CloudFormation", MU::WARN end MU::Cloud::CloudFormation.setCloudFormationProp(eipassoc_template[eipassoc_name], "InstanceId", { "Ref" => @cfm_name }) # MU::Cloud::CloudFormation.setCloudFormationProp(eip_template[eip_name], "EIP", @config['static_ip']['ip']) @cfm_template.merge!(eip_template) if !eip_template.nil? @cfm_template.merge!(eipassoc_template) end if !@userdata.nil? and !@userdata.empty? MU::Cloud::CloudFormation.setCloudFormationProp( @cfm_template[@cfm_name], "UserData", { "Fn::Base64" => { "Fn::Join" => [ "", [ "#!/bin/bash\n", "echo '", { "Ref" => "AWS::StackName" }, "' > /etc/aws_cloudformation_stack\n\n", @userdata ] ] } } ) end configured_storage = Array.new cfm_volume_map = {} if @config["storage"] @config["storage"].each { |vol| mapping, cfm_mapping = MU::Cloud.resourceClass("AWS", "Server").convertBlockDeviceMapping(vol) configured_storage << mapping # vol_name, vol_template = MU::Cloud::CloudFormation.cloudFormationBase("volume", name: "volume"+@cfm_name+mapping[:device_name]) # MU::Cloud::CloudFormation.setCloudFormationProp(vol_template[vol_name], "Size", mapping[:ebs][:volume_size].to_s) # MU::Cloud::CloudFormation.setCloudFormationProp(vol_template[vol_name], "VolumeType", mapping[:ebs][:volume_type]) # @cfm_template.merge!(vol_template) # cfm_volume_map[mapping[:device_name]] = { "Ref" => vol_name } if cfm_mapping.size > 0 MU::Cloud::CloudFormation.setCloudFormationProp(@cfm_template[@cfm_name], "BlockDeviceMappings", cfm_mapping) end } end cfm_volume_map.each_pair{ |dev, vol| # MU::Cloud::CloudFormation.setCloudFormationProp(@cfm_template[@cfm_name], "Volumes", { "Device" => dev, "VolumeId" => vol }) } @ephemeral_mappings.each { |mapping| MU::Cloud::CloudFormation.setCloudFormationProp(@cfm_template[@cfm_name], "BlockDeviceMappings", { "DeviceName" => mapping[:device_name], "VirtualName" => mapping[:virtual_name] }) } return @config end
Placeholder. This is a NOOP for CloudFormation
, which doesn't build resources directly.
# File modules/mu/providers/cloudformation/server.rb, line 229 def getSSHConfig end
Placeholder. This is a NOOP for CloudFormation
, which doesn't build resources directly.
# File modules/mu/providers/cloudformation/server.rb, line 239 def getWindowsAdminPassword end
Placeholder. This is a NOOP for CloudFormation
, which doesn't build resources directly.
# File modules/mu/providers/cloudformation/server.rb, line 218 def groom return create end
Placeholder. This is a NOOP for CloudFormation
, which doesn't build resources directly.
# File modules/mu/providers/cloudformation/server.rb, line 254 def notify {} end
Placeholder. This is a NOOP for CloudFormation
, which doesn't build resources directly.
# File modules/mu/providers/cloudformation/server.rb, line 224 def postBoot end
Placeholder. This is a NOOP for CloudFormation
, which doesn't build resources directly.
# File modules/mu/providers/cloudformation/server.rb, line 249 def reboot end