mirror of https://github.com/containers/podman.git
Merge pull request #5611 from baude/v2podcreate
podmanv2 pod create using podspecgen
This commit is contained in:
commit
4233250c43
|
@ -0,0 +1,2 @@
|
||||||
|
all:
|
||||||
|
GO111MODULE=off go build -tags 'ABISupport'
|
|
@ -0,0 +1,108 @@
|
||||||
|
package common
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net"
|
||||||
|
|
||||||
|
"github.com/containers/libpod/pkg/domain/entities"
|
||||||
|
"github.com/containers/libpod/pkg/rootless"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
"github.com/spf13/pflag"
|
||||||
|
)
|
||||||
|
|
||||||
|
func getDefaultNetwork() string {
|
||||||
|
if rootless.IsRootless() {
|
||||||
|
return "slirp4netns"
|
||||||
|
}
|
||||||
|
return "bridge"
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetNetFlags() *pflag.FlagSet {
|
||||||
|
netFlags := pflag.FlagSet{}
|
||||||
|
netFlags.StringSlice(
|
||||||
|
"add-host", []string{},
|
||||||
|
"Add a custom host-to-IP mapping (host:ip) (default [])",
|
||||||
|
)
|
||||||
|
netFlags.StringSlice(
|
||||||
|
"dns", []string{},
|
||||||
|
"Set custom DNS servers",
|
||||||
|
)
|
||||||
|
netFlags.StringSlice(
|
||||||
|
"dns-opt", []string{},
|
||||||
|
"Set custom DNS options",
|
||||||
|
)
|
||||||
|
netFlags.StringSlice(
|
||||||
|
"dns-search", []string{},
|
||||||
|
"Set custom DNS search domains",
|
||||||
|
)
|
||||||
|
netFlags.String(
|
||||||
|
"ip", "",
|
||||||
|
"Specify a static IPv4 address for the container",
|
||||||
|
)
|
||||||
|
netFlags.String(
|
||||||
|
"mac-address", "",
|
||||||
|
"Container MAC address (e.g. 92:d0:c6:0a:29:33)",
|
||||||
|
)
|
||||||
|
netFlags.String(
|
||||||
|
"network", getDefaultNetwork(),
|
||||||
|
"Connect a container to a network",
|
||||||
|
)
|
||||||
|
netFlags.StringSliceP(
|
||||||
|
"publish", "p", []string{},
|
||||||
|
"Publish a container's port, or a range of ports, to the host (default [])",
|
||||||
|
)
|
||||||
|
netFlags.Bool(
|
||||||
|
"no-hosts", false,
|
||||||
|
"Do not create /etc/hosts within the container, instead use the version from the image",
|
||||||
|
)
|
||||||
|
return &netFlags
|
||||||
|
}
|
||||||
|
|
||||||
|
func NetFlagsToNetOptions(cmd *cobra.Command) (*entities.NetOptions, error) {
|
||||||
|
var (
|
||||||
|
err error
|
||||||
|
)
|
||||||
|
opts := entities.NetOptions{}
|
||||||
|
opts.AddHosts, err = cmd.Flags().GetStringSlice("add-host")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
servers, err := cmd.Flags().GetStringSlice("dns")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
for _, d := range servers {
|
||||||
|
if d == "none" {
|
||||||
|
opts.DNSHost = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
opts.DNSServers = append(opts.DNSServers, net.ParseIP(d))
|
||||||
|
}
|
||||||
|
opts.DNSSearch, err = cmd.Flags().GetStringSlice("dns-search")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
m, err := cmd.Flags().GetString("mac-address")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if len(m) > 0 {
|
||||||
|
mac, err := net.ParseMAC(m)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
opts.StaticMAC = &mac
|
||||||
|
}
|
||||||
|
inputPorts, err := cmd.Flags().GetStringSlice("publish")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if len(inputPorts) > 0 {
|
||||||
|
opts.PublishPorts, err = createPortBindings(inputPorts)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
opts.NoHosts, err = cmd.Flags().GetBool("no-hosts")
|
||||||
|
return &opts, err
|
||||||
|
}
|
|
@ -0,0 +1,3 @@
|
||||||
|
package common
|
||||||
|
|
||||||
|
var DefaultKernelNamespaces = "cgroup,ipc,net,uts"
|
|
@ -0,0 +1,43 @@
|
||||||
|
package common
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/cri-o/ocicni/pkg/ocicni"
|
||||||
|
"github.com/docker/go-connections/nat"
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
// createPortBindings iterates ports mappings and exposed ports into a format CNI understands
|
||||||
|
func createPortBindings(ports []string) ([]ocicni.PortMapping, error) {
|
||||||
|
// TODO wants someone to rewrite this code in the future
|
||||||
|
var portBindings []ocicni.PortMapping
|
||||||
|
// The conversion from []string to natBindings is temporary while mheon reworks the port
|
||||||
|
// deduplication code. Eventually that step will not be required.
|
||||||
|
_, natBindings, err := nat.ParsePortSpecs(ports)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
for containerPb, hostPb := range natBindings {
|
||||||
|
var pm ocicni.PortMapping
|
||||||
|
pm.ContainerPort = int32(containerPb.Int())
|
||||||
|
for _, i := range hostPb {
|
||||||
|
var hostPort int
|
||||||
|
var err error
|
||||||
|
pm.HostIP = i.HostIP
|
||||||
|
if i.HostPort == "" {
|
||||||
|
hostPort = containerPb.Int()
|
||||||
|
} else {
|
||||||
|
hostPort, err = strconv.Atoi(i.HostPort)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrapf(err, "unable to convert host port to integer")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pm.HostPort = int32(hostPort)
|
||||||
|
pm.Protocol = containerPb.Proto()
|
||||||
|
portBindings = append(portBindings, pm)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return portBindings, nil
|
||||||
|
}
|
|
@ -0,0 +1,132 @@
|
||||||
|
package pods
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/containers/libpod/cmd/podmanV2/common"
|
||||||
|
"github.com/containers/libpod/cmd/podmanV2/parse"
|
||||||
|
"github.com/containers/libpod/cmd/podmanV2/registry"
|
||||||
|
"github.com/containers/libpod/libpod/define"
|
||||||
|
"github.com/containers/libpod/pkg/domain/entities"
|
||||||
|
"github.com/containers/libpod/pkg/errorhandling"
|
||||||
|
"github.com/containers/libpod/pkg/specgen"
|
||||||
|
"github.com/containers/libpod/pkg/util"
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
podCreateDescription = `After creating the pod, the pod ID is printed to stdout.
|
||||||
|
|
||||||
|
You can then start it at any time with the podman pod start <pod_id> command. The pod will be created with the initial state 'created'.`
|
||||||
|
|
||||||
|
createCommand = &cobra.Command{
|
||||||
|
Use: "create",
|
||||||
|
Args: cobra.NoArgs,
|
||||||
|
Short: "Create a new empty pod",
|
||||||
|
Long: podCreateDescription,
|
||||||
|
RunE: create,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
createOptions entities.PodCreateOptions
|
||||||
|
labels, labelFile []string
|
||||||
|
podIDFile string
|
||||||
|
share string
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
registry.Commands = append(registry.Commands, registry.CliCommand{
|
||||||
|
Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode},
|
||||||
|
Command: createCommand,
|
||||||
|
Parent: podCmd,
|
||||||
|
})
|
||||||
|
flags := createCommand.Flags()
|
||||||
|
flags.SetInterspersed(false)
|
||||||
|
flags.AddFlagSet(common.GetNetFlags())
|
||||||
|
flags.StringVar(&createOptions.CGroupParent, "cgroup-parent", "", "Set parent cgroup for the pod")
|
||||||
|
flags.BoolVar(&createOptions.Infra, "infra", true, "Create an infra container associated with the pod to share namespaces with")
|
||||||
|
flags.StringVar(&createOptions.InfraImage, "infra-image", define.DefaultInfraImage, "The image of the infra container to associate with the pod")
|
||||||
|
flags.StringVar(&createOptions.InfraCommand, "infra-command", define.DefaultInfraCommand, "The command to run on the infra container when the pod is started")
|
||||||
|
flags.StringSliceVar(&labelFile, "label-file", []string{}, "Read in a line delimited file of labels")
|
||||||
|
flags.StringSliceVarP(&labels, "label", "l", []string{}, "Set metadata on pod (default [])")
|
||||||
|
flags.StringVarP(&createOptions.Name, "name", "n", "", "Assign a name to the pod")
|
||||||
|
flags.StringVarP(&createOptions.Hostname, "hostname", "", "", "Set a hostname to the pod")
|
||||||
|
flags.StringVar(&podIDFile, "pod-id-file", "", "Write the pod ID to the file")
|
||||||
|
flags.StringVar(&share, "share", common.DefaultKernelNamespaces, "A comma delimited list of kernel namespaces the pod will share")
|
||||||
|
}
|
||||||
|
|
||||||
|
func create(cmd *cobra.Command, args []string) error {
|
||||||
|
var (
|
||||||
|
err error
|
||||||
|
podIdFile *os.File
|
||||||
|
)
|
||||||
|
createOptions.Labels, err = parse.GetAllLabels(labelFile, labels)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrapf(err, "unable to process labels")
|
||||||
|
}
|
||||||
|
|
||||||
|
if !createOptions.Infra && cmd.Flag("share").Changed && share != "none" && share != "" {
|
||||||
|
return errors.Errorf("You cannot share kernel namespaces on the pod level without an infra container")
|
||||||
|
}
|
||||||
|
createOptions.Share = strings.Split(share, ",")
|
||||||
|
if cmd.Flag("pod-id-file").Changed {
|
||||||
|
podIdFile, err = util.OpenExclusiveFile(podIDFile)
|
||||||
|
if err != nil && os.IsExist(err) {
|
||||||
|
return errors.Errorf("pod id file exists. Ensure another pod is not using it or delete %s", podIDFile)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return errors.Errorf("error opening pod-id-file %s", podIDFile)
|
||||||
|
}
|
||||||
|
defer errorhandling.CloseQuiet(podIdFile)
|
||||||
|
defer errorhandling.SyncQuiet(podIdFile)
|
||||||
|
}
|
||||||
|
|
||||||
|
createOptions.Net, err = common.NetFlagsToNetOptions(cmd)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
netInput, err := cmd.Flags().GetString("network")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
n := specgen.Namespace{}
|
||||||
|
switch netInput {
|
||||||
|
case "bridge":
|
||||||
|
n.NSMode = specgen.Bridge
|
||||||
|
case "host":
|
||||||
|
n.NSMode = specgen.Host
|
||||||
|
case "slip4netns":
|
||||||
|
n.NSMode = specgen.Slirp
|
||||||
|
default:
|
||||||
|
if strings.HasPrefix(netInput, "container:") { //nolint
|
||||||
|
split := strings.Split(netInput, ":")
|
||||||
|
if len(split) != 2 {
|
||||||
|
return errors.Errorf("invalid network paramater: %q", netInput)
|
||||||
|
}
|
||||||
|
n.NSMode = specgen.FromContainer
|
||||||
|
n.Value = split[1]
|
||||||
|
} else if strings.HasPrefix(netInput, "ns:") {
|
||||||
|
return errors.New("the ns: network option is not supported for pods")
|
||||||
|
} else {
|
||||||
|
n.NSMode = specgen.Bridge
|
||||||
|
createOptions.Net.CNINetworks = strings.Split(netInput, ",")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(createOptions.Net.PublishPorts) > 0 {
|
||||||
|
if !createOptions.Infra {
|
||||||
|
return errors.Errorf("you must have an infra container to publish port bindings to the host")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
response, err := registry.ContainerEngine().PodCreate(context.Background(), createOptions)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
fmt.Println(response.Id)
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -5,7 +5,6 @@ import (
|
||||||
|
|
||||||
"github.com/containers/libpod/libpod/define"
|
"github.com/containers/libpod/libpod/define"
|
||||||
"github.com/containers/libpod/libpod/events"
|
"github.com/containers/libpod/libpod/events"
|
||||||
"github.com/containers/libpod/pkg/domain/entities"
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -130,10 +129,8 @@ func (r *Runtime) GetAllVolumes() ([]*Volume, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// PruneVolumes removes unused volumes from the system
|
// PruneVolumes removes unused volumes from the system
|
||||||
func (r *Runtime) PruneVolumes(ctx context.Context) ([]*entities.VolumePruneReport, error) {
|
func (r *Runtime) PruneVolumes(ctx context.Context) (map[string]error, error) {
|
||||||
var (
|
reports := make(map[string]error)
|
||||||
reports []*entities.VolumePruneReport
|
|
||||||
)
|
|
||||||
vols, err := r.GetAllVolumes()
|
vols, err := r.GetAllVolumes()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -142,12 +139,12 @@ func (r *Runtime) PruneVolumes(ctx context.Context) ([]*entities.VolumePruneRepo
|
||||||
for _, vol := range vols {
|
for _, vol := range vols {
|
||||||
if err := r.RemoveVolume(ctx, vol, false); err != nil {
|
if err := r.RemoveVolume(ctx, vol, false); err != nil {
|
||||||
if errors.Cause(err) != define.ErrVolumeBeingUsed && errors.Cause(err) != define.ErrVolumeRemoved {
|
if errors.Cause(err) != define.ErrVolumeBeingUsed && errors.Cause(err) != define.ErrVolumeRemoved {
|
||||||
reports = append(reports, &entities.VolumePruneReport{Id: vol.Name(), Err: err})
|
reports[vol.Name()] = err
|
||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
vol.newVolumeEvent(events.Prune)
|
vol.newVolumeEvent(events.Prune)
|
||||||
reports = append(reports, &entities.VolumePruneReport{Id: vol.Name()})
|
reports[vol.Name()] = nil
|
||||||
}
|
}
|
||||||
return reports, nil
|
return reports, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -356,11 +356,11 @@ func (r *LocalRuntime) PruneVolumes(ctx context.Context) ([]string, []error) {
|
||||||
errs = append(errs, err)
|
errs = append(errs, err)
|
||||||
return vids, errs
|
return vids, errs
|
||||||
}
|
}
|
||||||
for _, r := range reports {
|
for k, v := range reports {
|
||||||
if r.Err == nil {
|
if v == nil {
|
||||||
vids = append(vids, r.Id)
|
vids = append(vids, k)
|
||||||
} else {
|
} else {
|
||||||
errs = append(errs, r.Err)
|
errs = append(errs, v)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return vids, errs
|
return vids, errs
|
||||||
|
|
|
@ -4,15 +4,13 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/containers/libpod/cmd/podman/shared"
|
|
||||||
"github.com/containers/libpod/cmd/podman/shared/parse"
|
|
||||||
"github.com/containers/libpod/libpod"
|
"github.com/containers/libpod/libpod"
|
||||||
"github.com/containers/libpod/libpod/define"
|
"github.com/containers/libpod/libpod/define"
|
||||||
"github.com/containers/libpod/pkg/api/handlers"
|
"github.com/containers/libpod/pkg/api/handlers"
|
||||||
"github.com/containers/libpod/pkg/api/handlers/utils"
|
"github.com/containers/libpod/pkg/api/handlers/utils"
|
||||||
"github.com/containers/libpod/pkg/domain/entities"
|
"github.com/containers/libpod/pkg/domain/entities"
|
||||||
|
"github.com/containers/libpod/pkg/specgen"
|
||||||
"github.com/containers/libpod/pkg/util"
|
"github.com/containers/libpod/pkg/util"
|
||||||
"github.com/gorilla/schema"
|
"github.com/gorilla/schema"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
|
@ -21,76 +19,14 @@ import (
|
||||||
func PodCreate(w http.ResponseWriter, r *http.Request) {
|
func PodCreate(w http.ResponseWriter, r *http.Request) {
|
||||||
var (
|
var (
|
||||||
runtime = r.Context().Value("runtime").(*libpod.Runtime)
|
runtime = r.Context().Value("runtime").(*libpod.Runtime)
|
||||||
options []libpod.PodCreateOption
|
|
||||||
err error
|
err error
|
||||||
)
|
)
|
||||||
labels := make(map[string]string)
|
var psg specgen.PodSpecGenerator
|
||||||
input := handlers.PodCreateConfig{}
|
if err := json.NewDecoder(r.Body).Decode(&psg); err != nil {
|
||||||
if err := json.NewDecoder(r.Body).Decode(&input); err != nil {
|
utils.Error(w, "Failed to decode specgen", http.StatusInternalServerError, errors.Wrap(err, "failed to decode specgen"))
|
||||||
utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "Decode()"))
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if len(input.InfraCommand) > 0 || len(input.InfraImage) > 0 {
|
pod, err := psg.MakePod(runtime)
|
||||||
utils.Error(w, "Something went wrong.", http.StatusInternalServerError,
|
|
||||||
errors.New("infra-command and infra-image are not implemented yet"))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
// TODO long term we should break the following out of adapter and into libpod proper
|
|
||||||
// so that the cli and api can share the creation of a pod with the same options
|
|
||||||
if len(input.CGroupParent) > 0 {
|
|
||||||
options = append(options, libpod.WithPodCgroupParent(input.CGroupParent))
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(input.Labels) > 0 {
|
|
||||||
labels, err = parse.GetAllLabels([]string{}, input.Labels)
|
|
||||||
if err != nil {
|
|
||||||
utils.Error(w, "Something went wrong.", http.StatusInternalServerError, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(labels) != 0 {
|
|
||||||
options = append(options, libpod.WithPodLabels(labels))
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(input.Name) > 0 {
|
|
||||||
options = append(options, libpod.WithPodName(input.Name))
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(input.Hostname) > 0 {
|
|
||||||
options = append(options, libpod.WithPodHostname(input.Hostname))
|
|
||||||
}
|
|
||||||
|
|
||||||
if input.Infra {
|
|
||||||
// TODO infra-image and infra-command are not supported in the libpod API yet. Will fix
|
|
||||||
// when implemented in libpod
|
|
||||||
options = append(options, libpod.WithInfraContainer())
|
|
||||||
sharedNamespaces := shared.DefaultKernelNamespaces
|
|
||||||
if len(input.Share) > 0 {
|
|
||||||
sharedNamespaces = input.Share
|
|
||||||
}
|
|
||||||
nsOptions, err := shared.GetNamespaceOptions(strings.Split(sharedNamespaces, ","))
|
|
||||||
if err != nil {
|
|
||||||
utils.Error(w, "Something went wrong.", http.StatusInternalServerError, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
options = append(options, nsOptions...)
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(input.Publish) > 0 {
|
|
||||||
portBindings, err := shared.CreatePortBindings(input.Publish)
|
|
||||||
if err != nil {
|
|
||||||
utils.Error(w, "Something went wrong.", http.StatusInternalServerError, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
options = append(options, libpod.WithInfraContainerPorts(portBindings))
|
|
||||||
|
|
||||||
}
|
|
||||||
// always have containers use pod cgroups
|
|
||||||
// User Opt out is not yet supported
|
|
||||||
options = append(options, libpod.WithPodCgroups())
|
|
||||||
|
|
||||||
pod, err := runtime.NewPod(r.Context(), options...)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http_code := http.StatusInternalServerError
|
http_code := http.StatusInternalServerError
|
||||||
if errors.Cause(err) == define.ErrPodExists {
|
if errors.Cause(err) == define.ErrPodExists {
|
||||||
|
|
|
@ -149,13 +149,20 @@ func ListVolumes(w http.ResponseWriter, r *http.Request) {
|
||||||
func PruneVolumes(w http.ResponseWriter, r *http.Request) {
|
func PruneVolumes(w http.ResponseWriter, r *http.Request) {
|
||||||
var (
|
var (
|
||||||
runtime = r.Context().Value("runtime").(*libpod.Runtime)
|
runtime = r.Context().Value("runtime").(*libpod.Runtime)
|
||||||
|
reports []*entities.VolumePruneReport
|
||||||
)
|
)
|
||||||
pruned, err := runtime.PruneVolumes(r.Context())
|
pruned, err := runtime.PruneVolumes(r.Context())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.InternalServerError(w, err)
|
utils.InternalServerError(w, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
utils.WriteResponse(w, http.StatusOK, pruned)
|
for k, v := range pruned {
|
||||||
|
reports = append(reports, &entities.VolumePruneReport{
|
||||||
|
Err: v,
|
||||||
|
Id: k,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
utils.WriteResponse(w, http.StatusOK, reports)
|
||||||
}
|
}
|
||||||
|
|
||||||
func RemoveVolume(w http.ResponseWriter, r *http.Request) {
|
func RemoveVolume(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
|
@ -133,19 +133,6 @@ type ContainerTopOKBody struct {
|
||||||
dockerContainer.ContainerTopOKBody
|
dockerContainer.ContainerTopOKBody
|
||||||
}
|
}
|
||||||
|
|
||||||
// swagger:model PodCreateConfig
|
|
||||||
type PodCreateConfig struct {
|
|
||||||
Name string `json:"name"`
|
|
||||||
CGroupParent string `json:"cgroup-parent"`
|
|
||||||
Hostname string `json:"hostname"`
|
|
||||||
Infra bool `json:"infra"`
|
|
||||||
InfraCommand string `json:"infra-command"`
|
|
||||||
InfraImage string `json:"infra-image"`
|
|
||||||
Labels []string `json:"labels"`
|
|
||||||
Publish []string `json:"publish"`
|
|
||||||
Share string `json:"share"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type ErrorModel struct {
|
type ErrorModel struct {
|
||||||
Message string `json:"message"`
|
Message string `json:"message"`
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,7 +37,7 @@ func (s *APIServer) registerPodsHandlers(r *mux.Router) error {
|
||||||
// description: attributes for creating a pod
|
// description: attributes for creating a pod
|
||||||
// schema:
|
// schema:
|
||||||
// type: object
|
// type: object
|
||||||
// $ref: "#/definitions/PodCreateConfig"
|
// $ref: "#/definitions/PodSpecGenerator"
|
||||||
// responses:
|
// responses:
|
||||||
// 200:
|
// 200:
|
||||||
// $ref: "#/definitions/IdResponse"
|
// $ref: "#/definitions/IdResponse"
|
||||||
|
|
|
@ -5,15 +5,33 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/containers/libpod/libpod"
|
"github.com/containers/libpod/libpod"
|
||||||
"github.com/containers/libpod/pkg/bindings"
|
"github.com/containers/libpod/pkg/bindings"
|
||||||
"github.com/containers/libpod/pkg/domain/entities"
|
"github.com/containers/libpod/pkg/domain/entities"
|
||||||
|
"github.com/containers/libpod/pkg/specgen"
|
||||||
|
jsoniter "github.com/json-iterator/go"
|
||||||
)
|
)
|
||||||
|
|
||||||
func CreatePod() error {
|
func CreatePodFromSpec(ctx context.Context, s *specgen.PodSpecGenerator) (*entities.PodCreateReport, error) {
|
||||||
// TODO
|
var (
|
||||||
return bindings.ErrNotImplemented
|
pcr entities.PodCreateReport
|
||||||
|
)
|
||||||
|
conn, err := bindings.GetClient(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
specgenString, err := jsoniter.MarshalToString(s)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
stringReader := strings.NewReader(specgenString)
|
||||||
|
response, err := conn.DoRequest(stringReader, http.MethodPost, "/pods/create", nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &pcr, response.Process(&pcr)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Exists is a lightweight method to determine if a pod exists in local storage
|
// Exists is a lightweight method to determine if a pod exists in local storage
|
||||||
|
|
|
@ -7,6 +7,7 @@ import (
|
||||||
"github.com/containers/libpod/libpod/define"
|
"github.com/containers/libpod/libpod/define"
|
||||||
"github.com/containers/libpod/pkg/bindings"
|
"github.com/containers/libpod/pkg/bindings"
|
||||||
"github.com/containers/libpod/pkg/bindings/pods"
|
"github.com/containers/libpod/pkg/bindings/pods"
|
||||||
|
"github.com/containers/libpod/pkg/specgen"
|
||||||
. "github.com/onsi/ginkgo"
|
. "github.com/onsi/ginkgo"
|
||||||
. "github.com/onsi/gomega"
|
. "github.com/onsi/gomega"
|
||||||
"github.com/onsi/gomega/gexec"
|
"github.com/onsi/gomega/gexec"
|
||||||
|
@ -307,4 +308,15 @@ var _ = Describe("Podman pods", func() {
|
||||||
Expect(err).To(BeNil())
|
Expect(err).To(BeNil())
|
||||||
Expect(len(podSummary)).To(Equal(0))
|
Expect(len(podSummary)).To(Equal(0))
|
||||||
})
|
})
|
||||||
|
|
||||||
|
It("simple create pod", func() {
|
||||||
|
ps := specgen.PodSpecGenerator{}
|
||||||
|
ps.Name = "foobar"
|
||||||
|
_, err := pods.CreatePodFromSpec(bt.conn, &ps)
|
||||||
|
Expect(err).To(BeNil())
|
||||||
|
|
||||||
|
exists, err := pods.Exists(bt.conn, "foobar")
|
||||||
|
Expect(err).To(BeNil())
|
||||||
|
Expect(exists).To(BeTrue())
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
|
@ -15,7 +15,7 @@ type ContainerEngine interface {
|
||||||
ContainerStop(ctx context.Context, namesOrIds []string, options StopOptions) ([]*StopReport, error)
|
ContainerStop(ctx context.Context, namesOrIds []string, options StopOptions) ([]*StopReport, error)
|
||||||
ContainerWait(ctx context.Context, namesOrIds []string, options WaitOptions) ([]WaitReport, error)
|
ContainerWait(ctx context.Context, namesOrIds []string, options WaitOptions) ([]WaitReport, error)
|
||||||
ContainerTop(ctx context.Context, options TopOptions) (*StringSliceReport, error)
|
ContainerTop(ctx context.Context, options TopOptions) (*StringSliceReport, error)
|
||||||
|
PodCreate(ctx context.Context, opts PodCreateOptions) (*PodCreateReport, error)
|
||||||
PodExists(ctx context.Context, nameOrId string) (*BoolReport, error)
|
PodExists(ctx context.Context, nameOrId string) (*BoolReport, error)
|
||||||
PodKill(ctx context.Context, namesOrIds []string, options PodKillOptions) ([]*PodKillReport, error)
|
PodKill(ctx context.Context, namesOrIds []string, options PodKillOptions) ([]*PodKillReport, error)
|
||||||
PodPause(ctx context.Context, namesOrIds []string, options PodPauseOptions) ([]*PodPauseReport, error)
|
PodPause(ctx context.Context, namesOrIds []string, options PodPauseOptions) ([]*PodPauseReport, error)
|
||||||
|
|
|
@ -1,6 +1,10 @@
|
||||||
package entities
|
package entities
|
||||||
|
|
||||||
import "time"
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/containers/libpod/pkg/specgen"
|
||||||
|
)
|
||||||
|
|
||||||
type PodKillOptions struct {
|
type PodKillOptions struct {
|
||||||
All bool
|
All bool
|
||||||
|
@ -92,3 +96,48 @@ type PodRmReport struct {
|
||||||
Err error
|
Err error
|
||||||
Id string
|
Id string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type PodCreateOptions struct {
|
||||||
|
CGroupParent string
|
||||||
|
Hostname string
|
||||||
|
Infra bool
|
||||||
|
InfraImage string
|
||||||
|
InfraCommand string
|
||||||
|
Labels map[string]string
|
||||||
|
Name string
|
||||||
|
Net *NetOptions
|
||||||
|
Share []string
|
||||||
|
}
|
||||||
|
|
||||||
|
type PodCreateReport struct {
|
||||||
|
Id string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p PodCreateOptions) ToPodSpecGen(s *specgen.PodSpecGenerator) {
|
||||||
|
// Basic Config
|
||||||
|
s.Name = p.Name
|
||||||
|
s.Hostname = p.Hostname
|
||||||
|
s.Labels = p.Labels
|
||||||
|
s.NoInfra = !p.Infra
|
||||||
|
s.InfraCommand = []string{p.InfraCommand}
|
||||||
|
s.InfraImage = p.InfraImage
|
||||||
|
s.SharedNamespaces = p.Share
|
||||||
|
|
||||||
|
// Networking config
|
||||||
|
s.NetNS = p.Net.Network
|
||||||
|
s.StaticIP = p.Net.StaticIP
|
||||||
|
s.StaticMAC = p.Net.StaticMAC
|
||||||
|
s.PortMappings = p.Net.PublishPorts
|
||||||
|
s.CNINetworks = p.Net.CNINetworks
|
||||||
|
if p.Net.DNSHost {
|
||||||
|
s.NoManageResolvConf = true
|
||||||
|
}
|
||||||
|
s.DNSServer = p.Net.DNSServers
|
||||||
|
s.DNSSearch = p.Net.DNSSearch
|
||||||
|
s.DNSOption = p.Net.DNSOptions
|
||||||
|
s.NoManageHosts = p.Net.NoHosts
|
||||||
|
s.HostAdd = p.Net.AddHosts
|
||||||
|
|
||||||
|
// Cgroup
|
||||||
|
s.CgroupParent = p.CGroupParent
|
||||||
|
}
|
||||||
|
|
|
@ -1,5 +1,12 @@
|
||||||
package entities
|
package entities
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net"
|
||||||
|
|
||||||
|
"github.com/containers/libpod/pkg/specgen"
|
||||||
|
"github.com/cri-o/ocicni/pkg/ocicni"
|
||||||
|
)
|
||||||
|
|
||||||
type Container struct {
|
type Container struct {
|
||||||
IdOrNamed
|
IdOrNamed
|
||||||
}
|
}
|
||||||
|
@ -15,3 +22,23 @@ type Report struct {
|
||||||
|
|
||||||
type PodDeleteReport struct{ Report }
|
type PodDeleteReport struct{ Report }
|
||||||
type PodPruneOptions struct{}
|
type PodPruneOptions struct{}
|
||||||
|
|
||||||
|
type PodPruneReport struct{ Report }
|
||||||
|
type VolumeDeleteOptions struct{}
|
||||||
|
type VolumeDeleteReport struct{ Report }
|
||||||
|
|
||||||
|
// NetOptions reflect the shared network options between
|
||||||
|
// pods and containers
|
||||||
|
type NetOptions struct {
|
||||||
|
AddHosts []string
|
||||||
|
CNINetworks []string
|
||||||
|
DNSHost bool
|
||||||
|
DNSOptions []string
|
||||||
|
DNSSearch []string
|
||||||
|
DNSServers []net.IP
|
||||||
|
Network specgen.Namespace
|
||||||
|
NoHosts bool
|
||||||
|
PublishPorts []ocicni.PortMapping
|
||||||
|
StaticIP *net.IP
|
||||||
|
StaticMAC *net.HardwareAddr
|
||||||
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@ import (
|
||||||
"github.com/containers/libpod/libpod/define"
|
"github.com/containers/libpod/libpod/define"
|
||||||
"github.com/containers/libpod/pkg/domain/entities"
|
"github.com/containers/libpod/pkg/domain/entities"
|
||||||
"github.com/containers/libpod/pkg/signal"
|
"github.com/containers/libpod/pkg/signal"
|
||||||
|
"github.com/containers/libpod/pkg/specgen"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
@ -239,3 +240,13 @@ func (ic *ContainerEngine) PodRm(ctx context.Context, namesOrIds []string, optio
|
||||||
}
|
}
|
||||||
return reports, nil
|
return reports, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ic *ContainerEngine) PodCreate(ctx context.Context, opts entities.PodCreateOptions) (*entities.PodCreateReport, error) {
|
||||||
|
podSpec := specgen.NewPodSpecGenerator()
|
||||||
|
opts.ToPodSpecGen(podSpec)
|
||||||
|
pod, err := podSpec.MakePod(ic.Libpod)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &entities.PodCreateReport{Id: pod.ID()}, nil
|
||||||
|
}
|
||||||
|
|
|
@ -113,7 +113,20 @@ func (ic *ContainerEngine) VolumeInspect(ctx context.Context, namesOrIds []strin
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ic *ContainerEngine) VolumePrune(ctx context.Context, opts entities.VolumePruneOptions) ([]*entities.VolumePruneReport, error) {
|
func (ic *ContainerEngine) VolumePrune(ctx context.Context, opts entities.VolumePruneOptions) ([]*entities.VolumePruneReport, error) {
|
||||||
return ic.Libpod.PruneVolumes(ctx)
|
var (
|
||||||
|
reports []*entities.VolumePruneReport
|
||||||
|
)
|
||||||
|
pruned, err := ic.Libpod.PruneVolumes(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
for k, v := range pruned {
|
||||||
|
reports = append(reports, &entities.VolumePruneReport{
|
||||||
|
Err: v,
|
||||||
|
Id: k,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return reports, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ic *ContainerEngine) VolumeList(ctx context.Context, opts entities.VolumeListOptions) ([]*entities.VolumeListReport, error) {
|
func (ic *ContainerEngine) VolumeList(ctx context.Context, opts entities.VolumeListOptions) ([]*entities.VolumeListReport, error) {
|
||||||
|
|
|
@ -5,6 +5,7 @@ import (
|
||||||
|
|
||||||
"github.com/containers/libpod/pkg/bindings/pods"
|
"github.com/containers/libpod/pkg/bindings/pods"
|
||||||
"github.com/containers/libpod/pkg/domain/entities"
|
"github.com/containers/libpod/pkg/domain/entities"
|
||||||
|
"github.com/containers/libpod/pkg/specgen"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (ic *ContainerEngine) PodExists(ctx context.Context, nameOrId string) (*entities.BoolReport, error) {
|
func (ic *ContainerEngine) PodExists(ctx context.Context, nameOrId string) (*entities.BoolReport, error) {
|
||||||
|
@ -170,3 +171,9 @@ func (ic *ContainerEngine) PodRm(ctx context.Context, namesOrIds []string, optio
|
||||||
}
|
}
|
||||||
return reports, nil
|
return reports, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ic *ContainerEngine) PodCreate(ctx context.Context, opts entities.PodCreateOptions) (*entities.PodCreateReport, error) {
|
||||||
|
podSpec := specgen.NewPodSpecGenerator()
|
||||||
|
opts.ToPodSpecGen(podSpec)
|
||||||
|
return pods.CreatePodFromSpec(ic.ClientCxt, podSpec)
|
||||||
|
}
|
||||||
|
|
|
@ -13,7 +13,7 @@ import (
|
||||||
|
|
||||||
// MakeContainer creates a container based on the SpecGenerator
|
// MakeContainer creates a container based on the SpecGenerator
|
||||||
func (s *SpecGenerator) MakeContainer(rt *libpod.Runtime) (*libpod.Container, error) {
|
func (s *SpecGenerator) MakeContainer(rt *libpod.Runtime) (*libpod.Container, error) {
|
||||||
if err := s.validate(rt); err != nil {
|
if err := s.validate(); err != nil {
|
||||||
return nil, errors.Wrap(err, "invalid config provided")
|
return nil, errors.Wrap(err, "invalid config provided")
|
||||||
}
|
}
|
||||||
rtc, err := rt.GetConfig()
|
rtc, err := rt.GetConfig()
|
|
@ -4,8 +4,6 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/containers/libpod/pkg/rootless"
|
"github.com/containers/libpod/pkg/rootless"
|
||||||
|
|
||||||
"github.com/containers/libpod/libpod"
|
|
||||||
"github.com/containers/libpod/pkg/util"
|
"github.com/containers/libpod/pkg/util"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
@ -25,7 +23,7 @@ func exclusiveOptions(opt1, opt2 string) error {
|
||||||
|
|
||||||
// Validate verifies that the given SpecGenerator is valid and satisfies required
|
// Validate verifies that the given SpecGenerator is valid and satisfies required
|
||||||
// input for creating a container.
|
// input for creating a container.
|
||||||
func (s *SpecGenerator) validate(rt *libpod.Runtime) error {
|
func (s *SpecGenerator) validate() error {
|
||||||
|
|
||||||
//
|
//
|
||||||
// ContainerBasicConfig
|
// ContainerBasicConfig
|
|
@ -0,0 +1,83 @@
|
||||||
|
package specgen
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/containers/libpod/cmd/podman/shared"
|
||||||
|
"github.com/containers/libpod/libpod"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (p *PodSpecGenerator) MakePod(rt *libpod.Runtime) (*libpod.Pod, error) {
|
||||||
|
if err := p.validate(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
options, err := p.createPodOptions()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return rt.NewPod(context.Background(), options...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *PodSpecGenerator) createPodOptions() ([]libpod.PodCreateOption, error) {
|
||||||
|
var (
|
||||||
|
options []libpod.PodCreateOption
|
||||||
|
)
|
||||||
|
if !p.NoInfra {
|
||||||
|
options = append(options, libpod.WithInfraContainer())
|
||||||
|
nsOptions, err := shared.GetNamespaceOptions(p.SharedNamespaces)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
options = append(options, nsOptions...)
|
||||||
|
}
|
||||||
|
if len(p.CgroupParent) > 0 {
|
||||||
|
options = append(options, libpod.WithPodCgroupParent(p.CgroupParent))
|
||||||
|
}
|
||||||
|
if len(p.Labels) > 0 {
|
||||||
|
options = append(options, libpod.WithPodLabels(p.Labels))
|
||||||
|
}
|
||||||
|
if len(p.Name) > 0 {
|
||||||
|
options = append(options, libpod.WithPodName(p.Name))
|
||||||
|
}
|
||||||
|
if len(p.Hostname) > 0 {
|
||||||
|
options = append(options, libpod.WithPodHostname(p.Hostname))
|
||||||
|
}
|
||||||
|
if len(p.HostAdd) > 0 {
|
||||||
|
options = append(options, libpod.WithPodHosts(p.HostAdd))
|
||||||
|
}
|
||||||
|
if len(p.DNSOption) > 0 {
|
||||||
|
options = append(options, libpod.WithPodDNSOption(p.DNSOption))
|
||||||
|
}
|
||||||
|
if len(p.DNSSearch) > 0 {
|
||||||
|
options = append(options, libpod.WithPodDNSSearch(p.DNSSearch))
|
||||||
|
}
|
||||||
|
if p.StaticIP != nil {
|
||||||
|
options = append(options, libpod.WithPodStaticIP(*p.StaticIP))
|
||||||
|
}
|
||||||
|
if p.StaticMAC != nil {
|
||||||
|
options = append(options, libpod.WithPodStaticMAC(*p.StaticMAC))
|
||||||
|
}
|
||||||
|
if p.NoManageResolvConf {
|
||||||
|
options = append(options, libpod.WithPodUseImageResolvConf())
|
||||||
|
}
|
||||||
|
switch p.NetNS.NSMode {
|
||||||
|
case Bridge:
|
||||||
|
logrus.Debugf("Pod using default network mode")
|
||||||
|
case Host:
|
||||||
|
logrus.Debugf("Pod will use host networking")
|
||||||
|
options = append(options, libpod.WithPodHostNetwork())
|
||||||
|
default:
|
||||||
|
logrus.Debugf("Pod joining CNI networks: %v", p.CNINetworks)
|
||||||
|
options = append(options, libpod.WithPodNetworks(p.CNINetworks))
|
||||||
|
}
|
||||||
|
|
||||||
|
if p.NoManageHosts {
|
||||||
|
options = append(options, libpod.WithPodUseImageHosts())
|
||||||
|
}
|
||||||
|
if len(p.PortMappings) > 0 {
|
||||||
|
options = append(options, libpod.WithInfraContainerPorts(p.PortMappings))
|
||||||
|
}
|
||||||
|
options = append(options, libpod.WithPodCgroups())
|
||||||
|
return options, nil
|
||||||
|
}
|
|
@ -0,0 +1,104 @@
|
||||||
|
package specgen
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/containers/libpod/libpod/define"
|
||||||
|
"github.com/containers/libpod/pkg/rootless"
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// ErrInvalidPodSpecConfig describes an error given when the podspecgenerator is invalid
|
||||||
|
ErrInvalidPodSpecConfig error = errors.New("invalid pod spec")
|
||||||
|
)
|
||||||
|
|
||||||
|
func exclusivePodOptions(opt1, opt2 string) error {
|
||||||
|
return errors.Wrapf(ErrInvalidPodSpecConfig, "%s and %s are mutually exclusive pod options", opt1, opt2)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *PodSpecGenerator) validate() error {
|
||||||
|
// PodBasicConfig
|
||||||
|
if p.NoInfra {
|
||||||
|
if len(p.InfraCommand) > 0 {
|
||||||
|
return exclusivePodOptions("NoInfra", "InfraCommand")
|
||||||
|
}
|
||||||
|
if len(p.InfraImage) > 0 {
|
||||||
|
return exclusivePodOptions("NoInfra", "InfraImage")
|
||||||
|
}
|
||||||
|
if len(p.SharedNamespaces) > 0 {
|
||||||
|
return exclusivePodOptions("NoInfo", "SharedNamespaces")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// PodNetworkConfig
|
||||||
|
if err := p.NetNS.validate(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if p.NoInfra {
|
||||||
|
if p.NetNS.NSMode == NoNetwork {
|
||||||
|
return errors.New("NoInfra and a none network cannot be used toegther")
|
||||||
|
}
|
||||||
|
if p.StaticIP != nil {
|
||||||
|
return exclusivePodOptions("NoInfra", "StaticIP")
|
||||||
|
}
|
||||||
|
if p.StaticMAC != nil {
|
||||||
|
return exclusivePodOptions("NoInfra", "StaticMAC")
|
||||||
|
}
|
||||||
|
if len(p.DNSOption) > 0 {
|
||||||
|
return exclusivePodOptions("NoInfra", "DNSOption")
|
||||||
|
}
|
||||||
|
if len(p.DNSSearch) > 0 {
|
||||||
|
return exclusivePodOptions("NoInfo", "DNSSearch")
|
||||||
|
}
|
||||||
|
if len(p.DNSServer) > 0 {
|
||||||
|
return exclusivePodOptions("NoInfra", "DNSServer")
|
||||||
|
}
|
||||||
|
if len(p.HostAdd) > 0 {
|
||||||
|
return exclusivePodOptions("NoInfra", "HostAdd")
|
||||||
|
}
|
||||||
|
if p.NoManageResolvConf {
|
||||||
|
return exclusivePodOptions("NoInfra", "NoManageResolvConf")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if p.NetNS.NSMode != Bridge {
|
||||||
|
if len(p.PortMappings) > 0 {
|
||||||
|
return errors.New("PortMappings can only be used with Bridge mode networking")
|
||||||
|
}
|
||||||
|
if len(p.CNINetworks) > 0 {
|
||||||
|
return errors.New("CNINetworks can only be used with Bridge mode networking")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if p.NoManageResolvConf {
|
||||||
|
if len(p.DNSServer) > 0 {
|
||||||
|
return exclusivePodOptions("NoManageResolvConf", "DNSServer")
|
||||||
|
}
|
||||||
|
if len(p.DNSSearch) > 0 {
|
||||||
|
return exclusivePodOptions("NoManageResolvConf", "DNSSearch")
|
||||||
|
}
|
||||||
|
if len(p.DNSOption) > 0 {
|
||||||
|
return exclusivePodOptions("NoManageResolvConf", "DNSOption")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if p.NoManageHosts && len(p.HostAdd) > 0 {
|
||||||
|
return exclusivePodOptions("NoManageHosts", "HostAdd")
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := p.NetNS.validate(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set Defaults
|
||||||
|
if p.NetNS.Value == "" {
|
||||||
|
if rootless.IsRootless() {
|
||||||
|
p.NetNS.NSMode = Slirp
|
||||||
|
} else {
|
||||||
|
p.NetNS.NSMode = Bridge
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(p.InfraImage) < 1 {
|
||||||
|
p.InfraImage = define.DefaultInfraImage
|
||||||
|
}
|
||||||
|
if len(p.InfraCommand) < 1 {
|
||||||
|
p.InfraCommand = []string{define.DefaultInfraCommand}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -138,3 +138,16 @@ type PodCgroupConfig struct {
|
||||||
// Optional.
|
// Optional.
|
||||||
CgroupParent string `json:"cgroup_parent,omitempty"`
|
CgroupParent string `json:"cgroup_parent,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// PodSpecGenerator describes options to create a pod
|
||||||
|
// swagger:model PodSpecGenerator
|
||||||
|
type PodSpecGenerator struct {
|
||||||
|
PodBasicConfig
|
||||||
|
PodNetworkConfig
|
||||||
|
PodCgroupConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewPodSpecGenerator creates a new pod spec
|
||||||
|
func NewPodSpecGenerator() *PodSpecGenerator {
|
||||||
|
return &PodSpecGenerator{}
|
||||||
|
}
|
|
@ -394,18 +394,18 @@ type SpecGenerator struct {
|
||||||
|
|
||||||
// NewSpecGenerator returns a SpecGenerator struct given one of two mandatory inputs
|
// NewSpecGenerator returns a SpecGenerator struct given one of two mandatory inputs
|
||||||
func NewSpecGenerator(image string) *SpecGenerator {
|
func NewSpecGenerator(image string) *SpecGenerator {
|
||||||
net := ContainerNetworkConfig{
|
networkConfig := ContainerNetworkConfig{
|
||||||
NetNS: Namespace{
|
NetNS: Namespace{
|
||||||
NSMode: Bridge,
|
NSMode: Bridge,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
csc := ContainerStorageConfig{Image: image}
|
csc := ContainerStorageConfig{Image: image}
|
||||||
if rootless.IsRootless() {
|
if rootless.IsRootless() {
|
||||||
net.NetNS.NSMode = Slirp
|
networkConfig.NetNS.NSMode = Slirp
|
||||||
}
|
}
|
||||||
return &SpecGenerator{
|
return &SpecGenerator{
|
||||||
ContainerStorageConfig: csc,
|
ContainerStorageConfig: csc,
|
||||||
ContainerNetworkConfig: net,
|
ContainerNetworkConfig: networkConfig,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
|
||||||
"github.com/containers/libpod/cmd/podman/shared"
|
"github.com/containers/libpod/cmd/podman/shared"
|
||||||
"github.com/containers/libpod/cmd/podman/varlink"
|
iopodman "github.com/containers/libpod/cmd/podman/varlink"
|
||||||
"github.com/containers/libpod/libpod"
|
"github.com/containers/libpod/libpod"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -113,11 +113,11 @@ func (i *LibpodAPI) VolumesPrune(call iopodman.VarlinkCall) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return call.ReplyVolumesPrune([]string{}, []string{err.Error()})
|
return call.ReplyVolumesPrune([]string{}, []string{err.Error()})
|
||||||
}
|
}
|
||||||
for _, i := range responses {
|
for k, v := range responses {
|
||||||
if i.Err == nil {
|
if v == nil {
|
||||||
prunedNames = append(prunedNames, i.Id)
|
prunedNames = append(prunedNames, k)
|
||||||
} else {
|
} else {
|
||||||
prunedErrors = append(prunedErrors, i.Err.Error())
|
prunedErrors = append(prunedErrors, v.Error())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return call.ReplyVolumesPrune(prunedNames, prunedErrors)
|
return call.ReplyVolumesPrune(prunedNames, prunedErrors)
|
||||||
|
|
|
@ -12,11 +12,11 @@ t GET libpod/pods/notfoo/exists 404
|
||||||
t GET libpod/pods/foo/json 200 \
|
t GET libpod/pods/foo/json 200 \
|
||||||
.Config.name=foo \
|
.Config.name=foo \
|
||||||
.Config.id=$pod_id \
|
.Config.id=$pod_id \
|
||||||
.Containers=null
|
.Containers\|length=1
|
||||||
t GET libpod/pods/json 200 \
|
t GET libpod/pods/json 200 \
|
||||||
.[0].Name=foo \
|
.[0].Name=foo \
|
||||||
.[0].Id=$pod_id \
|
.[0].Id=$pod_id \
|
||||||
.[0].Containers=null
|
.[0].Containers\|length=1
|
||||||
|
|
||||||
# Cannot create a dup pod with the same name
|
# Cannot create a dup pod with the same name
|
||||||
t POST libpod/pods/create name=foo 409 .cause="pod already exists"
|
t POST libpod/pods/create name=foo 409 .cause="pod already exists"
|
||||||
|
@ -34,7 +34,7 @@ fi
|
||||||
t POST libpod/pods/foo/unpause '' 200
|
t POST libpod/pods/foo/unpause '' 200
|
||||||
t POST libpod/pods/foo/unpause '' 200 # (2nd time)
|
t POST libpod/pods/foo/unpause '' 200 # (2nd time)
|
||||||
t POST libpod/pods/foo/stop '' 304
|
t POST libpod/pods/foo/stop '' 304
|
||||||
t POST libpod/pods/foo/restart '' 500 .cause="no such container"
|
t POST libpod/pods/foo/restart '' 200
|
||||||
|
|
||||||
t POST libpod/pods/bar/restart '' 404
|
t POST libpod/pods/bar/restart '' 404
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue