func()

in cni/ipam/ipam.go [141:274]


func (plugin *ipamPlugin) Add(args *cniSkel.CmdArgs) error {
	var result *cniTypesCurr.Result
	var err error

	logger.Info("Processing ADD command",
		zap.String("ContainerId", args.ContainerID),
		zap.String("Netns", args.Netns),
		zap.String("IfName", args.IfName),
		zap.String("Args", args.Args),
		zap.String("Path", args.Path),
		zap.ByteString("StdinData", args.StdinData))

	defer func() {
		logger.Info("ADD command completed",
			zap.Any("result", result),
			zap.Error(err))
	}()

	// Parse network configuration from stdin.
	nwCfg, err := plugin.Configure(args.StdinData)
	if err != nil {
		err = plugin.Errorf("Failed to parse network configuration: %v", err)
		return err
	}

	// assign the container id
	options := make(map[string]string)
	options[ipam.OptAddressID] = args.ContainerID

	// Check if an address pool is specified.
	if nwCfg.IPAM.Subnet == "" {
		var poolID string
		var subnet string

		isIpv6 := false
		if nwCfg.IPAM.Type == ipamV6 {
			isIpv6 = true
		}

		// Select the requested interface.
		options[ipam.OptInterfaceName] = nwCfg.Master

		// Allocate an address pool.
		poolID, subnet, err = plugin.am.RequestPool(nwCfg.IPAM.AddrSpace, "", "", options, isIpv6)
		if err != nil {
			err = plugin.Errorf("Failed to allocate pool: %v", err)
			return err
		}

		// On failure, release the address pool.
		defer func() {
			if err != nil && poolID != "" {
				logger.Info("Releasing pool",
					zap.String("poolId", poolID))
				_ = plugin.am.ReleasePool(nwCfg.IPAM.AddrSpace, poolID)
			}
		}()

		nwCfg.IPAM.Subnet = subnet
		logger.Info("Allocated address with subnet",
			zap.String("poolId", poolID),
			zap.String("subnet", subnet))
	}

	// Allocate an address for the endpoint.
	address, err := plugin.am.RequestAddress(nwCfg.IPAM.AddrSpace, nwCfg.IPAM.Subnet, nwCfg.IPAM.Address, options)
	if err != nil {
		err = plugin.Errorf("Failed to allocate address: %v", err)
		return err
	}

	// On failure, release the address.
	defer func() {
		if err != nil && address != "" {
			logger.Info("Releasing address", zap.String("address", address))
			_ = plugin.am.ReleaseAddress(nwCfg.IPAM.AddrSpace, nwCfg.IPAM.Subnet, address, options)
		}
	}()

	logger.Info("Allocated address", zap.String("address", address))

	// Parse IP address.
	ipAddress, err := platform.ConvertStringToIPNet(address)
	if err != nil {
		err = plugin.Errorf("Failed to parse address: %v", err)
		return err
	}

	// Query pool information for gateways and DNS servers.
	apInfo, err := plugin.am.GetPoolInfo(nwCfg.IPAM.AddrSpace, nwCfg.IPAM.Subnet)
	if err != nil {
		err = plugin.Errorf("Failed to get pool information: %v", err)
		return err
	}

	// Populate result.
	result = &cniTypesCurr.Result{
		IPs: []*cniTypesCurr.IPConfig{
			{
				Address: *ipAddress,
				Gateway: apInfo.Gateway,
			},
		},
		Routes: []*cniTypes.Route{
			{
				Dst: ipv4DefaultRouteDstPrefix,
				GW:  apInfo.Gateway,
			},
		},
	}

	// Populate DNS servers.
	for _, dnsServer := range apInfo.DnsServers {
		result.DNS.Nameservers = append(result.DNS.Nameservers, dnsServer.String())
	}

	// Convert result to the requested CNI version.
	res, err := result.GetAsVersion(nwCfg.CNIVersion)
	if err != nil {
		err = plugin.Errorf("Failed to convert result: %v", err)
		return err
	}

	// Output the result.
	if nwCfg.IPAM.Type == cni.Internal {
		// Called via the internal interface. Pass output back in args.
		args.StdinData, _ = json.Marshal(res)
	} else {
		// Called via the executable interface. Print output to stdout.
		res.Print()
	}

	return nil
}