class MU::Cloud::CloudFormation::VPC

Creation of Virtual Private Clouds and associated artifacts (routes, subnets, etc).

Attributes

cfm_name[R]
cfm_template[R]
cloud_id[R]
config[R]
mu_name[R]

Public Class Methods

cleanup(**args) click to toggle source

Placeholder. This is a NOOP for CloudFormation, which doesn't build resources directly.

# File modules/mu/providers/cloudformation/vpc.rb, line 295
def self.cleanup(**args)
  MU.log "cleanup() not implemented for CloudFormation layer", MU::DEBUG
  nil
end
find(**args) click to toggle source

Placeholder. This is a NOOP for CloudFormation, which doesn't build resources directly.

# File modules/mu/providers/cloudformation/vpc.rb, line 289
def self.find(**args)
  MU.log "find() not implemented for CloudFormation layer", MU::DEBUG
  nil
end
isGlobal?() click to toggle source

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/vpc.rb, line 318
def self.isGlobal?
  MU::Cloud.resourceClass("AWS", "VPC").isGlobal?
end
new(mommacat: nil, kitten_cfg: nil, mu_name: nil, cloud_id: nil) click to toggle source

@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::vpcs}

# File modules/mu/providers/cloudformation/vpc.rb, line 33
def initialize(mommacat: nil, kitten_cfg: nil, mu_name: nil, cloud_id: nil)
  @deploy = mommacat
  @config = kitten_cfg
  @subnets = []
  @cloud_id = cloud_id
  if !mu_name.nil?
    @mu_name = mu_name
    loadSubnets if !@cloud_id.nil?
  elsif @config['scrub_mu_isms']
    @mu_name = @config['name']
  else
    @mu_name = @deploy.getResourceName(@config['name'])
  end

end
schema(config) click to toggle source

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/vpc.rb, line 303
def self.schema(config)
  MU::Cloud.resourceClass("AWS", "VPC").schema(config)
end
validateConfig(server, configurator) click to toggle source

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/vpc.rb, line 311
def self.validateConfig(server, configurator)
  MU::Cloud.resourceClass("AWS", "VPC").validateConfig(server, configurator)
end

Public Instance Methods

create() click to toggle source

Populate @cfm_template with a resource description for this VPC in CloudFormation language.

# File modules/mu/providers/cloudformation/vpc.rb, line 51
        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?
          MU::Cloud::CloudFormation.setCloudFormationProp(@cfm_template[@cfm_name], "CidrBlock", @config['ip_block'])
          ["enable_dns_support", "enable_dns_hostnames"].each { |arg|
            if !@config[arg].nil?
              key = ""
              arg.split(/_/).each { |chunk| key = key + chunk.capitalize }
              MU::Cloud::CloudFormation.setCloudFormationProp(@cfm_template[@cfm_name], key, @config[arg])
            end
          }

          igw_name = attach_name = nil
          if @config['create_internet_gateway']
            igw_name, igw_template = MU::Cloud::CloudFormation.cloudFormationBase("igw", name: @mu_name, tags: @config['tags'], scrub_mu_isms: @config['scrub_mu_isms'])
            attach_name, attach_template = MU::Cloud::CloudFormation.cloudFormationBase("vpcgwattach", name: @mu_name, scrub_mu_isms: @config['scrub_mu_isms'])
            MU::Cloud::CloudFormation.setCloudFormationProp(attach_template[attach_name], "DependsOn", igw_name)
            MU::Cloud::CloudFormation.setCloudFormationProp(attach_template[attach_name], "DependsOn", @cfm_name)
            MU::Cloud::CloudFormation.setCloudFormationProp(attach_template[attach_name], "InternetGatewayId", { "Ref" => igw_name } )
            MU::Cloud::CloudFormation.setCloudFormationProp(attach_template[attach_name], "VpcId", { "Ref" => @cfm_name })
            @cfm_template.merge!(igw_template)
            @cfm_template.merge!(attach_template)
          end


          rtb_map = {}
          route_needs_nat = {}
          if !@config['route_tables'].nil?
            @config['route_tables'].each { |rtb|
              rtb_name, rtb_template = MU::Cloud::CloudFormation.cloudFormationBase("rtb", name: rtb['name']+@config['name'], tags: @config['tags'], scrub_mu_isms: @config['scrub_mu_isms'])
              rtb_map[rtb['name']] = rtb_name
              MU::Cloud::CloudFormation.setCloudFormationProp(rtb_template[rtb_name], "VpcId", { "Ref" => @cfm_name })
              MU::Cloud::CloudFormation.setCloudFormationProp(rtb_template[rtb_name], "DependsOn", @cfm_name)
              rtb['routes'].each { |route|
                route_name, route_template = MU::Cloud::CloudFormation.cloudFormationBase("route", name: rtb['name']+@config['name']+route['destination_network'], scrub_mu_isms: @config['scrub_mu_isms'])
                MU::Cloud::CloudFormation.setCloudFormationProp(route_template[route_name], "DependsOn", rtb_name)
                MU::Cloud::CloudFormation.setCloudFormationProp(route_template[route_name], "RouteTableId", { "Ref" => rtb_name } )
                MU::Cloud::CloudFormation.setCloudFormationProp(route_template[route_name], "DestinationCidrBlock", route['destination_network'])
                if !route['interface'].nil?
                  MU::Cloud::CloudFormation.setCloudFormationProp(route_template[route_name], "NetworkInterfaceId", route['interface'] )
                end
                if route['gateway'] == '#INTERNET'
                  if igw_name.nil?
                    raise MuError, "Requested an internet gateway in route table #{rtb_name}, but none is degined"
                  end
                  MU::Cloud::CloudFormation.setCloudFormationProp(route_template[route_name], "GatewayId", { "Ref" => igw_name } )
                  MU::Cloud::CloudFormation.setCloudFormationProp(rtb_template[rtb_name], "DependsOn", igw_name )
                  MU::Cloud::CloudFormation.setCloudFormationProp(route_template[route_name], "DependsOn", igw_name )
                elsif route['gateway'] == '#NAT'
                  route_needs_nat[rtb['name']] ||= {}
                  route_needs_nat[rtb['name']]["template"] = rtb_template
                  route_needs_nat[rtb['name']]["name"] = rtb_name
                  route_needs_nat[rtb['name']]["routes"] ||= []
                  route_needs_nat[rtb['name']]["routes"] << {
                    "name" => route_name,
                    "template" => route_template
                  }
                elsif !route['nat_host_id'].nil?
                  MU::Cloud::CloudFormation.setCloudFormationProp(route_template[route_name], "InstanceId", route['nat_host_id'] )
                elsif !route['nat_host_name'].nil?
                  if !@dependencies.has_key?("server") or !@dependencies["server"][route['nat_host_name']] or @dependencies["server"][route['nat_host_name']].cloudobj.nil?
#                    raise MuError, "VPC #{@config['name']} is missing NAT host dependency #{route['nat_host_name']}"
                    next
                  end
                  MU::Cloud::CloudFormation.setCloudFormationProp(route_template[route_name], "InstanceId", { "Ref" => @dependencies["server"][route['nat_host_name']].cloudobj.cfm_name } )
                  MU::Cloud::CloudFormation.setCloudFormationProp(route_template[route_name], "DependsOn", @dependencies["server"][route['nat_host_name']].cloudobj.cfm_name)
                elsif !route['peer_id'].nil?
                  MU::Cloud::CloudFormation.setCloudFormationProp(route_template[route_name], "VpcPeeringConnectionId", route['peer_id'] )
                end
                @cfm_template.merge!(route_template)
              }
              
              @cfm_template.merge!(rtb_template)
            }
          end

# XXX get back to this flowlogs stuff later
#          if @config["enable_traffic_logging"]
#            @config["log_group_name"] = @mu_name unless @config["log_group_name"]
#            loggroup_name, loggroup_template = MU::Cloud::CloudFormation.cloudFormationBase("loggroup", name: @config["log_group_name"])
#          end

          nats = {} # keep track of what NATs we've stashed in what AZs so that we can set up routes appropriately for private subnets
          if !@config['subnets'].nil?
            @config['subnets'].each { |subnet_cfg|
#              subnet_name = @config['name']+"-"+subnet['name']
              subnet_cfg['mu_name'] = @deploy.getResourceName(@config['name']+"-"+subnet_cfg['name'])
              subnet_cfg['tags'] = @config['tags']
              subnet = MU::Cloud::CloudFormation::VPC::Subnet.new(self, subnet_cfg)
              @subnets << subnet

              if subnet_cfg['create_nat_gateway']
                eip_name, eip_template = MU::Cloud::CloudFormation.cloudFormationBase("eip", name: subnet_cfg['mu_name']+"NATIP", scrub_mu_isms: @config['scrub_mu_isms'])
                MU::Cloud::CloudFormation.setCloudFormationProp(eip_template[eip_name], "Domain", "vpc")

                nat_name, nat_template = MU::Cloud::CloudFormation.cloudFormationBase("nat", name: subnet_cfg['mu_name'], scrub_mu_isms: @config['scrub_mu_isms'])
                if !@config['route_tables'].nil?
                  @config['route_tables'].each { |rtb|
                    next if !route_needs_nat[rtb['name']]
                    rtb_template = route_needs_nat[rtb['name']]["template"]
                    rtb_name = route_needs_nat[rtb['name']]["name"]
                    route_needs_nat[rtb['name']]["routes"].each { |r|
                      route_template = r["template"]
                      route_name = r["name"]
                      MU::Cloud::CloudFormation.setCloudFormationProp(route_template[route_name], "NatGatewayId", { "Ref" => nat_name } )
                      MU::Cloud::CloudFormation.setCloudFormationProp(rtb_template[rtb_name], "DependsOn", nat_name )
                      MU::Cloud::CloudFormation.setCloudFormationProp(route_template[route_name], "DependsOn", nat_name )
                      @cfm_template.merge!(route_template)
                    }
                    @cfm_template.merge!(rtb_template)
                  }
                end

                MU::Cloud::CloudFormation.setCloudFormationProp(nat_template[nat_name], "AllocationId", { "Fn::GetAtt" => [eip_name, "AllocationId"] })
                MU::Cloud::CloudFormation.setCloudFormationProp(nat_template[nat_name], "DependsOn", eip_name)
                MU::Cloud::CloudFormation.setCloudFormationProp(nat_template[nat_name], "DependsOn", attach_name) # XXX make sure config parser catches this requirement
                MU::Cloud::CloudFormation.setCloudFormationProp(nat_template[nat_name], "SubnetId", { "Ref" => subnet.cfm_name})
                @cfm_template.merge!(eip_template)
                @cfm_template.merge!(nat_template)
                nats[subnet_cfg["availability_zone"]] = nat_name
              end

              assoc_name, assoc_template = MU::Cloud::CloudFormation.cloudFormationBase("rtbassoc", name: subnet.cfm_name+subnet_cfg['route_table'], scrub_mu_isms: @config['scrub_mu_isms'])
              MU::Cloud::CloudFormation.setCloudFormationProp(assoc_template[assoc_name], "SubnetId", { "Ref" => subnet.cfm_name })
              MU::Cloud::CloudFormation.setCloudFormationProp(assoc_template[assoc_name], "RouteTableId", { "Ref" => rtb_map[subnet_cfg['route_table']] })
              MU::Cloud::CloudFormation.setCloudFormationProp(assoc_template[assoc_name], "DependsOn", rtb_map[subnet_cfg['route_table']])

              @cfm_template.merge!(assoc_template)
              @cfm_template.merge!(subnet.cfm_template)
            }

            # Go through again and fix up route tables that now should have
            # NATs tied to them.
            @config['subnets'].each { |subnet_cfg|
              my_rtb = rtb_map[subnet_cfg['route_table']]
              if route_needs_nat.has_key?(my_rtb)
                use_nat = nil
                if nats.has_key?(subnet_cfg["availability_zone"])
                  use_nat = nats[subnet_cfg["availability_zone"]]
                else
                  natnames = nats.values
                  use_nat = natnames[rand(natnames.size)]
                end
                my_route = route_needs_nat[my_rtb]

                MU::Cloud::CloudFormation.setCloudFormationProp(@cfm_template[my_route], "NatGatewayId", { "Ref" => use_nat } )
                MU::Cloud::CloudFormation.setCloudFormationProp(@cfm_template[my_route], "DependsOn", use_nat)
                MU::Cloud::CloudFormation.setCloudFormationProp(@cfm_template[my_rtb], "DependsOn", use_nat)
              end
            }
          end
          
# XXX get back to this DHCP stuff later
          if @config['dhcp']
          end
        end
findBastion(nat_name: nil, nat_cloud_id: nil, nat_tag_key: nil, nat_tag_value: nil, nat_ip: nil) click to toggle source

Placeholder. This is a NOOP for CloudFormation, which doesn't build resources directly.

# File modules/mu/providers/cloudformation/vpc.rb, line 231
def findBastion(nat_name: nil, nat_cloud_id: nil, nat_tag_key: nil, nat_tag_value: nil, nat_ip: nil)
  # XXX should probably use findSibling, since that's the only
  # valid case.
  return nil
end
getSubnet() click to toggle source

Placeholder. This is a NOOP for CloudFormation, which doesn't build resources directly.

# File modules/mu/providers/cloudformation/vpc.rb, line 227
def getSubnet
end
groom() click to toggle source

Placeholder. This is a NOOP for CloudFormation, which doesn't build resources directly.

# File modules/mu/providers/cloudformation/vpc.rb, line 209
def groom
  return create
end
listSubnets() click to toggle source

Return an array of MU::Cloud::CloudFormation::VPC::Subnet objects describe the member subnets of this VPC. @return [Array<MU::Cloud::AWS::CloudFormation::Subnet>]

# File modules/mu/providers/cloudformation/vpc.rb, line 222
def listSubnets
  @subnets
end
notify() click to toggle source

Placeholder. This is a NOOP for CloudFormation, which doesn't build resources directly.

# File modules/mu/providers/cloudformation/vpc.rb, line 239
def notify
  {}
end
subnets() click to toggle source

Return an array of MU::Cloud::CloudFormation::VPC::Subnet objects describe the member subnets of this VPC. @return [Array<MU::Cloud::AWS::CloudFormation::Subnet>]

# File modules/mu/providers/cloudformation/vpc.rb, line 216
def subnets
  @subnets
end