summaryrefslogtreecommitdiff
path: root/libpod
diff options
context:
space:
mode:
Diffstat (limited to 'libpod')
-rw-r--r--libpod/image/image.go104
-rw-r--r--libpod/options.go153
-rw-r--r--libpod/pod.go14
-rw-r--r--libpod/runtime_pod_infra_linux.go28
4 files changed, 231 insertions, 68 deletions
diff --git a/libpod/image/image.go b/libpod/image/image.go
index ba1080a71..43fd52a1a 100644
--- a/libpod/image/image.go
+++ b/libpod/image/image.go
@@ -99,10 +99,7 @@ func NewImageRuntimeFromOptions(options storage.StoreOptions) (*Runtime, error)
if err != nil {
return nil, err
}
-
- return &Runtime{
- store: store,
- }, nil
+ return NewImageRuntimeFromStore(store), nil
}
func setStore(options storage.StoreOptions) (storage.Store, error) {
@@ -114,30 +111,29 @@ func setStore(options storage.StoreOptions) (storage.Store, error) {
return store, nil
}
-// newFromStorage creates a new image object from a storage.Image
-func (ir *Runtime) newFromStorage(img *storage.Image) *Image {
- image := Image{
- InputName: img.ID,
+// newImage creates a new image object given an "input name" and a storage.Image
+func (ir *Runtime) newImage(inputName string, img *storage.Image) *Image {
+ return &Image{
+ InputName: inputName,
imageruntime: ir,
image: img,
}
- return &image
+}
+
+// newFromStorage creates a new image object from a storage.Image. Its "input name" will be its ID.
+func (ir *Runtime) newFromStorage(img *storage.Image) *Image {
+ return ir.newImage(img.ID, img)
}
// NewFromLocal creates a new image object that is intended
// to only deal with local images already in the store (or
// its aliases)
func (ir *Runtime) NewFromLocal(name string) (*Image, error) {
- image := Image{
- InputName: name,
- imageruntime: ir,
- }
- localImage, err := image.getLocalImage()
+ updatedInputName, localImage, err := ir.getLocalImage(name)
if err != nil {
return nil, err
}
- image.image = localImage
- return &image, nil
+ return ir.newImage(updatedInputName, localImage), nil
}
// New creates a new image object where the image could be local
@@ -148,15 +144,10 @@ func (ir *Runtime) New(ctx context.Context, name, signaturePolicyPath, authfile
defer span.Finish()
// We don't know if the image is local or not ... check local first
- newImage := Image{
- InputName: name,
- imageruntime: ir,
- }
if pullType != util.PullImageAlways {
- localImage, err := newImage.getLocalImage()
+ newImage, err := ir.NewFromLocal(name)
if err == nil {
- newImage.image = localImage
- return &newImage, nil
+ return newImage, nil
} else if pullType == util.PullImageNever {
return nil, err
}
@@ -171,13 +162,11 @@ func (ir *Runtime) New(ctx context.Context, name, signaturePolicyPath, authfile
return nil, errors.Wrapf(err, "unable to pull %s", name)
}
- newImage.InputName = imageName[0]
- img, err := newImage.getLocalImage()
+ newImage, err := ir.NewFromLocal(imageName[0])
if err != nil {
return nil, errors.Wrapf(err, "error retrieving local image after pulling %s", name)
}
- newImage.image = img
- return &newImage, nil
+ return newImage, nil
}
// LoadFromArchiveReference creates a new image object for images pulled from a tar archive and the like (podman load)
@@ -194,16 +183,11 @@ func (ir *Runtime) LoadFromArchiveReference(ctx context.Context, srcRef types.Im
}
for _, name := range imageNames {
- newImage := Image{
- InputName: name,
- imageruntime: ir,
- }
- img, err := newImage.getLocalImage()
+ newImage, err := ir.NewFromLocal(name)
if err != nil {
return nil, errors.Wrapf(err, "error retrieving local image after pulling %s", name)
}
- newImage.image = img
- newImages = append(newImages, &newImage)
+ newImages = append(newImages, newImage)
}
ir.newImageEvent(events.LoadFromArchive, "")
return newImages, nil
@@ -234,7 +218,7 @@ func (i *Image) reloadImage() error {
if err != nil {
return errors.Wrapf(err, "unable to reload image")
}
- i.image = newImage.image
+ i.image = newImage
return nil
}
@@ -247,60 +231,60 @@ func stripSha256(name string) string {
}
// getLocalImage resolves an unknown input describing an image and
-// returns a storage.Image or an error. It is used by NewFromLocal.
-func (i *Image) getLocalImage() (*storage.Image, error) {
- imageError := fmt.Sprintf("unable to find '%s' in local storage", i.InputName)
- if i.InputName == "" {
- return nil, errors.Errorf("input name is blank")
+// returns an updated input name, and a storage.Image, or an error. It is used by NewFromLocal.
+func (ir *Runtime) getLocalImage(inputName string) (string, *storage.Image, error) {
+ imageError := fmt.Sprintf("unable to find '%s' in local storage", inputName)
+ if inputName == "" {
+ return "", nil, errors.Errorf("input name is blank")
}
// Check if the input name has a transport and if so strip it
- dest, err := alltransports.ParseImageName(i.InputName)
+ dest, err := alltransports.ParseImageName(inputName)
if err == nil && dest.DockerReference() != nil {
- i.InputName = dest.DockerReference().String()
+ inputName = dest.DockerReference().String()
}
- img, err := i.imageruntime.getImage(stripSha256(i.InputName))
+ img, err := ir.getImage(stripSha256(inputName))
if err == nil {
- return img.image, err
+ return inputName, img, err
}
// container-storage wasn't able to find it in its current form
// check if the input name has a tag, and if not, run it through
// again
- decomposedImage, err := decompose(i.InputName)
+ decomposedImage, err := decompose(inputName)
if err != nil {
- return nil, err
+ return "", nil, err
}
// The image has a registry name in it and we made sure we looked for it locally
// with a tag. It cannot be local.
if decomposedImage.hasRegistry {
- return nil, errors.Wrapf(ErrNoSuchImage, imageError)
+ return "", nil, errors.Wrapf(ErrNoSuchImage, imageError)
}
// if the image is saved with the repository localhost, searching with localhost prepended is necessary
// We don't need to strip the sha because we have already determined it is not an ID
ref, err := decomposedImage.referenceWithRegistry(DefaultLocalRegistry)
if err != nil {
- return nil, err
+ return "", nil, err
}
- img, err = i.imageruntime.getImage(ref.String())
+ img, err = ir.getImage(ref.String())
if err == nil {
- return img.image, err
+ return inputName, img, err
}
// grab all the local images
- images, err := i.imageruntime.GetImages()
+ images, err := ir.GetImages()
if err != nil {
- return nil, err
+ return "", nil, err
}
// check the repotags of all images for a match
repoImage, err := findImageInRepotags(decomposedImage, images)
if err == nil {
- return repoImage, nil
+ return inputName, repoImage, nil
}
- return nil, errors.Wrapf(ErrNoSuchImage, err.Error())
+ return "", nil, errors.Wrapf(ErrNoSuchImage, err.Error())
}
// ID returns the image ID as a string
@@ -460,7 +444,7 @@ func (i *Image) Remove(ctx context.Context, force bool) error {
// getImage retrieves an image matching the given name or hash from system
// storage
// If no matching image can be found, an error is returned
-func (ir *Runtime) getImage(image string) (*Image, error) {
+func (ir *Runtime) getImage(image string) (*storage.Image, error) {
var img *storage.Image
ref, err := is.Transport.ParseStoreReference(ir.store, image)
if err == nil {
@@ -476,8 +460,7 @@ func (ir *Runtime) getImage(image string) (*Image, error) {
}
img = img2
}
- newImage := ir.newFromStorage(img)
- return newImage, nil
+ return img, nil
}
// GetImages retrieves all images present in storage
@@ -702,13 +685,6 @@ func (i *Image) toImageSourceRef(ctx context.Context) (types.ImageSource, error)
//Size returns the size of the image
func (i *Image) Size(ctx context.Context) (*uint64, error) {
- if i.image == nil {
- localImage, err := i.getLocalImage()
- if err != nil {
- return nil, err
- }
- i.image = localImage
- }
sum, err := i.imageruntime.store.ImageSize(i.ID())
if err == nil && sum >= 0 {
usum := uint64(sum)
diff --git a/libpod/options.go b/libpod/options.go
index 923e7292c..4957f822d 100644
--- a/libpod/options.go
+++ b/libpod/options.go
@@ -1784,3 +1784,156 @@ func WithInfraContainerPorts(bindings []ocicni.PortMapping) PodCreateOption {
return nil
}
}
+
+// WithPodStaticIP sets a static IP for the pod.
+func WithPodStaticIP(ip net.IP) PodCreateOption {
+ return func(pod *Pod) error {
+ if pod.valid {
+ return define.ErrPodFinalized
+ }
+
+ if len(pod.config.InfraContainer.Networks) > 1 {
+ return errors.Wrapf(define.ErrInvalidArg, "cannot set a static IP if joining more than 1 CNI network")
+ }
+
+ pod.config.InfraContainer.StaticIP = ip
+
+ return nil
+ }
+}
+
+// WithPodStaticMAC sets a static MAC address for the pod.
+func WithPodStaticMAC(mac net.HardwareAddr) PodCreateOption {
+ return func(pod *Pod) error {
+ if pod.valid {
+ return define.ErrPodFinalized
+ }
+
+ if len(pod.config.InfraContainer.Networks) > 1 {
+ return errors.Wrapf(define.ErrInvalidArg, "cannot set a static MAC if joining more than 1 CNI network")
+ }
+
+ pod.config.InfraContainer.StaticMAC = mac
+
+ return nil
+ }
+}
+
+// WithPodUseImageResolvConf sets a pod to use an image's resolv.conf and not
+// create its own.
+func WithPodUseImageResolvConf() PodCreateOption {
+ return func(pod *Pod) error {
+ if pod.valid {
+ return define.ErrPodFinalized
+ }
+
+ if len(pod.config.InfraContainer.DNSServer) != 0 ||
+ len(pod.config.InfraContainer.DNSSearch) != 0 ||
+ len(pod.config.InfraContainer.DNSOption) != 0 {
+ return errors.Wrapf(define.ErrInvalidArg, "requested use of image resolv.conf conflicts with already-configured DNS settings")
+ }
+
+ pod.config.InfraContainer.UseImageResolvConf = true
+
+ return nil
+ }
+}
+
+// WithPodDNS sets the DNS Servers for a pod.
+func WithPodDNS(dnsServer []string) PodCreateOption {
+ return func(pod *Pod) error {
+ if pod.valid {
+ return define.ErrPodFinalized
+ }
+
+ if pod.config.InfraContainer.UseImageResolvConf {
+ return errors.Wrapf(define.ErrInvalidArg, "cannot add DNS servers if pod will not create /etc/resolv.conf")
+ }
+
+ pod.config.InfraContainer.DNSServer = dnsServer
+
+ return nil
+ }
+}
+
+// WithPodDNSSearch sets the DNS Search domains for a pod.
+func WithPodDNSSearch(dnsSearch []string) PodCreateOption {
+ return func(pod *Pod) error {
+ if pod.valid {
+ return define.ErrPodFinalized
+ }
+
+ if pod.config.InfraContainer.UseImageResolvConf {
+ return errors.Wrapf(define.ErrInvalidArg, "cannot add DNS search domains if pod will not create /etc/resolv.conf")
+ }
+
+ pod.config.InfraContainer.DNSSearch = dnsSearch
+
+ return nil
+ }
+}
+
+// WithPodDNSOption sets DNS Options for a pod.
+func WithPodDNSOption(dnsOption []string) PodCreateOption {
+ return func(pod *Pod) error {
+ if pod.valid {
+ return define.ErrPodFinalized
+ }
+
+ if pod.config.InfraContainer.UseImageResolvConf {
+ return errors.Wrapf(define.ErrInvalidArg, "cannot add DNS options if pod will not create /etc/resolv.conf")
+ }
+
+ pod.config.InfraContainer.DNSOption = dnsOption
+
+ return nil
+ }
+}
+
+// WithPodUseImageHosts tells the pod not to create /etc/hosts and instead to
+// use the one provided by the image.
+func WithPodUseImageHosts() PodCreateOption {
+ return func(pod *Pod) error {
+ if pod.valid {
+ return define.ErrPodFinalized
+ }
+
+ if len(pod.config.InfraContainer.HostAdd) != 0 {
+ return errors.Wrapf(define.ErrInvalidArg, "not creating /etc/hosts conflicts with adding to the hosts file")
+ }
+
+ pod.config.InfraContainer.UseImageHosts = true
+
+ return nil
+ }
+}
+
+// WithPodHosts adds additional entries to the pod's /etc/hosts
+func WithPodHosts(hosts []string) PodCreateOption {
+ return func(pod *Pod) error {
+ if pod.valid {
+ return define.ErrPodFinalized
+ }
+
+ if pod.config.InfraContainer.UseImageHosts {
+ return errors.Wrapf(define.ErrInvalidArg, "cannot add to /etc/hosts if container is using image hosts")
+ }
+
+ pod.config.InfraContainer.HostAdd = hosts
+
+ return nil
+ }
+}
+
+// WithPodNetworks sets additional CNI networks for the pod to join.
+func WithPodNetworks(networks []string) PodCreateOption {
+ return func(pod *Pod) error {
+ if pod.valid {
+ return define.ErrPodFinalized
+ }
+
+ pod.config.InfraContainer.Networks = networks
+
+ return nil
+ }
+}
diff --git a/libpod/pod.go b/libpod/pod.go
index 3b9bb9c60..4f85caf08 100644
--- a/libpod/pod.go
+++ b/libpod/pod.go
@@ -1,6 +1,7 @@
package libpod
import (
+ "net"
"time"
"github.com/containers/libpod/libpod/define"
@@ -97,8 +98,17 @@ type PodContainerInfo struct {
// InfraContainerConfig is the configuration for the pod's infra container
type InfraContainerConfig struct {
- HasInfraContainer bool `json:"makeInfraContainer"`
- PortBindings []ocicni.PortMapping `json:"infraPortBindings"`
+ HasInfraContainer bool `json:"makeInfraContainer"`
+ PortBindings []ocicni.PortMapping `json:"infraPortBindings"`
+ StaticIP net.IP `json:"staticIP,omitempty"`
+ StaticMAC net.HardwareAddr `json:"staticMAC,omitempty"`
+ UseImageResolvConf bool `json:"useImageResolvConf,omitempty"`
+ DNSServer []string `json:"dnsServer,omitempty"`
+ DNSSearch []string `json:"dnsSearch,omitempty"`
+ DNSOption []string `json:"dnsOption,omitempty"`
+ UseImageHosts bool `json:"useImageHosts,omitempty"`
+ HostAdd []string `json:"hostsAdd,omitempty"`
+ Networks []string `json:"networks,omitempty"`
}
// ID retrieves the pod's ID
diff --git a/libpod/runtime_pod_infra_linux.go b/libpod/runtime_pod_infra_linux.go
index 6a27c2800..1b1421ca8 100644
--- a/libpod/runtime_pod_infra_linux.go
+++ b/libpod/runtime_pod_infra_linux.go
@@ -94,14 +94,38 @@ func (r *Runtime) makeInfraContainer(ctx context.Context, p *Pod, imgName, imgID
options = append(options, withIsInfra())
// Since user namespace sharing is not implemented, we only need to check if it's rootless
- networks := make([]string, 0)
netmode := "bridge"
if isRootless {
netmode = "slirp4netns"
}
// PostConfigureNetNS should not be set since user namespace sharing is not implemented
// and rootless networking no longer supports post configuration setup
- options = append(options, WithNetNS(p.config.InfraContainer.PortBindings, false, netmode, networks))
+ options = append(options, WithNetNS(p.config.InfraContainer.PortBindings, false, netmode, p.config.InfraContainer.Networks))
+
+ if p.config.InfraContainer.StaticIP != nil {
+ options = append(options, WithStaticIP(p.config.InfraContainer.StaticIP))
+ }
+ if p.config.InfraContainer.StaticMAC != nil {
+ options = append(options, WithStaticMAC(p.config.InfraContainer.StaticMAC))
+ }
+ if p.config.InfraContainer.UseImageResolvConf {
+ options = append(options, WithUseImageResolvConf())
+ }
+ if len(p.config.InfraContainer.DNSServer) > 0 {
+ options = append(options, WithDNS(p.config.InfraContainer.DNSServer))
+ }
+ if len(p.config.InfraContainer.DNSSearch) > 0 {
+ options = append(options, WithDNSSearch(p.config.InfraContainer.DNSSearch))
+ }
+ if len(p.config.InfraContainer.DNSOption) > 0 {
+ options = append(options, WithDNSOption(p.config.InfraContainer.DNSOption))
+ }
+ if p.config.InfraContainer.UseImageHosts {
+ options = append(options, WithUseImageHosts())
+ }
+ if len(p.config.InfraContainer.HostAdd) > 0 {
+ options = append(options, WithHosts(p.config.InfraContainer.HostAdd))
+ }
return r.newContainer(ctx, g.Config, options...)
}