mirror of
https://github.com/containers/podman.git
synced 2025-09-19 12:56:57 +08:00
Refactor compat container create endpoint
* Make endpoint compatibile with docker-py network expectations * Update specgen helper when called from compat endpoint * Update godoc on types * Add test for network/container create using docker-py method * Add syslog logging when DEBUG=1 for tests Fixes #8361 Signed-off-by: Jhon Honce <jhonce@redhat.com>
This commit is contained in:
@ -134,7 +134,6 @@ func stringMaptoArray(m map[string]string) []string {
|
|||||||
// a specgen spec.
|
// a specgen spec.
|
||||||
func ContainerCreateToContainerCLIOpts(cc handlers.CreateContainerConfig, cgroupsManager string) (*ContainerCLIOpts, []string, error) {
|
func ContainerCreateToContainerCLIOpts(cc handlers.CreateContainerConfig, cgroupsManager string) (*ContainerCLIOpts, []string, error) {
|
||||||
var (
|
var (
|
||||||
aliases []string
|
|
||||||
capAdd []string
|
capAdd []string
|
||||||
cappDrop []string
|
cappDrop []string
|
||||||
entrypoint *string
|
entrypoint *string
|
||||||
@ -212,7 +211,7 @@ func ContainerCreateToContainerCLIOpts(cc handlers.CreateContainerConfig, cgroup
|
|||||||
mounts = append(mounts, mount)
|
mounts = append(mounts, mount)
|
||||||
}
|
}
|
||||||
|
|
||||||
//volumes
|
// volumes
|
||||||
volumes := make([]string, 0, len(cc.Config.Volumes))
|
volumes := make([]string, 0, len(cc.Config.Volumes))
|
||||||
for v := range cc.Config.Volumes {
|
for v := range cc.Config.Volumes {
|
||||||
volumes = append(volumes, v)
|
volumes = append(volumes, v)
|
||||||
@ -242,16 +241,6 @@ func ContainerCreateToContainerCLIOpts(cc handlers.CreateContainerConfig, cgroup
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// network names
|
|
||||||
endpointsConfig := cc.NetworkingConfig.EndpointsConfig
|
|
||||||
cniNetworks := make([]string, 0, len(endpointsConfig))
|
|
||||||
for netName, endpoint := range endpointsConfig {
|
|
||||||
cniNetworks = append(cniNetworks, netName)
|
|
||||||
if len(endpoint.Aliases) > 0 {
|
|
||||||
aliases = append(aliases, endpoint.Aliases...)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// netMode
|
// netMode
|
||||||
nsmode, _, err := specgen.ParseNetworkNamespace(cc.HostConfig.NetworkMode.NetworkName())
|
nsmode, _, err := specgen.ParseNetworkNamespace(cc.HostConfig.NetworkMode.NetworkName())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -268,8 +257,6 @@ func ContainerCreateToContainerCLIOpts(cc handlers.CreateContainerConfig, cgroup
|
|||||||
// defined when there is only one network.
|
// defined when there is only one network.
|
||||||
netInfo := entities.NetOptions{
|
netInfo := entities.NetOptions{
|
||||||
AddHosts: cc.HostConfig.ExtraHosts,
|
AddHosts: cc.HostConfig.ExtraHosts,
|
||||||
Aliases: aliases,
|
|
||||||
CNINetworks: cniNetworks,
|
|
||||||
DNSOptions: cc.HostConfig.DNSOptions,
|
DNSOptions: cc.HostConfig.DNSOptions,
|
||||||
DNSSearch: cc.HostConfig.DNSSearch,
|
DNSSearch: cc.HostConfig.DNSSearch,
|
||||||
DNSServers: dns,
|
DNSServers: dns,
|
||||||
@ -277,31 +264,58 @@ func ContainerCreateToContainerCLIOpts(cc handlers.CreateContainerConfig, cgroup
|
|||||||
PublishPorts: specPorts,
|
PublishPorts: specPorts,
|
||||||
}
|
}
|
||||||
|
|
||||||
// static IP and MAC
|
// network names
|
||||||
if len(endpointsConfig) == 1 {
|
switch {
|
||||||
for _, ep := range endpointsConfig {
|
case len(cc.NetworkingConfig.EndpointsConfig) > 0:
|
||||||
// if IP address is provided
|
var aliases []string
|
||||||
if len(ep.IPAddress) > 0 {
|
|
||||||
staticIP := net.ParseIP(ep.IPAddress)
|
endpointsConfig := cc.NetworkingConfig.EndpointsConfig
|
||||||
netInfo.StaticIP = &staticIP
|
cniNetworks := make([]string, 0, len(endpointsConfig))
|
||||||
|
for netName, endpoint := range endpointsConfig {
|
||||||
|
|
||||||
|
cniNetworks = append(cniNetworks, netName)
|
||||||
|
|
||||||
|
if endpoint == nil {
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
// If MAC address is provided
|
if len(endpoint.Aliases) > 0 {
|
||||||
if len(ep.MacAddress) > 0 {
|
aliases = append(aliases, endpoint.Aliases...)
|
||||||
staticMac, err := net.ParseMAC(ep.MacAddress)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
netInfo.StaticMAC = &staticMac
|
|
||||||
}
|
}
|
||||||
break
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// static IP and MAC
|
||||||
|
if len(endpointsConfig) == 1 {
|
||||||
|
for _, ep := range endpointsConfig {
|
||||||
|
if ep == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
// if IP address is provided
|
||||||
|
if len(ep.IPAddress) > 0 {
|
||||||
|
staticIP := net.ParseIP(ep.IPAddress)
|
||||||
|
netInfo.StaticIP = &staticIP
|
||||||
|
}
|
||||||
|
// If MAC address is provided
|
||||||
|
if len(ep.MacAddress) > 0 {
|
||||||
|
staticMac, err := net.ParseMAC(ep.MacAddress)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
netInfo.StaticMAC = &staticMac
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
netInfo.Aliases = aliases
|
||||||
|
netInfo.CNINetworks = cniNetworks
|
||||||
|
case len(cc.HostConfig.NetworkMode) > 0:
|
||||||
|
netInfo.CNINetworks = []string{string(cc.HostConfig.NetworkMode)}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Note: several options here are marked as "don't need". this is based
|
// Note: several options here are marked as "don't need". this is based
|
||||||
// on speculation by Matt and I. We think that these come into play later
|
// on speculation by Matt and I. We think that these come into play later
|
||||||
// like with start. We believe this is just a difference in podman/compat
|
// like with start. We believe this is just a difference in podman/compat
|
||||||
cliOpts := ContainerCLIOpts{
|
cliOpts := ContainerCLIOpts{
|
||||||
//Attach: nil, // dont need?
|
// Attach: nil, // dont need?
|
||||||
Authfile: "",
|
Authfile: "",
|
||||||
CapAdd: append(capAdd, cc.HostConfig.CapAdd...),
|
CapAdd: append(capAdd, cc.HostConfig.CapAdd...),
|
||||||
CapDrop: append(cappDrop, cc.HostConfig.CapDrop...),
|
CapDrop: append(cappDrop, cc.HostConfig.CapDrop...),
|
||||||
@ -312,11 +326,11 @@ func ContainerCreateToContainerCLIOpts(cc handlers.CreateContainerConfig, cgroup
|
|||||||
CPURTPeriod: uint64(cc.HostConfig.CPURealtimePeriod),
|
CPURTPeriod: uint64(cc.HostConfig.CPURealtimePeriod),
|
||||||
CPURTRuntime: cc.HostConfig.CPURealtimeRuntime,
|
CPURTRuntime: cc.HostConfig.CPURealtimeRuntime,
|
||||||
CPUShares: uint64(cc.HostConfig.CPUShares),
|
CPUShares: uint64(cc.HostConfig.CPUShares),
|
||||||
//CPUS: 0, // dont need?
|
// CPUS: 0, // dont need?
|
||||||
CPUSetCPUs: cc.HostConfig.CpusetCpus,
|
CPUSetCPUs: cc.HostConfig.CpusetCpus,
|
||||||
CPUSetMems: cc.HostConfig.CpusetMems,
|
CPUSetMems: cc.HostConfig.CpusetMems,
|
||||||
//Detach: false, // dont need
|
// Detach: false, // dont need
|
||||||
//DetachKeys: "", // dont need
|
// DetachKeys: "", // dont need
|
||||||
Devices: devices,
|
Devices: devices,
|
||||||
DeviceCGroupRule: nil,
|
DeviceCGroupRule: nil,
|
||||||
DeviceReadBPs: readBps,
|
DeviceReadBPs: readBps,
|
||||||
@ -438,7 +452,7 @@ func ContainerCreateToContainerCLIOpts(cc handlers.CreateContainerConfig, cgroup
|
|||||||
}
|
}
|
||||||
|
|
||||||
// specgen assumes the image name is arg[0]
|
// specgen assumes the image name is arg[0]
|
||||||
cmd := []string{cc.Image}
|
cmd := []string{cc.Config.Image}
|
||||||
cmd = append(cmd, cc.Config.Cmd...)
|
cmd = append(cmd, cc.Config.Cmd...)
|
||||||
return &cliOpts, cmd, nil
|
return &cliOpts, cmd, nil
|
||||||
}
|
}
|
||||||
|
@ -900,7 +900,7 @@ func (c *Container) getContainerNetworkInfo() (*define.InspectNetworkSettings, e
|
|||||||
// If we have CNI networks - handle that here
|
// If we have CNI networks - handle that here
|
||||||
if len(networks) > 0 && !isDefault {
|
if len(networks) > 0 && !isDefault {
|
||||||
if len(networks) != len(c.state.NetworkStatus) {
|
if len(networks) != len(c.state.NetworkStatus) {
|
||||||
return nil, errors.Wrapf(define.ErrInternal, "network inspection mismatch: asked to join %d CNI networks but have information on %d networks", len(networks), len(c.state.NetworkStatus))
|
return nil, errors.Wrapf(define.ErrInternal, "network inspection mismatch: asked to join %d CNI network(s) %v, but have information on %d network(s)", len(networks), networks, len(c.state.NetworkStatus))
|
||||||
}
|
}
|
||||||
|
|
||||||
settings.Networks = make(map[string]*define.InspectAdditionalNetwork)
|
settings.Networks = make(map[string]*define.InspectAdditionalNetwork)
|
||||||
|
@ -19,7 +19,6 @@ import (
|
|||||||
func CreateContainer(w http.ResponseWriter, r *http.Request) {
|
func CreateContainer(w http.ResponseWriter, r *http.Request) {
|
||||||
runtime := r.Context().Value("runtime").(*libpod.Runtime)
|
runtime := r.Context().Value("runtime").(*libpod.Runtime)
|
||||||
decoder := r.Context().Value("decoder").(*schema.Decoder)
|
decoder := r.Context().Value("decoder").(*schema.Decoder)
|
||||||
input := handlers.CreateContainerConfig{}
|
|
||||||
query := struct {
|
query := struct {
|
||||||
Name string `schema:"name"`
|
Name string `schema:"name"`
|
||||||
}{
|
}{
|
||||||
@ -30,11 +29,15 @@ func CreateContainer(w http.ResponseWriter, r *http.Request) {
|
|||||||
errors.Wrapf(err, "failed to parse parameters for %s", r.URL.String()))
|
errors.Wrapf(err, "failed to parse parameters for %s", r.URL.String()))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if err := json.NewDecoder(r.Body).Decode(&input); err != nil {
|
|
||||||
|
// compatible configuration
|
||||||
|
body := handlers.CreateContainerConfig{}
|
||||||
|
if err := json.NewDecoder(r.Body).Decode(&body); err != nil {
|
||||||
utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "Decode()"))
|
utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "Decode()"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if len(input.HostConfig.Links) > 0 {
|
|
||||||
|
if len(body.HostConfig.Links) > 0 {
|
||||||
utils.Error(w, utils.ErrLinkNotSupport.Error(), http.StatusBadRequest, errors.Wrapf(utils.ErrLinkNotSupport, "bad parameter"))
|
utils.Error(w, utils.ErrLinkNotSupport.Error(), http.StatusBadRequest, errors.Wrapf(utils.ErrLinkNotSupport, "bad parameter"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -43,7 +46,7 @@ func CreateContainer(w http.ResponseWriter, r *http.Request) {
|
|||||||
utils.Error(w, "unable to obtain runtime config", http.StatusInternalServerError, errors.Wrap(err, "unable to get runtime config"))
|
utils.Error(w, "unable to obtain runtime config", http.StatusInternalServerError, errors.Wrap(err, "unable to get runtime config"))
|
||||||
}
|
}
|
||||||
|
|
||||||
newImage, err := runtime.ImageRuntime().NewFromLocal(input.Image)
|
newImage, err := runtime.ImageRuntime().NewFromLocal(body.Config.Image)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Cause(err) == define.ErrNoSuchImage {
|
if errors.Cause(err) == define.ErrNoSuchImage {
|
||||||
utils.Error(w, "No such image", http.StatusNotFound, err)
|
utils.Error(w, "No such image", http.StatusNotFound, err)
|
||||||
@ -54,11 +57,8 @@ func CreateContainer(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add the container name to the input struct
|
// Take body structure and convert to cliopts
|
||||||
input.Name = query.Name
|
cliOpts, args, err := common.ContainerCreateToContainerCLIOpts(body, rtc.Engine.CgroupManager)
|
||||||
|
|
||||||
// Take input structure and convert to cliopts
|
|
||||||
cliOpts, args, err := common.ContainerCreateToContainerCLIOpts(input, rtc.Engine.CgroupManager)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "make cli opts()"))
|
utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "make cli opts()"))
|
||||||
return
|
return
|
||||||
@ -69,6 +69,9 @@ func CreateContainer(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Override the container name in the body struct
|
||||||
|
body.Name = query.Name
|
||||||
|
|
||||||
ic := abi.ContainerEngine{Libpod: runtime}
|
ic := abi.ContainerEngine{Libpod: runtime}
|
||||||
report, err := ic.ContainerCreate(r.Context(), sg)
|
report, err := ic.ContainerCreate(r.Context(), sg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -110,11 +110,12 @@ type ContainerWaitOKBody struct {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CreateContainerConfig used when compatible endpoint creates a container
|
||||||
type CreateContainerConfig struct {
|
type CreateContainerConfig struct {
|
||||||
Name string
|
Name string // container name
|
||||||
dockerContainer.Config
|
dockerContainer.Config // desired container configuration
|
||||||
HostConfig dockerContainer.HostConfig
|
HostConfig dockerContainer.HostConfig // host dependent configuration for container
|
||||||
NetworkingConfig dockerNetwork.NetworkingConfig
|
NetworkingConfig dockerNetwork.NetworkingConfig // network configuration for container
|
||||||
}
|
}
|
||||||
|
|
||||||
// swagger:model IDResponse
|
// swagger:model IDResponse
|
||||||
@ -253,7 +254,7 @@ func ImageDataToImageInspect(ctx context.Context, l *libpodImage.Image) (*ImageI
|
|||||||
// StdinOnce: false,
|
// StdinOnce: false,
|
||||||
Env: info.Config.Env,
|
Env: info.Config.Env,
|
||||||
Cmd: info.Config.Cmd,
|
Cmd: info.Config.Cmd,
|
||||||
//Healthcheck: l.ImageData.HealthCheck,
|
// Healthcheck: l.ImageData.HealthCheck,
|
||||||
// ArgsEscaped: false,
|
// ArgsEscaped: false,
|
||||||
// Image: "",
|
// Image: "",
|
||||||
Volumes: info.Config.Volumes,
|
Volumes: info.Config.Volumes,
|
||||||
@ -261,7 +262,7 @@ func ImageDataToImageInspect(ctx context.Context, l *libpodImage.Image) (*ImageI
|
|||||||
Entrypoint: info.Config.Entrypoint,
|
Entrypoint: info.Config.Entrypoint,
|
||||||
// NetworkDisabled: false,
|
// NetworkDisabled: false,
|
||||||
// MacAddress: "",
|
// MacAddress: "",
|
||||||
//OnBuild: info.Config.OnBuild,
|
// OnBuild: info.Config.OnBuild,
|
||||||
Labels: info.Labels,
|
Labels: info.Labels,
|
||||||
StopSignal: info.Config.StopSignal,
|
StopSignal: info.Config.StopSignal,
|
||||||
// StopTimeout: nil,
|
// StopTimeout: nil,
|
||||||
|
@ -16,19 +16,18 @@ class Podman(object):
|
|||||||
binary = os.getenv("PODMAN", "bin/podman")
|
binary = os.getenv("PODMAN", "bin/podman")
|
||||||
self.cmd = [binary, "--storage-driver=vfs"]
|
self.cmd = [binary, "--storage-driver=vfs"]
|
||||||
|
|
||||||
cgroupfs = os.getenv("CGROUP_MANAGER", "cgroupfs")
|
cgroupfs = os.getenv("CGROUP_MANAGER", "systemd")
|
||||||
self.cmd.append(f"--cgroup-manager={cgroupfs}")
|
self.cmd.append(f"--cgroup-manager={cgroupfs}")
|
||||||
|
|
||||||
if os.getenv("DEBUG"):
|
if os.getenv("DEBUG"):
|
||||||
self.cmd.append("--log-level=debug")
|
self.cmd.append("--log-level=debug")
|
||||||
|
self.cmd.append("--syslog=true")
|
||||||
|
|
||||||
self.anchor_directory = tempfile.mkdtemp(prefix="podman_restapi_")
|
self.anchor_directory = tempfile.mkdtemp(prefix="podman_restapi_")
|
||||||
self.cmd.append("--root=" + os.path.join(self.anchor_directory, "crio"))
|
self.cmd.append("--root=" + os.path.join(self.anchor_directory, "crio"))
|
||||||
self.cmd.append("--runroot=" + os.path.join(self.anchor_directory, "crio-run"))
|
self.cmd.append("--runroot=" + os.path.join(self.anchor_directory, "crio-run"))
|
||||||
|
|
||||||
os.environ["REGISTRIES_CONFIG_PATH"] = os.path.join(
|
os.environ["REGISTRIES_CONFIG_PATH"] = os.path.join(self.anchor_directory, "registry.conf")
|
||||||
self.anchor_directory, "registry.conf"
|
|
||||||
)
|
|
||||||
p = configparser.ConfigParser()
|
p = configparser.ConfigParser()
|
||||||
p.read_dict(
|
p.read_dict(
|
||||||
{
|
{
|
||||||
@ -40,14 +39,10 @@ class Podman(object):
|
|||||||
with open(os.environ["REGISTRIES_CONFIG_PATH"], "w") as w:
|
with open(os.environ["REGISTRIES_CONFIG_PATH"], "w") as w:
|
||||||
p.write(w)
|
p.write(w)
|
||||||
|
|
||||||
os.environ["CNI_CONFIG_PATH"] = os.path.join(
|
os.environ["CNI_CONFIG_PATH"] = os.path.join(self.anchor_directory, "cni", "net.d")
|
||||||
self.anchor_directory, "cni", "net.d"
|
|
||||||
)
|
|
||||||
os.makedirs(os.environ["CNI_CONFIG_PATH"], exist_ok=True)
|
os.makedirs(os.environ["CNI_CONFIG_PATH"], exist_ok=True)
|
||||||
self.cmd.append("--cni-config-dir=" + os.environ["CNI_CONFIG_PATH"])
|
self.cmd.append("--cni-config-dir=" + os.environ["CNI_CONFIG_PATH"])
|
||||||
cni_cfg = os.path.join(
|
cni_cfg = os.path.join(os.environ["CNI_CONFIG_PATH"], "87-podman-bridge.conflist")
|
||||||
os.environ["CNI_CONFIG_PATH"], "87-podman-bridge.conflist"
|
|
||||||
)
|
|
||||||
# json decoded and encoded to ensure legal json
|
# json decoded and encoded to ensure legal json
|
||||||
buf = json.loads(
|
buf = json.loads(
|
||||||
"""
|
"""
|
||||||
|
@ -61,9 +61,7 @@ class TestApi(unittest.TestCase):
|
|||||||
super().setUpClass()
|
super().setUpClass()
|
||||||
|
|
||||||
TestApi.podman = Podman()
|
TestApi.podman = Podman()
|
||||||
TestApi.service = TestApi.podman.open(
|
TestApi.service = TestApi.podman.open("system", "service", "tcp:localhost:8080", "--time=0")
|
||||||
"system", "service", "tcp:localhost:8080", "--time=0"
|
|
||||||
)
|
|
||||||
# give the service some time to be ready...
|
# give the service some time to be ready...
|
||||||
time.sleep(2)
|
time.sleep(2)
|
||||||
|
|
||||||
@ -165,11 +163,71 @@ class TestApi(unittest.TestCase):
|
|||||||
r = requests.get(_url(ctnr("/containers/{}/logs?stdout=true")))
|
r = requests.get(_url(ctnr("/containers/{}/logs?stdout=true")))
|
||||||
self.assertEqual(r.status_code, 200, r.text)
|
self.assertEqual(r.status_code, 200, r.text)
|
||||||
|
|
||||||
def test_post_create_compat(self):
|
# TODO Need to support Docker-py order of network/container creates
|
||||||
|
def test_post_create_compat_connect(self):
|
||||||
"""Create network and container then connect to network"""
|
"""Create network and container then connect to network"""
|
||||||
net = requests.post(
|
net_default = requests.post(
|
||||||
PODMAN_URL + "/v1.40/networks/create", json={"Name": "TestNetwork"}
|
PODMAN_URL + "/v1.40/networks/create", json={"Name": "TestDefaultNetwork"}
|
||||||
)
|
)
|
||||||
|
self.assertEqual(net_default.status_code, 201, net_default.text)
|
||||||
|
|
||||||
|
create = requests.post(
|
||||||
|
PODMAN_URL + "/v1.40/containers/create?name=postCreate",
|
||||||
|
json={
|
||||||
|
"Cmd": ["top"],
|
||||||
|
"Image": "alpine:latest",
|
||||||
|
"NetworkDisabled": False,
|
||||||
|
# FIXME adding these 2 lines cause: (This is sampled from docker-py)
|
||||||
|
# "network already exists","message":"container
|
||||||
|
# 01306e499df5441560d70071a54342611e422a94de20865add50a9565fd79fb9 is already connected to CNI network \"TestDefaultNetwork\": network already exists"
|
||||||
|
# "HostConfig": {"NetworkMode": "TestDefaultNetwork"},
|
||||||
|
# "NetworkingConfig": {"EndpointsConfig": {"TestDefaultNetwork": None}},
|
||||||
|
# FIXME These two lines cause:
|
||||||
|
# CNI network \"TestNetwork\" not found","message":"error configuring network namespace for container 369ddfa7d3211ebf1fbd5ddbff91bd33fa948858cea2985c133d6b6507546dff: CNI network \"TestNetwork\" not found"
|
||||||
|
# "HostConfig": {"NetworkMode": "TestNetwork"},
|
||||||
|
# "NetworkingConfig": {"EndpointsConfig": {"TestNetwork": None}},
|
||||||
|
# FIXME no networking defined cause: (note this error is from the container inspect below)
|
||||||
|
# "internal libpod error","message":"network inspection mismatch: asked to join 2 CNI network(s) [TestDefaultNetwork podman], but have information on 1 network(s): internal libpod error"
|
||||||
|
},
|
||||||
|
)
|
||||||
|
self.assertEqual(create.status_code, 201, create.text)
|
||||||
|
payload = json.loads(create.text)
|
||||||
|
self.assertIsNotNone(payload["Id"])
|
||||||
|
|
||||||
|
start = requests.post(PODMAN_URL + f"/v1.40/containers/{payload['Id']}/start")
|
||||||
|
self.assertEqual(start.status_code, 204, start.text)
|
||||||
|
|
||||||
|
connect = requests.post(
|
||||||
|
PODMAN_URL + "/v1.40/networks/TestDefaultNetwork/connect",
|
||||||
|
json={"Container": payload["Id"]},
|
||||||
|
)
|
||||||
|
self.assertEqual(connect.status_code, 200, connect.text)
|
||||||
|
self.assertEqual(connect.text, "OK\n")
|
||||||
|
|
||||||
|
inspect = requests.get(f"{PODMAN_URL}/v1.40/containers/{payload['Id']}/json")
|
||||||
|
self.assertEqual(inspect.status_code, 200, inspect.text)
|
||||||
|
|
||||||
|
payload = json.loads(inspect.text)
|
||||||
|
self.assertFalse(payload["Config"].get("NetworkDisabled", False))
|
||||||
|
|
||||||
|
self.assertEqual(
|
||||||
|
"TestDefaultNetwork",
|
||||||
|
payload["NetworkSettings"]["Networks"]["TestDefaultNetwork"]["NetworkID"],
|
||||||
|
)
|
||||||
|
# TODO restore this to test, when joining multiple networks possible
|
||||||
|
# self.assertEqual(
|
||||||
|
# "TestNetwork",
|
||||||
|
# payload["NetworkSettings"]["Networks"]["TestNetwork"]["NetworkID"],
|
||||||
|
# )
|
||||||
|
# TODO Need to support network aliases
|
||||||
|
# self.assertIn(
|
||||||
|
# "test_post_create",
|
||||||
|
# payload["NetworkSettings"]["Networks"]["TestNetwork"]["Aliases"],
|
||||||
|
# )
|
||||||
|
|
||||||
|
def test_post_create_compat(self):
|
||||||
|
"""Create network and connect container during create"""
|
||||||
|
net = requests.post(PODMAN_URL + "/v1.40/networks/create", json={"Name": "TestNetwork"})
|
||||||
self.assertEqual(net.status_code, 201, net.text)
|
self.assertEqual(net.status_code, 201, net.text)
|
||||||
|
|
||||||
create = requests.post(
|
create = requests.post(
|
||||||
@ -178,23 +236,21 @@ class TestApi(unittest.TestCase):
|
|||||||
"Cmd": ["date"],
|
"Cmd": ["date"],
|
||||||
"Image": "alpine:latest",
|
"Image": "alpine:latest",
|
||||||
"NetworkDisabled": False,
|
"NetworkDisabled": False,
|
||||||
"NetworkConfig": {
|
"HostConfig": {"NetworkMode": "TestNetwork"},
|
||||||
"EndpointConfig": {"TestNetwork": {"Aliases": ["test_post_create"]}}
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
self.assertEqual(create.status_code, 201, create.text)
|
self.assertEqual(create.status_code, 201, create.text)
|
||||||
payload = json.loads(create.text)
|
payload = json.loads(create.text)
|
||||||
self.assertIsNotNone(payload["Id"])
|
self.assertIsNotNone(payload["Id"])
|
||||||
|
|
||||||
# This cannot be done until full completion of the network connect
|
inspect = requests.get(f"{PODMAN_URL}/v1.40/containers/{payload['Id']}/json")
|
||||||
# stack and network disconnect stack are complete
|
self.assertEqual(inspect.status_code, 200, inspect.text)
|
||||||
# connect = requests.post(
|
payload = json.loads(inspect.text)
|
||||||
# PODMAN_URL + "/v1.40/networks/TestNetwork/connect",
|
self.assertFalse(payload["Config"].get("NetworkDisabled", False))
|
||||||
# json={"Container": payload["Id"]},
|
self.assertEqual(
|
||||||
# )
|
"TestNetwork",
|
||||||
# self.assertEqual(connect.status_code, 200, connect.text)
|
payload["NetworkSettings"]["Networks"]["TestNetwork"]["NetworkID"],
|
||||||
# self.assertEqual(connect.text, "OK\n")
|
)
|
||||||
|
|
||||||
def test_commit(self):
|
def test_commit(self):
|
||||||
r = requests.post(_url(ctnr("/commit?container={}")))
|
r = requests.post(_url(ctnr("/commit?container={}")))
|
||||||
|
@ -84,9 +84,7 @@ class TestApi(unittest.TestCase):
|
|||||||
print("\nService Stderr:\n" + stderr.decode("utf-8"))
|
print("\nService Stderr:\n" + stderr.decode("utf-8"))
|
||||||
|
|
||||||
if TestApi.podman.returncode > 0:
|
if TestApi.podman.returncode > 0:
|
||||||
sys.stderr.write(
|
sys.stderr.write("podman exited with error code {}\n".format(TestApi.podman.returncode))
|
||||||
"podman exited with error code {}\n".format(TestApi.podman.returncode)
|
|
||||||
)
|
|
||||||
sys.exit(2)
|
sys.exit(2)
|
||||||
|
|
||||||
return super().tearDownClass()
|
return super().tearDownClass()
|
||||||
|
@ -39,9 +39,7 @@ class Podman(object):
|
|||||||
self.cmd.append("--root=" + os.path.join(self.anchor_directory, "crio"))
|
self.cmd.append("--root=" + os.path.join(self.anchor_directory, "crio"))
|
||||||
self.cmd.append("--runroot=" + os.path.join(self.anchor_directory, "crio-run"))
|
self.cmd.append("--runroot=" + os.path.join(self.anchor_directory, "crio-run"))
|
||||||
|
|
||||||
os.environ["REGISTRIES_CONFIG_PATH"] = os.path.join(
|
os.environ["REGISTRIES_CONFIG_PATH"] = os.path.join(self.anchor_directory, "registry.conf")
|
||||||
self.anchor_directory, "registry.conf"
|
|
||||||
)
|
|
||||||
p = configparser.ConfigParser()
|
p = configparser.ConfigParser()
|
||||||
p.read_dict(
|
p.read_dict(
|
||||||
{
|
{
|
||||||
@ -53,14 +51,10 @@ class Podman(object):
|
|||||||
with open(os.environ["REGISTRIES_CONFIG_PATH"], "w") as w:
|
with open(os.environ["REGISTRIES_CONFIG_PATH"], "w") as w:
|
||||||
p.write(w)
|
p.write(w)
|
||||||
|
|
||||||
os.environ["CNI_CONFIG_PATH"] = os.path.join(
|
os.environ["CNI_CONFIG_PATH"] = os.path.join(self.anchor_directory, "cni", "net.d")
|
||||||
self.anchor_directory, "cni", "net.d"
|
|
||||||
)
|
|
||||||
os.makedirs(os.environ["CNI_CONFIG_PATH"], exist_ok=True)
|
os.makedirs(os.environ["CNI_CONFIG_PATH"], exist_ok=True)
|
||||||
self.cmd.append("--cni-config-dir=" + os.environ["CNI_CONFIG_PATH"])
|
self.cmd.append("--cni-config-dir=" + os.environ["CNI_CONFIG_PATH"])
|
||||||
cni_cfg = os.path.join(
|
cni_cfg = os.path.join(os.environ["CNI_CONFIG_PATH"], "87-podman-bridge.conflist")
|
||||||
os.environ["CNI_CONFIG_PATH"], "87-podman-bridge.conflist"
|
|
||||||
)
|
|
||||||
# json decoded and encoded to ensure legal json
|
# json decoded and encoded to ensure legal json
|
||||||
buf = json.loads(
|
buf = json.loads(
|
||||||
"""
|
"""
|
||||||
|
@ -4,9 +4,7 @@ from test.python.docker import constant
|
|||||||
|
|
||||||
|
|
||||||
def run_top_container(client: DockerClient):
|
def run_top_container(client: DockerClient):
|
||||||
c = client.containers.create(
|
c = client.containers.create(constant.ALPINE, command="top", detach=True, tty=True, name="top")
|
||||||
constant.ALPINE, command="top", detach=True, tty=True, name="top"
|
|
||||||
)
|
|
||||||
c.start()
|
c.start()
|
||||||
return c.id
|
return c.id
|
||||||
|
|
||||||
|
@ -78,9 +78,7 @@ class TestImages(unittest.TestCase):
|
|||||||
self.assertEqual(len(self.client.images.list()), 2)
|
self.assertEqual(len(self.client.images.list()), 2)
|
||||||
|
|
||||||
# List images with filter
|
# List images with filter
|
||||||
self.assertEqual(
|
self.assertEqual(len(self.client.images.list(filters={"reference": "alpine"})), 1)
|
||||||
len(self.client.images.list(filters={"reference": "alpine"})), 1
|
|
||||||
)
|
|
||||||
|
|
||||||
def test_search_image(self):
|
def test_search_image(self):
|
||||||
"""Search for image"""
|
"""Search for image"""
|
||||||
|
Reference in New Issue
Block a user