mirror of
				https://github.com/containers/podman.git
				synced 2025-10-31 18:08:51 +08:00 
			
		
		
		
	 5b79cf15a0
			
		
	
	5b79cf15a0
	
	
	
		
			
			* Remove duplicate or unused types and constants * Move all documetation-only models and responses into swagger package * Remove all unecessary names, go-swagger will determine names from struct declarations * Use Libpod suffix to differentiate between compat and libpod models and responses. Taken from swagger:operation declarations. * Models and responses that start with lowercase are for swagger use only while uppercase are used "as is" in the code and swagger comments * Used gofumpt on new code ```release-note ``` Signed-off-by: Jhon Honce <jhonce@redhat.com>
		
			
				
	
	
		
			433 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			433 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package compat
 | |
| 
 | |
| import (
 | |
| 	"encoding/json"
 | |
| 	"fmt"
 | |
| 	"net"
 | |
| 	"net/http"
 | |
| 
 | |
| 	nettypes "github.com/containers/common/libnetwork/types"
 | |
| 	netutil "github.com/containers/common/libnetwork/util"
 | |
| 	"github.com/containers/podman/v4/libpod"
 | |
| 	"github.com/containers/podman/v4/libpod/define"
 | |
| 	"github.com/containers/podman/v4/pkg/api/handlers/utils"
 | |
| 	api "github.com/containers/podman/v4/pkg/api/types"
 | |
| 	"github.com/containers/podman/v4/pkg/domain/entities"
 | |
| 	"github.com/containers/podman/v4/pkg/domain/infra/abi"
 | |
| 	"github.com/containers/podman/v4/pkg/util"
 | |
| 	"github.com/docker/docker/api/types"
 | |
| 
 | |
| 	dockerNetwork "github.com/docker/docker/api/types/network"
 | |
| 	"github.com/gorilla/schema"
 | |
| 	"github.com/pkg/errors"
 | |
| 	"github.com/sirupsen/logrus"
 | |
| )
 | |
| 
 | |
| func InspectNetwork(w http.ResponseWriter, r *http.Request) {
 | |
| 	runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
 | |
| 
 | |
| 	// scope is only used to see if the user passes any illegal value, verbose is not used but implemented
 | |
| 	// for compatibility purposes only.
 | |
| 	query := struct {
 | |
| 		scope   string `schema:"scope"`
 | |
| 		verbose bool   `schema:"verbose"`
 | |
| 	}{
 | |
| 		scope: "local",
 | |
| 	}
 | |
| 	decoder := r.Context().Value(api.DecoderKey).(*schema.Decoder)
 | |
| 	if err := decoder.Decode(&query, r.URL.Query()); err != nil {
 | |
| 		utils.Error(w, http.StatusBadRequest, errors.Wrapf(err, "failed to parse parameters for %s", r.URL.String()))
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	if query.scope != "local" {
 | |
| 		utils.Error(w, http.StatusBadRequest, define.ErrInvalidArg)
 | |
| 		return
 | |
| 	}
 | |
| 	name := utils.GetName(r)
 | |
| 	net, err := runtime.Network().NetworkInspect(name)
 | |
| 	if err != nil {
 | |
| 		utils.NetworkNotFound(w, name, err)
 | |
| 		return
 | |
| 	}
 | |
| 	report, err := convertLibpodNetworktoDockerNetwork(runtime, net)
 | |
| 	if err != nil {
 | |
| 		utils.InternalServerError(w, err)
 | |
| 		return
 | |
| 	}
 | |
| 	utils.WriteResponse(w, http.StatusOK, report)
 | |
| }
 | |
| 
 | |
| func convertLibpodNetworktoDockerNetwork(runtime *libpod.Runtime, network nettypes.Network) (*types.NetworkResource, error) {
 | |
| 	cons, err := runtime.GetAllContainers()
 | |
| 	if err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 	containerEndpoints := make(map[string]types.EndpointResource, len(cons))
 | |
| 	for _, con := range cons {
 | |
| 		data, err := con.Inspect(false)
 | |
| 		if err != nil {
 | |
| 			return nil, err
 | |
| 		}
 | |
| 		if netData, ok := data.NetworkSettings.Networks[network.Name]; ok {
 | |
| 			ipv4Address := ""
 | |
| 			if netData.IPAddress != "" {
 | |
| 				ipv4Address = fmt.Sprintf("%s/%d", netData.IPAddress, netData.IPPrefixLen)
 | |
| 			}
 | |
| 			ipv6Address := ""
 | |
| 			if netData.GlobalIPv6Address != "" {
 | |
| 				ipv6Address = fmt.Sprintf("%s/%d", netData.GlobalIPv6Address, netData.GlobalIPv6PrefixLen)
 | |
| 			}
 | |
| 			containerEndpoint := types.EndpointResource{
 | |
| 				Name:        con.Name(),
 | |
| 				EndpointID:  netData.EndpointID,
 | |
| 				MacAddress:  netData.MacAddress,
 | |
| 				IPv4Address: ipv4Address,
 | |
| 				IPv6Address: ipv6Address,
 | |
| 			}
 | |
| 			containerEndpoints[con.ID()] = containerEndpoint
 | |
| 		}
 | |
| 	}
 | |
| 	ipamConfigs := make([]dockerNetwork.IPAMConfig, 0, len(network.Subnets))
 | |
| 	for _, sub := range network.Subnets {
 | |
| 		ipamConfig := dockerNetwork.IPAMConfig{
 | |
| 			Subnet:  sub.Subnet.String(),
 | |
| 			Gateway: sub.Gateway.String(),
 | |
| 			// TODO add range
 | |
| 		}
 | |
| 		ipamConfigs = append(ipamConfigs, ipamConfig)
 | |
| 	}
 | |
| 	ipamDriver := network.IPAMOptions["driver"]
 | |
| 	if ipamDriver == nettypes.HostLocalIPAMDriver {
 | |
| 		ipamDriver = "default"
 | |
| 	}
 | |
| 	ipam := dockerNetwork.IPAM{
 | |
| 		Driver:  ipamDriver,
 | |
| 		Options: network.IPAMOptions,
 | |
| 		Config:  ipamConfigs,
 | |
| 	}
 | |
| 
 | |
| 	report := types.NetworkResource{
 | |
| 		Name:   network.Name,
 | |
| 		ID:     network.ID,
 | |
| 		Driver: network.Driver,
 | |
| 		// TODO add Created: ,
 | |
| 		Internal:   network.Internal,
 | |
| 		EnableIPv6: network.IPv6Enabled,
 | |
| 		Labels:     network.Labels,
 | |
| 		Options:    network.Options,
 | |
| 		IPAM:       ipam,
 | |
| 		Scope:      "local",
 | |
| 		Attachable: false,
 | |
| 		Ingress:    false,
 | |
| 		ConfigFrom: dockerNetwork.ConfigReference{},
 | |
| 		ConfigOnly: false,
 | |
| 		Containers: containerEndpoints,
 | |
| 		Peers:      nil,
 | |
| 		Services:   nil,
 | |
| 	}
 | |
| 	return &report, nil
 | |
| }
 | |
| 
 | |
| func ListNetworks(w http.ResponseWriter, r *http.Request) {
 | |
| 	runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
 | |
| 	filterMap, err := util.PrepareFilters(r)
 | |
| 	if err != nil {
 | |
| 		utils.Error(w, http.StatusInternalServerError, errors.Wrapf(err, "failed to parse parameters for %s", r.URL.String()))
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	options := entities.NetworkListOptions{
 | |
| 		Filters: *filterMap,
 | |
| 	}
 | |
| 
 | |
| 	ic := abi.ContainerEngine{Libpod: runtime}
 | |
| 	nets, err := ic.NetworkList(r.Context(), options)
 | |
| 	if err != nil {
 | |
| 		utils.InternalServerError(w, err)
 | |
| 		return
 | |
| 	}
 | |
| 	reports := make([]*types.NetworkResource, 0, len(nets))
 | |
| 	for _, net := range nets {
 | |
| 		report, err := convertLibpodNetworktoDockerNetwork(runtime, net)
 | |
| 		if err != nil {
 | |
| 			utils.InternalServerError(w, err)
 | |
| 			return
 | |
| 		}
 | |
| 		reports = append(reports, report)
 | |
| 	}
 | |
| 	utils.WriteResponse(w, http.StatusOK, reports)
 | |
| }
 | |
| 
 | |
| func CreateNetwork(w http.ResponseWriter, r *http.Request) {
 | |
| 	var (
 | |
| 		networkCreate types.NetworkCreateRequest
 | |
| 		network       nettypes.Network
 | |
| 	)
 | |
| 	runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
 | |
| 	if err := json.NewDecoder(r.Body).Decode(&networkCreate); err != nil {
 | |
| 		utils.Error(w, http.StatusInternalServerError, errors.Wrap(err, "Decode()"))
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	network.Name = networkCreate.Name
 | |
| 	if networkCreate.Driver == "" {
 | |
| 		networkCreate.Driver = nettypes.DefaultNetworkDriver
 | |
| 	}
 | |
| 	network.Driver = networkCreate.Driver
 | |
| 	network.Labels = networkCreate.Labels
 | |
| 	network.Internal = networkCreate.Internal
 | |
| 	network.IPv6Enabled = networkCreate.EnableIPv6
 | |
| 
 | |
| 	// FIXME use docker options and convert them to valid libpod options
 | |
| 	// network.Options = networkCreate.Options
 | |
| 
 | |
| 	// dns is only enabled for the bridge driver
 | |
| 	if network.Driver == nettypes.BridgeNetworkDriver {
 | |
| 		network.DNSEnabled = true
 | |
| 	}
 | |
| 
 | |
| 	if networkCreate.IPAM != nil && len(networkCreate.IPAM.Config) > 0 {
 | |
| 		for _, conf := range networkCreate.IPAM.Config {
 | |
| 			s := nettypes.Subnet{}
 | |
| 			if len(conf.Subnet) > 0 {
 | |
| 				var err error
 | |
| 				subnet, err := nettypes.ParseCIDR(conf.Subnet)
 | |
| 				if err != nil {
 | |
| 					utils.InternalServerError(w, errors.Wrap(err, "failed to parse subnet"))
 | |
| 					return
 | |
| 				}
 | |
| 				s.Subnet = subnet
 | |
| 			}
 | |
| 			if len(conf.Gateway) > 0 {
 | |
| 				gw := net.ParseIP(conf.Gateway)
 | |
| 				if gw == nil {
 | |
| 					utils.InternalServerError(w, errors.Errorf("failed to parse gateway ip %s", conf.Gateway))
 | |
| 					return
 | |
| 				}
 | |
| 				s.Gateway = gw
 | |
| 			}
 | |
| 			if len(conf.IPRange) > 0 {
 | |
| 				_, net, err := net.ParseCIDR(conf.IPRange)
 | |
| 				if err != nil {
 | |
| 					utils.InternalServerError(w, errors.Wrap(err, "failed to parse ip range"))
 | |
| 					return
 | |
| 				}
 | |
| 				startIP, err := netutil.FirstIPInSubnet(net)
 | |
| 				if err != nil {
 | |
| 					utils.InternalServerError(w, errors.Wrap(err, "failed to get first ip in range"))
 | |
| 					return
 | |
| 				}
 | |
| 				lastIP, err := netutil.LastIPInSubnet(net)
 | |
| 				if err != nil {
 | |
| 					utils.InternalServerError(w, errors.Wrap(err, "failed to get last ip in range"))
 | |
| 					return
 | |
| 				}
 | |
| 				s.LeaseRange = &nettypes.LeaseRange{
 | |
| 					StartIP: startIP,
 | |
| 					EndIP:   lastIP,
 | |
| 				}
 | |
| 			}
 | |
| 			network.Subnets = append(network.Subnets, s)
 | |
| 		}
 | |
| 		// FIXME can we use the IPAM driver and options?
 | |
| 	}
 | |
| 
 | |
| 	ic := abi.ContainerEngine{Libpod: runtime}
 | |
| 	newNetwork, err := ic.NetworkCreate(r.Context(), network)
 | |
| 	if err != nil {
 | |
| 		utils.InternalServerError(w, err)
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	body := struct {
 | |
| 		ID      string `json:"Id"`
 | |
| 		Warning string
 | |
| 	}{
 | |
| 		ID: newNetwork.ID,
 | |
| 	}
 | |
| 	utils.WriteResponse(w, http.StatusCreated, body)
 | |
| }
 | |
| 
 | |
| func RemoveNetwork(w http.ResponseWriter, r *http.Request) {
 | |
| 	runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
 | |
| 	ic := abi.ContainerEngine{Libpod: runtime}
 | |
| 
 | |
| 	query := struct {
 | |
| 		Force   bool  `schema:"force"`
 | |
| 		Timeout *uint `schema:"timeout"`
 | |
| 	}{
 | |
| 		// This is where you can override the golang default value for one of fields
 | |
| 	}
 | |
| 
 | |
| 	decoder := r.Context().Value(api.DecoderKey).(*schema.Decoder)
 | |
| 	if err := decoder.Decode(&query, r.URL.Query()); err != nil {
 | |
| 		utils.Error(w, http.StatusBadRequest, errors.Wrapf(err, "failed to parse parameters for %s", r.URL.String()))
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	options := entities.NetworkRmOptions{
 | |
| 		Force:   query.Force,
 | |
| 		Timeout: query.Timeout,
 | |
| 	}
 | |
| 
 | |
| 	name := utils.GetName(r)
 | |
| 	reports, err := ic.NetworkRm(r.Context(), []string{name}, options)
 | |
| 	if err != nil {
 | |
| 		utils.Error(w, http.StatusInternalServerError, err)
 | |
| 		return
 | |
| 	}
 | |
| 	if len(reports) == 0 {
 | |
| 		utils.Error(w, http.StatusInternalServerError, errors.Errorf("internal error"))
 | |
| 		return
 | |
| 	}
 | |
| 	report := reports[0]
 | |
| 	if report.Err != nil {
 | |
| 		if errors.Cause(report.Err) == define.ErrNoSuchNetwork {
 | |
| 			utils.Error(w, http.StatusNotFound, define.ErrNoSuchNetwork)
 | |
| 			return
 | |
| 		}
 | |
| 		utils.InternalServerError(w, report.Err)
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	utils.WriteResponse(w, http.StatusNoContent, nil)
 | |
| }
 | |
| 
 | |
| // Connect adds a container to a network
 | |
| func Connect(w http.ResponseWriter, r *http.Request) {
 | |
| 	runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
 | |
| 
 | |
| 	var netConnect types.NetworkConnect
 | |
| 	if err := json.NewDecoder(r.Body).Decode(&netConnect); err != nil {
 | |
| 		utils.Error(w, http.StatusInternalServerError, errors.Wrap(err, "Decode()"))
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	netOpts := nettypes.PerNetworkOptions{}
 | |
| 
 | |
| 	name := utils.GetName(r)
 | |
| 	if netConnect.EndpointConfig != nil {
 | |
| 		if netConnect.EndpointConfig.Aliases != nil {
 | |
| 			netOpts.Aliases = netConnect.EndpointConfig.Aliases
 | |
| 		}
 | |
| 
 | |
| 		// if IP address is provided
 | |
| 		if len(netConnect.EndpointConfig.IPAddress) > 0 {
 | |
| 			staticIP := net.ParseIP(netConnect.EndpointConfig.IPAddress)
 | |
| 			if staticIP == nil {
 | |
| 				utils.Error(w, http.StatusInternalServerError,
 | |
| 					errors.Errorf("failed to parse the ip address %q", netConnect.EndpointConfig.IPAddress))
 | |
| 				return
 | |
| 			}
 | |
| 			netOpts.StaticIPs = append(netOpts.StaticIPs, staticIP)
 | |
| 		}
 | |
| 
 | |
| 		if netConnect.EndpointConfig.IPAMConfig != nil {
 | |
| 			// if IPAMConfig.IPv4Address is provided
 | |
| 			if len(netConnect.EndpointConfig.IPAMConfig.IPv4Address) > 0 {
 | |
| 				staticIP := net.ParseIP(netConnect.EndpointConfig.IPAMConfig.IPv4Address)
 | |
| 				if staticIP == nil {
 | |
| 					utils.Error(w, http.StatusInternalServerError,
 | |
| 						errors.Errorf("failed to parse the ipv4 address %q", netConnect.EndpointConfig.IPAMConfig.IPv4Address))
 | |
| 					return
 | |
| 				}
 | |
| 				netOpts.StaticIPs = append(netOpts.StaticIPs, staticIP)
 | |
| 			}
 | |
| 			// if IPAMConfig.IPv6Address is provided
 | |
| 			if len(netConnect.EndpointConfig.IPAMConfig.IPv6Address) > 0 {
 | |
| 				staticIP := net.ParseIP(netConnect.EndpointConfig.IPAMConfig.IPv6Address)
 | |
| 				if staticIP == nil {
 | |
| 					utils.Error(w, http.StatusInternalServerError,
 | |
| 						errors.Errorf("failed to parse the ipv6 address %q", netConnect.EndpointConfig.IPAMConfig.IPv6Address))
 | |
| 					return
 | |
| 				}
 | |
| 				netOpts.StaticIPs = append(netOpts.StaticIPs, staticIP)
 | |
| 			}
 | |
| 		}
 | |
| 		// If MAC address is provided
 | |
| 		if len(netConnect.EndpointConfig.MacAddress) > 0 {
 | |
| 			staticMac, err := net.ParseMAC(netConnect.EndpointConfig.MacAddress)
 | |
| 			if err != nil {
 | |
| 				utils.Error(w, http.StatusInternalServerError,
 | |
| 					errors.Errorf("failed to parse the mac address %q", netConnect.EndpointConfig.IPAMConfig.IPv6Address))
 | |
| 				return
 | |
| 			}
 | |
| 			netOpts.StaticMAC = nettypes.HardwareAddr(staticMac)
 | |
| 		}
 | |
| 	}
 | |
| 	err := runtime.ConnectContainerToNetwork(netConnect.Container, name, netOpts)
 | |
| 	if err != nil {
 | |
| 		if errors.Cause(err) == define.ErrNoSuchCtr {
 | |
| 			utils.ContainerNotFound(w, netConnect.Container, err)
 | |
| 			return
 | |
| 		}
 | |
| 		if errors.Cause(err) == define.ErrNoSuchNetwork {
 | |
| 			utils.Error(w, http.StatusNotFound, err)
 | |
| 			return
 | |
| 		}
 | |
| 		utils.Error(w, http.StatusInternalServerError, err)
 | |
| 		return
 | |
| 	}
 | |
| 	utils.WriteResponse(w, http.StatusOK, "OK")
 | |
| }
 | |
| 
 | |
| // Disconnect removes a container from a network
 | |
| func Disconnect(w http.ResponseWriter, r *http.Request) {
 | |
| 	runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
 | |
| 
 | |
| 	var netDisconnect types.NetworkDisconnect
 | |
| 	if err := json.NewDecoder(r.Body).Decode(&netDisconnect); err != nil {
 | |
| 		utils.Error(w, http.StatusInternalServerError, errors.Wrap(err, "Decode()"))
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	name := utils.GetName(r)
 | |
| 	err := runtime.DisconnectContainerFromNetwork(netDisconnect.Container, name, netDisconnect.Force)
 | |
| 	if err != nil {
 | |
| 		if errors.Cause(err) == define.ErrNoSuchCtr {
 | |
| 			utils.Error(w, http.StatusNotFound, err)
 | |
| 			return
 | |
| 		}
 | |
| 		if errors.Cause(err) == define.ErrNoSuchNetwork {
 | |
| 			utils.Error(w, http.StatusNotFound, err)
 | |
| 			return
 | |
| 		}
 | |
| 		utils.Error(w, http.StatusInternalServerError, err)
 | |
| 		return
 | |
| 	}
 | |
| 	utils.WriteResponse(w, http.StatusOK, "OK")
 | |
| }
 | |
| 
 | |
| // Prune removes unused networks
 | |
| func Prune(w http.ResponseWriter, r *http.Request) {
 | |
| 	runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
 | |
| 	filterMap, err := util.PrepareFilters(r)
 | |
| 	if err != nil {
 | |
| 		utils.Error(w, http.StatusInternalServerError, errors.Wrap(err, "Decode()"))
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	ic := abi.ContainerEngine{Libpod: runtime}
 | |
| 	pruneOptions := entities.NetworkPruneOptions{
 | |
| 		Filters: *filterMap,
 | |
| 	}
 | |
| 	pruneReports, err := ic.NetworkPrune(r.Context(), pruneOptions)
 | |
| 	if err != nil {
 | |
| 		utils.Error(w, http.StatusInternalServerError, err)
 | |
| 		return
 | |
| 	}
 | |
| 	type response struct {
 | |
| 		NetworksDeleted []string
 | |
| 	}
 | |
| 	prunedNetworks := []string{}
 | |
| 	for _, pr := range pruneReports {
 | |
| 		if pr.Error != nil {
 | |
| 			logrus.Error(pr.Error)
 | |
| 			continue
 | |
| 		}
 | |
| 		prunedNetworks = append(prunedNetworks, pr.Name)
 | |
| 	}
 | |
| 	utils.WriteResponse(w, http.StatusOK, response{NetworksDeleted: prunedNetworks})
 | |
| }
 |