Example #1
0
func (v *Validator) network(ctx context.Context, input *data.Data, conf *config.VirtualContainerHostConfigSpec) {
	defer trace.End(trace.Begin(""))

	// External net
	// external network is default for appliance
	err := v.addNetworkHelper(ctx, conf, input.ExternalNetworkName, "external", "external", true)
	if err != nil {
		v.NoteIssue(fmt.Errorf("Error checking network for --external-network: %s", err))
		v.suggestNetwork("--external-network", true)
	}
	// Bridge network should be different than all other networks
	v.checkNetworkConflict(input.BridgeNetworkName, input.ExternalNetworkName, "external")

	// Client net
	if input.ClientNetworkName == "" {
		input.ClientNetworkName = input.ExternalNetworkName
	}
	err = v.addNetworkHelper(ctx, conf, input.ClientNetworkName, "client", "client", false)
	if err != nil {
		v.NoteIssue(fmt.Errorf("Error checking network for --client-network: %s", err))
		v.suggestNetwork("--client-network", true)
	}
	v.checkNetworkConflict(input.BridgeNetworkName, input.ClientNetworkName, "client")

	// Management net
	if input.ManagementNetworkName == "" {
		input.ManagementNetworkName = input.ClientNetworkName
	}
	err = v.addNetworkHelper(ctx, conf, input.ManagementNetworkName, "", "management", false)
	if err != nil {
		v.NoteIssue(fmt.Errorf("Error checking network for --management-network: %s", err))
		v.suggestNetwork("--management-network", true)
	}
	v.checkNetworkConflict(input.BridgeNetworkName, input.ManagementNetworkName, "management")

	// Bridge net -
	//   vCenter: must exist and must be a DPG
	//   ESX: doesn't need to exist - we will create with default value
	//
	// for now we're hardcoded to "bridge" for the container host name
	conf.BridgeNetwork = "bridge"
	endpointMoref, err := v.dpgHelper(ctx, input.BridgeNetworkName)

	var bridgeID, netMoid string
	if err != nil {
		bridgeID = ""
		netMoid = ""
	} else {
		bridgeID = endpointMoref.String()
		netMoid = endpointMoref.String()
	}

	checkBridgeVDS := true
	if err != nil {
		if _, ok := err.(*find.NotFoundError); !ok || v.IsVC() {
			v.NoteIssue(fmt.Errorf("An existing distributed port group must be specified for bridge network on vCenter: %s", err))
			v.suggestNetwork("--bridge-network", false)
			checkBridgeVDS = false // prevent duplicate error output
		}

		// this allows the dispatcher to create the network with corresponding name
		// if BridgeNetworkName doesn't already exist then we set the ContainerNetwork
		// ID to the name, but leaving the NetworkEndpoint moref as ""
		netMoid = input.BridgeNetworkName
	}

	bridgeNet := &executor.NetworkEndpoint{
		Common: executor.Common{
			Name: "bridge",
			ID:   bridgeID,
		},
		Static: &net.IPNet{IP: net.IPv4zero}, // static but managed externally
		Network: executor.ContainerNetwork{
			Common: executor.Common{
				Name: "bridge",
				ID:   netMoid,
			},
		},
	}
	// we need to have the bridge network identified as an available container network
	conf.AddContainerNetwork(&bridgeNet.Network)
	// we also need to have the appliance attached to the bridge network to allow
	// port forwarding
	conf.AddNetwork(bridgeNet)

	err = v.checkVDSMembership(ctx, endpointMoref, input.BridgeNetworkName)
	if err != nil && checkBridgeVDS {
		v.NoteIssue(fmt.Errorf("Unable to check hosts in vDS for %q: %s", input.BridgeNetworkName, err))
	}

	// add mapped networks (from --container-network)
	//   these should be a distributed port groups in vCenter
	suggestedMapped := false // only suggest mapped nets once
	for name, net := range input.MappedNetworks {
		checkMappedVDS := true
		// "bridge" is reserved
		if name == "bridge" {
			v.NoteIssue(fmt.Errorf("Cannot use reserved name \"bridge\" for container network"))
			continue
		}

		gw := input.MappedNetworksGateways[name]
		pools := input.MappedNetworksIPRanges[name]
		dns := input.MappedNetworksDNS[name]
		if len(pools) != 0 && ip.IsUnspecifiedSubnet(&gw) {
			v.NoteIssue(fmt.Errorf("IP range specified without gateway for container network %q", name))
			continue
		}

		if !ip.IsUnspecifiedSubnet(&gw) && !ip.IsRoutableIP(gw.IP, &gw) {
			v.NoteIssue(fmt.Errorf("Gateway %s is not a routable address", gw.IP))
			continue
		}

		err = nil
		// verify ip ranges are within subnet,
		// and don't overlap with each other
		for i, r := range pools {
			if !gw.Contains(r.FirstIP) || !gw.Contains(r.LastIP) {
				err = fmt.Errorf("IP range %q is not in subnet %q", r, gw)
				break
			}

			for _, r2 := range pools[i+1:] {
				if r2.Overlaps(r) {
					err = fmt.Errorf("Overlapping ip ranges: %q %q", r2, r)
					break
				}
			}

			if err != nil {
				break
			}
		}

		if err != nil {
			v.NoteIssue(err)
			continue
		}

		moref, err := v.dpgHelper(ctx, net)
		if err != nil {
			v.NoteIssue(fmt.Errorf("Error adding container network %q: %s", name, err))
			checkMappedVDS = false
			if !suggestedMapped {
				v.suggestNetwork("--container-network", true)
				suggestedMapped = true
			}
		}
		mappedNet := &executor.ContainerNetwork{
			Common: executor.Common{
				Name: name,
				ID:   moref.String(),
			},
			Gateway:     gw,
			Nameservers: dns,
			Pools:       pools,
		}
		if input.BridgeNetworkName == net {
			v.NoteIssue(errors.Errorf("the bridge network must not be shared with another network role - %q also mapped as container network %q", input.BridgeNetworkName, name))
		}

		err = v.checkVDSMembership(ctx, moref, net)
		if err != nil && checkMappedVDS {
			v.NoteIssue(fmt.Errorf("Unable to check hosts in vDS for %q: %s", net, err))
		}

		conf.AddContainerNetwork(mappedNet)
	}
}