summaryrefslogtreecommitdiff
path: root/pkg
diff options
context:
space:
mode:
Diffstat (limited to 'pkg')
-rw-r--r--pkg/api/handlers/compat/images.go76
-rw-r--r--pkg/domain/infra/abi/network.go2
-rw-r--r--pkg/machine/config.go1
-rw-r--r--pkg/machine/ignition.go17
-rw-r--r--pkg/machine/qemu/machine.go118
-rw-r--r--pkg/machine/qemu/options_darwin.go2
-rw-r--r--pkg/machine/qemu/options_darwin_amd64.go2
-rw-r--r--pkg/machine/qemu/options_linux.go10
8 files changed, 173 insertions, 55 deletions
diff --git a/pkg/api/handlers/compat/images.go b/pkg/api/handlers/compat/images.go
index 3f4320efa..7b336c470 100644
--- a/pkg/api/handlers/compat/images.go
+++ b/pkg/api/handlers/compat/images.go
@@ -1,7 +1,6 @@
package compat
import (
- "context"
"encoding/json"
"fmt"
"io/ioutil"
@@ -13,12 +12,12 @@ import (
"github.com/containers/common/libimage"
"github.com/containers/common/pkg/config"
"github.com/containers/image/v5/manifest"
+ "github.com/containers/image/v5/pkg/shortnames"
"github.com/containers/image/v5/types"
"github.com/containers/podman/v3/libpod"
"github.com/containers/podman/v3/pkg/api/handlers"
"github.com/containers/podman/v3/pkg/api/handlers/utils"
"github.com/containers/podman/v3/pkg/auth"
- "github.com/containers/podman/v3/pkg/channel"
"github.com/containers/podman/v3/pkg/domain/entities"
"github.com/containers/podman/v3/pkg/domain/infra/abi"
"github.com/containers/storage"
@@ -210,6 +209,11 @@ func CreateImageFromSrc(w http.ResponseWriter, r *http.Request) {
})
}
+type pullResult struct {
+ images []*libimage.Image
+ err error
+}
+
func CreateImageFromImage(w http.ResponseWriter, r *http.Request) {
// 200 no error
// 404 repo does not exist or no read access
@@ -231,6 +235,14 @@ func CreateImageFromImage(w http.ResponseWriter, r *http.Request) {
fromImage := mergeNameAndTagOrDigest(query.FromImage, query.Tag)
+ // without this early check this function would return 200 but reported error via body stream soon after
+ // it's better to let caller know early via HTTP status code that request cannot be processed
+ _, err := shortnames.Resolve(runtime.SystemContext(), fromImage)
+ if err != nil {
+ utils.Error(w, "Something went wrong.", http.StatusBadRequest, errors.Wrap(err, "failed to resolve image name"))
+ return
+ }
+
authConf, authfile, key, err := auth.GetCredentials(r)
if err != nil {
utils.Error(w, "failed to retrieve repository credentials", http.StatusBadRequest, errors.Wrapf(err, "failed to parse %q header for %s", key, r.URL.String()))
@@ -247,26 +259,14 @@ func CreateImageFromImage(w http.ResponseWriter, r *http.Request) {
}
pullOptions.Writer = os.Stderr // allows for debugging on the server
- stderr := channel.NewWriter(make(chan []byte))
- defer stderr.Close()
-
progress := make(chan types.ProgressProperties)
+
pullOptions.Progress = progress
- var img string
- runCtx, cancel := context.WithCancel(context.Background())
+ pullResChan := make(chan pullResult)
go func() {
- defer cancel()
- pulledImages, err := runtime.LibimageRuntime().Pull(runCtx, fromImage, config.PullPolicyAlways, pullOptions)
- if err != nil {
- stderr.Write([]byte(err.Error() + "\n"))
- } else {
- if len(pulledImages) == 0 {
- utils.Error(w, "Something went wrong.", http.StatusBadRequest, errors.New("internal error: no images pulled"))
- return
- }
- img = pulledImages[0].ID()
- }
+ pulledImages, err := runtime.LibimageRuntime().Pull(r.Context(), fromImage, config.PullPolicyAlways, pullOptions)
+ pullResChan <- pullResult{images: pulledImages, err: err}
}()
flush := func() {
@@ -281,7 +281,6 @@ func CreateImageFromImage(w http.ResponseWriter, r *http.Request) {
enc := json.NewEncoder(w)
enc.SetEscapeHTML(true)
- var failed bool
loop: // break out of for/select infinite loop
for {
@@ -312,32 +311,31 @@ loop: // break out of for/select infinite loop
}
report.Id = e.Artifact.Digest.Encoded()[0:12]
if err := enc.Encode(report); err != nil {
- stderr.Write([]byte(err.Error()))
- }
- flush()
- case e := <-stderr.Chan():
- failed = true
- report.Error = string(e)
- if err := enc.Encode(report); err != nil {
logrus.Warnf("Failed to json encode error %q", err.Error())
}
flush()
- case <-runCtx.Done():
- if !failed {
- if utils.IsLibpodRequest(r) {
- report.Status = "Pull complete"
+ case pullRes := <-pullResChan:
+ err := pullRes.err
+ pulledImages := pullRes.images
+ if err != nil {
+ report.Error = err.Error()
+ } else {
+ if len(pulledImages) > 0 {
+ img := pulledImages[0].ID()
+ if utils.IsLibpodRequest(r) {
+ report.Status = "Pull complete"
+ } else {
+ report.Status = "Download complete"
+ }
+ report.Id = img[0:12]
} else {
- report.Status = "Download complete"
- }
- report.Id = img[0:12]
- if err := enc.Encode(report); err != nil {
- logrus.Warnf("Failed to json encode error %q", err.Error())
+ report.Error = "internal error: no images pulled"
}
- flush()
}
- break loop // break out of for/select infinite loop
- case <-r.Context().Done():
- // Client has closed connection
+ if err := enc.Encode(report); err != nil {
+ logrus.Warnf("Failed to json encode error %q", err.Error())
+ }
+ flush()
break loop // break out of for/select infinite loop
}
}
diff --git a/pkg/domain/infra/abi/network.go b/pkg/domain/infra/abi/network.go
index 33ab280e5..7900caaa6 100644
--- a/pkg/domain/infra/abi/network.go
+++ b/pkg/domain/infra/abi/network.go
@@ -11,7 +11,7 @@ import (
)
func (ic *ContainerEngine) NetworkList(ctx context.Context, options entities.NetworkListOptions) ([]*entities.NetworkListReport, error) {
- var reports []*entities.NetworkListReport
+ reports := make([]*entities.NetworkListReport, 0)
config, err := ic.Libpod.GetConfig()
if err != nil {
diff --git a/pkg/machine/config.go b/pkg/machine/config.go
index 652229963..58794ce42 100644
--- a/pkg/machine/config.go
+++ b/pkg/machine/config.go
@@ -32,6 +32,7 @@ var (
ErrVMAlreadyExists = errors.New("VM already exists")
ErrVMAlreadyRunning = errors.New("VM already running")
ErrMultipleActiveVM = errors.New("only one VM can be active at a time")
+ ForwarderBinaryName = "gvproxy"
)
type Download struct {
diff --git a/pkg/machine/ignition.go b/pkg/machine/ignition.go
index 00068a136..a5c7210af 100644
--- a/pkg/machine/ignition.go
+++ b/pkg/machine/ignition.go
@@ -118,6 +118,7 @@ func getDirs(usrName string) []Directory {
// in one swoop, then the leading dirs are creates as root.
newDirs := []string{
"/home/" + usrName + "/.config",
+ "/home/" + usrName + "/.config/containers",
"/home/" + usrName + "/.config/systemd",
"/home/" + usrName + "/.config/systemd/user",
"/home/" + usrName + "/.config/systemd/user/default.target.wants",
@@ -159,6 +160,22 @@ func getFiles(usrName string) []File {
},
})
+ // Set containers.conf up for core user to use cni networks
+ // by default
+ files = append(files, File{
+ Node: Node{
+ Group: getNodeGrp(usrName),
+ Path: "/home/" + usrName + "/.config/containers/containers.conf",
+ User: getNodeUsr(usrName),
+ },
+ FileEmbedded1: FileEmbedded1{
+ Append: nil,
+ Contents: Resource{
+ Source: strToPtr("data:,%5Bcontainers%5D%0D%0Anetns%3D%22bridge%22%0D%0Arootless_networking%3D%22cni%22"),
+ },
+ Mode: intToPtr(484),
+ },
+ })
// Add a file into linger
files = append(files, File{
Node: Node{
diff --git a/pkg/machine/qemu/machine.go b/pkg/machine/qemu/machine.go
index 0bd711c90..31c355d4a 100644
--- a/pkg/machine/qemu/machine.go
+++ b/pkg/machine/qemu/machine.go
@@ -13,6 +13,8 @@ import (
"strings"
"time"
+ "github.com/containers/podman/v3/pkg/rootless"
+
"github.com/containers/podman/v3/pkg/machine"
"github.com/containers/podman/v3/utils"
"github.com/containers/storage/pkg/homedir"
@@ -82,9 +84,10 @@ func NewMachine(opts machine.InitOptions) (machine.VM, error) {
cmd = append(cmd, []string{"-qmp", monitor.Network + ":/" + monitor.Address + ",server=on,wait=off"}...)
// Add network
- cmd = append(cmd, "-nic", "user,model=virtio,hostfwd=tcp::"+strconv.Itoa(vm.Port)+"-:22")
-
- socketPath, err := getSocketDir()
+ // Right now the mac address is hardcoded so that the host networking gives it a specific IP address. This is
+ // why we can only run one vm at a time right now
+ cmd = append(cmd, []string{"-netdev", "socket,id=vlan,fd=3", "-device", "virtio-net-pci,netdev=vlan,mac=5a:94:ef:e4:0c:ee"}...)
+ socketPath, err := getRuntimeDir()
if err != nil {
return nil, err
}
@@ -235,12 +238,35 @@ func (v *MachineVM) Init(opts machine.InitOptions) error {
// Start executes the qemu command line and forks it
func (v *MachineVM) Start(name string, _ machine.StartOptions) error {
var (
- conn net.Conn
- err error
- wait time.Duration = time.Millisecond * 500
+ conn net.Conn
+ err error
+ qemuSocketConn net.Conn
+ wait time.Duration = time.Millisecond * 500
)
+ if err := v.startHostNetworking(); err != nil {
+ return errors.Errorf("unable to start host networking: %q", err)
+ }
+ qemuSocketPath, _, err := v.getSocketandPid()
+
+ for i := 0; i < 6; i++ {
+ qemuSocketConn, err = net.Dial("unix", qemuSocketPath)
+ if err == nil {
+ break
+ }
+ time.Sleep(wait)
+ wait++
+ }
+ if err != nil {
+ return err
+ }
+
+ fd, err := qemuSocketConn.(*net.UnixConn).File()
+ if err != nil {
+ return err
+ }
+
attr := new(os.ProcAttr)
- files := []*os.File{os.Stdin, os.Stdout, os.Stderr}
+ files := []*os.File{os.Stdin, os.Stdout, os.Stderr, fd}
attr.Files = files
logrus.Debug(v.CmdLine)
cmd := v.CmdLine
@@ -256,7 +282,7 @@ func (v *MachineVM) Start(name string, _ machine.StartOptions) error {
return err
}
fmt.Println("Waiting for VM ...")
- socketPath, err := getSocketDir()
+ socketPath, err := getRuntimeDir()
if err != nil {
return err
}
@@ -309,16 +335,42 @@ func (v *MachineVM) Stop(name string, _ machine.StopOptions) error {
logrus.Error(err)
}
}()
- _, err = qmpMonitor.Run(input)
- return err
+ if _, err = qmpMonitor.Run(input); err != nil {
+ return err
+ }
+ _, pidFile, err := v.getSocketandPid()
+ if err != nil {
+ return err
+ }
+ if _, err := os.Stat(pidFile); os.IsNotExist(err) {
+ logrus.Infof("pid file %s does not exist", pidFile)
+ return nil
+ }
+ pidString, err := ioutil.ReadFile(pidFile)
+ if err != nil {
+ return err
+ }
+ pidNum, err := strconv.Atoi(string(pidString))
+ if err != nil {
+ return err
+ }
+
+ p, err := os.FindProcess(pidNum)
+ if p == nil && err != nil {
+ return err
+ }
+ return p.Kill()
}
// NewQMPMonitor creates the monitor subsection of our vm
func NewQMPMonitor(network, name string, timeout time.Duration) (Monitor, error) {
- rtDir, err := getSocketDir()
+ rtDir, err := getRuntimeDir()
if err != nil {
return Monitor{}, err
}
+ if !rootless.IsRootless() {
+ rtDir = "/run"
+ }
rtDir = filepath.Join(rtDir, "podman")
if _, err := os.Stat(filepath.Join(rtDir)); os.IsNotExist(err) {
// TODO 0644 is fine on linux but macos is weird
@@ -533,3 +585,47 @@ func CheckActiveVM() (bool, string, error) {
}
return false, "", nil
}
+
+// startHostNetworking runs a binary on the host system that allows users
+// to setup port forwarding to the podman virtual machine
+func (v *MachineVM) startHostNetworking() error {
+ binary, err := exec.LookPath(machine.ForwarderBinaryName)
+ if err != nil {
+ return err
+ }
+ // Listen on all at port 7777 for setting up and tearing
+ // down forwarding
+ listenSocket := "tcp://0.0.0.0:7777"
+ qemuSocket, pidFile, err := v.getSocketandPid()
+ if err != nil {
+ return err
+ }
+ attr := new(os.ProcAttr)
+ // Pass on stdin, stdout, stderr
+ files := []*os.File{os.Stdin, os.Stdout, os.Stderr}
+ attr.Files = files
+ cmd := []string{binary}
+ cmd = append(cmd, []string{"-listen", listenSocket, "-listen-qemu", fmt.Sprintf("unix://%s", qemuSocket), "-pid-file", pidFile}...)
+ // Add the ssh port
+ cmd = append(cmd, []string{"-ssh-port", fmt.Sprintf("%d", v.Port)}...)
+ if logrus.GetLevel() == logrus.DebugLevel {
+ cmd = append(cmd, "--debug")
+ fmt.Println(cmd)
+ }
+ _, err = os.StartProcess(cmd[0], cmd, attr)
+ return err
+}
+
+func (v *MachineVM) getSocketandPid() (string, string, error) {
+ rtPath, err := getRuntimeDir()
+ if err != nil {
+ return "", "", err
+ }
+ if !rootless.IsRootless() {
+ rtPath = "/run"
+ }
+ socketDir := filepath.Join(rtPath, "podman")
+ pidFile := filepath.Join(socketDir, fmt.Sprintf("%s.pid", v.Name))
+ qemuSocket := filepath.Join(socketDir, fmt.Sprintf("qemu_%s.sock", v.Name))
+ return qemuSocket, pidFile, nil
+}
diff --git a/pkg/machine/qemu/options_darwin.go b/pkg/machine/qemu/options_darwin.go
index 46ccf24cb..440937131 100644
--- a/pkg/machine/qemu/options_darwin.go
+++ b/pkg/machine/qemu/options_darwin.go
@@ -6,7 +6,7 @@ import (
"github.com/pkg/errors"
)
-func getSocketDir() (string, error) {
+func getRuntimeDir() (string, error) {
tmpDir, ok := os.LookupEnv("TMPDIR")
if !ok {
return "", errors.New("unable to resolve TMPDIR")
diff --git a/pkg/machine/qemu/options_darwin_amd64.go b/pkg/machine/qemu/options_darwin_amd64.go
index 69f7982b2..ee1036291 100644
--- a/pkg/machine/qemu/options_darwin_amd64.go
+++ b/pkg/machine/qemu/options_darwin_amd64.go
@@ -5,7 +5,7 @@ var (
)
func (v *MachineVM) addArchOptions() []string {
- opts := []string{"-cpu", "host"}
+ opts := []string{"-machine", "q35,accel=hvf:tcg"}
return opts
}
diff --git a/pkg/machine/qemu/options_linux.go b/pkg/machine/qemu/options_linux.go
index 0a2e40d8f..c73a68cc6 100644
--- a/pkg/machine/qemu/options_linux.go
+++ b/pkg/machine/qemu/options_linux.go
@@ -1,7 +1,13 @@
package qemu
-import "github.com/containers/podman/v3/pkg/util"
+import (
+ "github.com/containers/podman/v3/pkg/rootless"
+ "github.com/containers/podman/v3/pkg/util"
+)
-func getSocketDir() (string, error) {
+func getRuntimeDir() (string, error) {
+ if !rootless.IsRootless() {
+ return "/run", nil
+ }
return util.GetRuntimeDir()
}