modules/mu/clouds/google/vpc.rb in cloud-mu-3.0.0beta vs modules/mu/clouds/google/vpc.rb in cloud-mu-3.0.0

- old
+ new

@@ -145,11 +145,11 @@ end # Called automatically by {MU::Deploy#createResources} def groom - rtb = @config['route_tables'].first + rtb = @config['route_tables'].first # there's only ever one rtb['routes'].each { |route| # If we had a sibling server being spun up as a NAT, rig up the # route that the hosts behind it will need. if route['gateway'] == "#NAT" and !route['nat_host_name'].nil? @@ -234,11 +234,11 @@ args[:project] ||= args[:habitat] args[:project] ||= MU::Cloud::Google.defaultProject(args[:credentials]) resp = {} if args[:cloud_id] and args[:project] begin - vpc = MU::Cloud::Google.compute(credentials: args[:credentials]).get_network( + vpc = MU::Cloud::Google.compute(credentials: args[:credentials]).get_network( args[:project], args[:cloud_id].to_s.sub(/^.*?\/([^\/]+)$/, '\1') ) resp[args[:cloud_id]] = vpc if !vpc.nil? rescue ::Google::Apis::ClientError => e @@ -253,11 +253,11 @@ raise e if !e.message.match(/^(?:notFound|forbidden): /) end if vpcs and vpcs.items vpcs.items.each { |v| - resp[vpc.name] = v + resp[v.name] = v } end end resp @@ -403,40 +403,52 @@ tag_value: nat_tag_value, allow_multi: true, dummy_ok: true, calling_deploy: @deploy ) -# XXX wat + return nil if found.nil? || found.empty? - if found.size > 1 + + if found.size == 1 + return found.first + elsif found.size > 1 found.each { |nat| + next if !nat.cloud_desc # Try some cloud-specific criteria - cloud_desc = nat.cloud_desc - if !nat_host_ip.nil? and -# XXX this is AWS code, is wrong here - (cloud_desc.private_ip_address == nat_host_ip or cloud_desc.public_ip_address == nat_host_ip) - return nat - elsif cloud_desc.vpc_id == @cloud_id - # XXX Strictly speaking we could have different NATs in - # different subnets, so this can be wrong in corner cases. - return nat - end + nat.cloud_desc.network_interfaces.each { |iface| + if !nat_ip.nil? + return nat if iface.network_ip == nat_ip + if iface.access_configs + iface.access_configs.each { |public_iface| + return if public_iface.nat_ip == nat_ip + } + end + end + if iface.network == @url + # XXX Strictly speaking we could have different NATs in + # different subnets, so this can be wrong in corner cases. + return nat + end + } } - elsif found.size == 1 - return found.first end + return nil end # Check for a subnet in this VPC matching one or more of the specified # criteria, and return it if found. - def getSubnet(cloud_id: nil, name: nil, tag_key: nil, tag_value: nil, ip_block: nil) + def getSubnet(cloud_id: nil, name: nil, tag_key: nil, tag_value: nil, ip_block: nil, region: nil) if !cloud_id.nil? and cloud_id.match(/^https:\/\//) + cloud_id.match(/\/regions\/([^\/]+)\/subnetworks\/([^\/]+)$/) + region = Regexp.last_match[1] + cloud_id = Regexp.last_match[2] cloud_id.gsub!(/.*?\//, "") end - MU.log "getSubnet(cloud_id: #{cloud_id}, name: #{name}, tag_key: #{tag_key}, tag_value: #{tag_value}, ip_block: #{ip_block})", MU::DEBUG, details: caller[0] + MU.log "getSubnet(cloud_id: #{cloud_id}, name: #{name}, tag_key: #{tag_key}, tag_value: #{tag_value}, ip_block: #{ip_block}, region: #{region})", MU::DEBUG, details: caller[0] subnets.each { |subnet| + next if region and subnet.az != region if !cloud_id.nil? and !subnet.cloud_id.nil? and subnet.cloud_id.to_s == cloud_id.to_s return subnet elsif !name.nil? and !subnet.name.nil? and subnet.name.downcase.to_s == name.downcase.to_s return subnet @@ -692,11 +704,73 @@ } } [toplevel_required, schema] end + # If the VPC a config block was set to one that's been "split," try to + # figure out which of the new VPCs we really want to be in. For use by + # resource types that don't go in subnets, but do tie to VPCs. + # @param vpc_block [Hash] + # @param configurator [MU::Config] + # @return [Hash] + def self.pickVPC(vpc_block, my_config, my_type, configurator) + _shortclass, cfg_name, cfg_plural, _classname = MU::Cloud.getResourceNames(my_type) + return if vpc_block.nil? + vpc_block['name'] ||= vpc_block['vpc_name'] + return if !vpc_block['name'] + vpcs = configurator.haveLitterMate?( + nil, + "vpcs", + has_multiple: true + ) + # drop all virtual vpcs that aren't real anymore + vpcs.reject! { |v| v['virtual_name'] == v['name'] } + # drop the ones that have nothing to do with us + vpcs.reject! { |v| v['virtual_name'] != vpc_block['name'] } + + return vpc_block if vpcs.size == 0 + + # see if one of this thing's siblings declared a subnet_pref we can + # use to guess which one we should marry ourselves to + configurator.kittens.each_pair { |type, siblings| + siblings.each { |sibling| + next if !sibling['dependencies'] + sibling['dependencies'].each { |dep| + if [cfg_name, cfg_plural].include?(dep['type']) and + dep['name'] == my_config['name'] + vpcs.each { |v| + if sibling['vpc']['name'] == v['name'] + vpc_block['name'] = v['name'] + return vpc_block + end + } + if sibling['vpc']['subnet_pref'] + vpcs.each { |v| + gateways = v['route_tables'].map { |rtb| + rtb['routes'].map { |r| r["gateway"] } + }.flatten.uniq + if ["public", "all_public"].include?(sibling['vpc']['subnet_pref']) and + gateways.include?("#INTERNET") + vpc_block['name'] = v['name'] + return vpc_block + elsif ["private", "all_private"].include?(sibling['vpc']['subnet_pref']) and + !gateways.include?("#INTERNET") + vpc_block['name'] = v['name'] + return vpc_block + end + } + + end + end + } + } + } + + vpc_block + end + # Cloud-specific pre-processing of {MU::Config::BasketofKittens::vpcs}, bare and unvalidated. # @param vpc [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 def self.validateConfig(vpc, configurator) @@ -718,11 +792,13 @@ vpc["subnets"] = [] vpc['route_tables'].each { |t| is_public = false t['routes'].each { |r| - if !vpc["virtual_name"] and !vpc["create_nat_gateway"] and + if !vpc["virtual_name"] and + !vpc["create_nat_gateway"] and + !vpc['bastion'] and r["gateway"] == "#NAT" r["gateway"] = "#DENY" end is_public = true if r["gateway"] == "#INTERNET" } @@ -779,10 +855,15 @@ vpc.each_pair { |key, val| next if ["name", "route_tables", "subnets", "ip_block"].include?(key) newvpc[key] = val } + if vpc["bastion"] and + !tbl["routes"].map { |r| r["gateway"] }.include?("#INTERNET") + newvpc["bastion"] = vpc["bastion"] + vpc.delete("bastion") + end newvpc['peers'] ||= [] # Add the peer connections we're generating, in addition peernames.each { |peer| if peer != newvpc['name'] newvpc['peers'] << { "vpc" => { "vpc_name" => peer } } @@ -807,10 +888,10 @@ if has_nat or has_deny ok = false if !genStandardSubnetACLs(vpc['parent_block'] || vpc['ip_block'], vpc['name'], configurator, vpc["project"], false, credentials: vpc['credentials']) else ok = false if !genStandardSubnetACLs(vpc['parent_block'] || vpc['ip_block'], vpc['name'], configurator, vpc["project"], credentials: vpc['credentials']) end - if has_nat and !has_deny + if has_nat and !has_deny and !vpc['bastion'] vpc['route_tables'].first["routes"] << { "gateway"=>"#DENY", "destination_network"=>"0.0.0.0/0" } end