mirror of
https://github.com/containers/podman.git
synced 2025-06-27 21:50:18 +08:00
Merge pull request #9759 from EduardoVega/9129-multi-docs-kube
Support multi doc yaml for generate/play kube
This commit is contained in:
2
go.mod
2
go.mod
@ -66,7 +66,7 @@ require (
|
|||||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9
|
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9
|
||||||
golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005
|
golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005
|
||||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect
|
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776 // indirect
|
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776
|
||||||
k8s.io/api v0.20.5
|
k8s.io/api v0.20.5
|
||||||
k8s.io/apimachinery v0.20.5
|
k8s.io/apimachinery v0.20.5
|
||||||
)
|
)
|
||||||
|
@ -44,11 +44,10 @@ func (ic *ContainerEngine) GenerateSystemd(ctx context.Context, nameOrID string,
|
|||||||
func (ic *ContainerEngine) GenerateKube(ctx context.Context, nameOrIDs []string, options entities.GenerateKubeOptions) (*entities.GenerateKubeReport, error) {
|
func (ic *ContainerEngine) GenerateKube(ctx context.Context, nameOrIDs []string, options entities.GenerateKubeOptions) (*entities.GenerateKubeReport, error) {
|
||||||
var (
|
var (
|
||||||
pods []*libpod.Pod
|
pods []*libpod.Pod
|
||||||
podYAML *k8sAPI.Pod
|
|
||||||
err error
|
|
||||||
ctrs []*libpod.Container
|
ctrs []*libpod.Container
|
||||||
servicePorts []k8sAPI.ServicePort
|
kubePods []*k8sAPI.Pod
|
||||||
serviceYAML k8sAPI.Service
|
kubeServices []k8sAPI.Service
|
||||||
|
content []byte
|
||||||
)
|
)
|
||||||
for _, nameOrID := range nameOrIDs {
|
for _, nameOrID := range nameOrIDs {
|
||||||
// Get the container in question
|
// Get the container in question
|
||||||
@ -59,9 +58,6 @@ func (ic *ContainerEngine) GenerateKube(ctx context.Context, nameOrIDs []string,
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
pods = append(pods, pod)
|
pods = append(pods, pod)
|
||||||
if len(pods) > 1 {
|
|
||||||
return nil, errors.New("can only generate single pod at a time")
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
if len(ctr.Dependencies()) > 0 {
|
if len(ctr.Dependencies()) > 0 {
|
||||||
return nil, errors.Wrapf(define.ErrNotImplemented, "containers with dependencies")
|
return nil, errors.Wrapf(define.ErrNotImplemented, "containers with dependencies")
|
||||||
@ -79,20 +75,29 @@ func (ic *ContainerEngine) GenerateKube(ctx context.Context, nameOrIDs []string,
|
|||||||
return nil, errors.New("cannot generate pods and containers at the same time")
|
return nil, errors.New("cannot generate pods and containers at the same time")
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(pods) == 1 {
|
if len(pods) >= 1 {
|
||||||
podYAML, servicePorts, err = pods[0].GenerateForKube()
|
pos, svcs, err := getKubePods(pods, options.Service)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
kubePods = append(kubePods, pos...)
|
||||||
|
if options.Service {
|
||||||
|
kubeServices = append(kubeServices, svcs...)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
podYAML, err = libpod.GenerateForKube(ctrs)
|
po, err := libpod.GenerateForKube(ctrs)
|
||||||
}
|
if err != nil {
|
||||||
if err != nil {
|
return nil, err
|
||||||
return nil, err
|
}
|
||||||
|
|
||||||
|
kubePods = append(kubePods, po)
|
||||||
|
if options.Service {
|
||||||
|
kubeServices = append(kubeServices, libpod.GenerateKubeServiceFromV1Pod(po, []k8sAPI.ServicePort{}))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if options.Service {
|
content, err := generateKubeOutput(kubePods, kubeServices, options.Service)
|
||||||
serviceYAML = libpod.GenerateKubeServiceFromV1Pod(podYAML, servicePorts)
|
|
||||||
}
|
|
||||||
|
|
||||||
content, err := generateKubeOutput(podYAML, &serviceYAML, options.Service)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -100,23 +105,55 @@ func (ic *ContainerEngine) GenerateKube(ctx context.Context, nameOrIDs []string,
|
|||||||
return &entities.GenerateKubeReport{Reader: bytes.NewReader(content)}, nil
|
return &entities.GenerateKubeReport{Reader: bytes.NewReader(content)}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func generateKubeOutput(podYAML *k8sAPI.Pod, serviceYAML *k8sAPI.Service, hasService bool) ([]byte, error) {
|
func getKubePods(pods []*libpod.Pod, getService bool) ([]*k8sAPI.Pod, []k8sAPI.Service, error) {
|
||||||
var (
|
kubePods := make([]*k8sAPI.Pod, 0)
|
||||||
output []byte
|
kubeServices := make([]k8sAPI.Service, 0)
|
||||||
marshalledPod []byte
|
|
||||||
marshalledService []byte
|
|
||||||
err error
|
|
||||||
)
|
|
||||||
|
|
||||||
marshalledPod, err = yaml.Marshal(podYAML)
|
for _, p := range pods {
|
||||||
if err != nil {
|
po, svc, err := p.GenerateForKube()
|
||||||
return nil, err
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
kubePods = append(kubePods, po)
|
||||||
|
if getService {
|
||||||
|
kubeServices = append(kubeServices, libpod.GenerateKubeServiceFromV1Pod(po, svc))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return kubePods, kubeServices, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func generateKubeOutput(kubePods []*k8sAPI.Pod, kubeServices []k8sAPI.Service, hasService bool) ([]byte, error) {
|
||||||
|
output := make([]byte, 0)
|
||||||
|
marshalledPods := make([]byte, 0)
|
||||||
|
marshalledServices := make([]byte, 0)
|
||||||
|
|
||||||
|
for i, p := range kubePods {
|
||||||
|
if i != 0 {
|
||||||
|
marshalledPods = append(marshalledPods, []byte("---\n")...)
|
||||||
|
}
|
||||||
|
|
||||||
|
b, err := yaml.Marshal(p)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
marshalledPods = append(marshalledPods, b...)
|
||||||
}
|
}
|
||||||
|
|
||||||
if hasService {
|
if hasService {
|
||||||
marshalledService, err = yaml.Marshal(serviceYAML)
|
for i, s := range kubeServices {
|
||||||
if err != nil {
|
if i != 0 {
|
||||||
return nil, err
|
marshalledServices = append(marshalledServices, []byte("---\n")...)
|
||||||
|
}
|
||||||
|
|
||||||
|
b, err := yaml.Marshal(s)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
marshalledServices = append(marshalledServices, b...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -133,11 +170,12 @@ func generateKubeOutput(podYAML *k8sAPI.Pod, serviceYAML *k8sAPI.Service, hasSer
|
|||||||
}
|
}
|
||||||
|
|
||||||
output = append(output, []byte(fmt.Sprintf(header, podmanVersion.Version))...)
|
output = append(output, []byte(fmt.Sprintf(header, podmanVersion.Version))...)
|
||||||
output = append(output, marshalledPod...)
|
// kube generate order is based on helm install order (service, pod...)
|
||||||
if hasService {
|
if hasService {
|
||||||
|
output = append(output, marshalledServices...)
|
||||||
output = append(output, []byte("---\n")...)
|
output = append(output, []byte("---\n")...)
|
||||||
output = append(output, marshalledService...)
|
|
||||||
}
|
}
|
||||||
|
output = append(output, marshalledPods...)
|
||||||
|
|
||||||
return output, nil
|
return output, nil
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package abi
|
package abi
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
@ -20,46 +21,79 @@ import (
|
|||||||
"github.com/ghodss/yaml"
|
"github.com/ghodss/yaml"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
|
yamlv3 "gopkg.in/yaml.v3"
|
||||||
v1apps "k8s.io/api/apps/v1"
|
v1apps "k8s.io/api/apps/v1"
|
||||||
v1 "k8s.io/api/core/v1"
|
v1 "k8s.io/api/core/v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (ic *ContainerEngine) PlayKube(ctx context.Context, path string, options entities.PlayKubeOptions) (*entities.PlayKubeReport, error) {
|
func (ic *ContainerEngine) PlayKube(ctx context.Context, path string, options entities.PlayKubeOptions) (*entities.PlayKubeReport, error) {
|
||||||
var (
|
report := &entities.PlayKubeReport{}
|
||||||
kubeObject v1.ObjectReference
|
validKinds := 0
|
||||||
)
|
|
||||||
|
|
||||||
|
// read yaml document
|
||||||
content, err := ioutil.ReadFile(path)
|
content, err := ioutil.ReadFile(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := yaml.Unmarshal(content, &kubeObject); err != nil {
|
// split yaml document
|
||||||
return nil, errors.Wrapf(err, "unable to read %q as YAML", path)
|
documentList, err := splitMultiDocYAML(content)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: pkg/bindings/play is also parsing the file.
|
// create pod on each document if it is a pod or deployment
|
||||||
// A pkg/kube would be nice to refactor and abstract
|
// any other kube kind will be skipped
|
||||||
// parts of the K8s-related code.
|
for _, document := range documentList {
|
||||||
switch kubeObject.Kind {
|
kind, err := getKubeKind(document)
|
||||||
case "Pod":
|
if err != nil {
|
||||||
var podYAML v1.Pod
|
return nil, errors.Wrapf(err, "unable to read %q as kube YAML", path)
|
||||||
var podTemplateSpec v1.PodTemplateSpec
|
|
||||||
if err := yaml.Unmarshal(content, &podYAML); err != nil {
|
|
||||||
return nil, errors.Wrapf(err, "unable to read YAML %q as Kube Pod", path)
|
|
||||||
}
|
}
|
||||||
podTemplateSpec.ObjectMeta = podYAML.ObjectMeta
|
|
||||||
podTemplateSpec.Spec = podYAML.Spec
|
switch kind {
|
||||||
return ic.playKubePod(ctx, podTemplateSpec.ObjectMeta.Name, &podTemplateSpec, options)
|
case "Pod":
|
||||||
case "Deployment":
|
var podYAML v1.Pod
|
||||||
var deploymentYAML v1apps.Deployment
|
var podTemplateSpec v1.PodTemplateSpec
|
||||||
if err := yaml.Unmarshal(content, &deploymentYAML); err != nil {
|
|
||||||
return nil, errors.Wrapf(err, "unable to read YAML %q as Kube Deployment", path)
|
if err := yaml.Unmarshal(document, &podYAML); err != nil {
|
||||||
|
return nil, errors.Wrapf(err, "unable to read YAML %q as Kube Pod", path)
|
||||||
|
}
|
||||||
|
|
||||||
|
podTemplateSpec.ObjectMeta = podYAML.ObjectMeta
|
||||||
|
podTemplateSpec.Spec = podYAML.Spec
|
||||||
|
|
||||||
|
r, err := ic.playKubePod(ctx, podTemplateSpec.ObjectMeta.Name, &podTemplateSpec, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
report.Pods = append(report.Pods, r.Pods...)
|
||||||
|
validKinds++
|
||||||
|
case "Deployment":
|
||||||
|
var deploymentYAML v1apps.Deployment
|
||||||
|
|
||||||
|
if err := yaml.Unmarshal(document, &deploymentYAML); err != nil {
|
||||||
|
return nil, errors.Wrapf(err, "unable to read YAML %q as Kube Deployment", path)
|
||||||
|
}
|
||||||
|
|
||||||
|
r, err := ic.playKubeDeployment(ctx, &deploymentYAML, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
report.Pods = append(report.Pods, r.Pods...)
|
||||||
|
validKinds++
|
||||||
|
default:
|
||||||
|
logrus.Infof("kube kind %s not supported", kind)
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
return ic.playKubeDeployment(ctx, &deploymentYAML, options)
|
|
||||||
default:
|
|
||||||
return nil, errors.Errorf("invalid YAML kind: %q. [Pod|Deployment] are the only supported Kubernetes Kinds", kubeObject.Kind)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if validKinds == 0 {
|
||||||
|
return nil, fmt.Errorf("YAML document does not contain any supported kube kind")
|
||||||
|
}
|
||||||
|
|
||||||
|
return report, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ic *ContainerEngine) playKubeDeployment(ctx context.Context, deploymentYAML *v1apps.Deployment, options entities.PlayKubeOptions) (*entities.PlayKubeReport, error) {
|
func (ic *ContainerEngine) playKubeDeployment(ctx context.Context, deploymentYAML *v1apps.Deployment, options entities.PlayKubeOptions) (*entities.PlayKubeReport, error) {
|
||||||
@ -290,3 +324,45 @@ func readConfigMapFromFile(r io.Reader) (v1.ConfigMap, error) {
|
|||||||
|
|
||||||
return cm, nil
|
return cm, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// splitMultiDocYAML reads mutiple documents in a YAML file and
|
||||||
|
// returns them as a list.
|
||||||
|
func splitMultiDocYAML(yamlContent []byte) ([][]byte, error) {
|
||||||
|
var documentList [][]byte
|
||||||
|
|
||||||
|
d := yamlv3.NewDecoder(bytes.NewReader(yamlContent))
|
||||||
|
for {
|
||||||
|
var o interface{}
|
||||||
|
// read individual document
|
||||||
|
err := d.Decode(&o)
|
||||||
|
if err == io.EOF {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrapf(err, "multi doc yaml could not be split")
|
||||||
|
}
|
||||||
|
|
||||||
|
if o != nil {
|
||||||
|
// back to bytes
|
||||||
|
document, err := yamlv3.Marshal(o)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrapf(err, "individual doc yaml could not be marshalled")
|
||||||
|
}
|
||||||
|
|
||||||
|
documentList = append(documentList, document)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return documentList, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// getKubeKind unmarshals a kube YAML document and returns its kind.
|
||||||
|
func getKubeKind(obj []byte) (string, error) {
|
||||||
|
var kubeObject v1.ObjectReference
|
||||||
|
|
||||||
|
if err := yaml.Unmarshal(obj, &kubeObject); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
return kubeObject.Kind, nil
|
||||||
|
}
|
||||||
|
@ -89,3 +89,100 @@ data:
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestGetKubeKind(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
kubeYAML string
|
||||||
|
expectError bool
|
||||||
|
expectedErrorMsg string
|
||||||
|
expected string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
"ValidKubeYAML",
|
||||||
|
`
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Pod
|
||||||
|
`,
|
||||||
|
false,
|
||||||
|
"",
|
||||||
|
"Pod",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"InvalidKubeYAML",
|
||||||
|
"InvalidKubeYAML",
|
||||||
|
true,
|
||||||
|
"cannot unmarshal",
|
||||||
|
"",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range tests {
|
||||||
|
test := test
|
||||||
|
t.Run(test.name, func(t *testing.T) {
|
||||||
|
kind, err := getKubeKind([]byte(test.kubeYAML))
|
||||||
|
if test.expectError {
|
||||||
|
assert.Error(t, err)
|
||||||
|
assert.Contains(t, err.Error(), test.expectedErrorMsg)
|
||||||
|
} else {
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, test.expected, kind)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSplitMultiDocYAML(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
kubeYAML string
|
||||||
|
expectError bool
|
||||||
|
expectedErrorMsg string
|
||||||
|
expected int
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
"ValidNumberOfDocs",
|
||||||
|
`
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Pod
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Pod
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Pod
|
||||||
|
`,
|
||||||
|
false,
|
||||||
|
"",
|
||||||
|
3,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"InvalidMultiDocYAML",
|
||||||
|
`
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Pod
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Pod
|
||||||
|
-
|
||||||
|
`,
|
||||||
|
true,
|
||||||
|
"multi doc yaml could not be split",
|
||||||
|
0,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range tests {
|
||||||
|
test := test
|
||||||
|
t.Run(test.name, func(t *testing.T) {
|
||||||
|
docs, err := splitMultiDocYAML([]byte(test.kubeYAML))
|
||||||
|
if test.expectError {
|
||||||
|
assert.Error(t, err)
|
||||||
|
assert.Contains(t, err.Error(), test.expectedErrorMsg)
|
||||||
|
} else {
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, test.expected, len(docs))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -155,6 +155,23 @@ var _ = Describe("Podman generate kube", func() {
|
|||||||
Expect(numContainers).To(Equal(1))
|
Expect(numContainers).To(Equal(1))
|
||||||
})
|
})
|
||||||
|
|
||||||
|
It("podman generate kube multiple pods", func() {
|
||||||
|
pod1 := podmanTest.Podman([]string{"run", "-dt", "--pod", "new:pod1", ALPINE, "top"})
|
||||||
|
pod1.WaitWithDefaultTimeout()
|
||||||
|
Expect(pod1.ExitCode()).To(Equal(0))
|
||||||
|
|
||||||
|
pod2 := podmanTest.Podman([]string{"run", "-dt", "--pod", "new:pod2", ALPINE, "top"})
|
||||||
|
pod2.WaitWithDefaultTimeout()
|
||||||
|
Expect(pod2.ExitCode()).To(Equal(0))
|
||||||
|
|
||||||
|
kube := podmanTest.Podman([]string{"generate", "kube", "pod1", "pod2"})
|
||||||
|
kube.WaitWithDefaultTimeout()
|
||||||
|
Expect(kube.ExitCode()).To(Equal(0))
|
||||||
|
|
||||||
|
Expect(string(kube.Out.Contents())).To(ContainSubstring(`name: pod1`))
|
||||||
|
Expect(string(kube.Out.Contents())).To(ContainSubstring(`name: pod2`))
|
||||||
|
})
|
||||||
|
|
||||||
It("podman generate kube on pod with host network", func() {
|
It("podman generate kube on pod with host network", func() {
|
||||||
podSession := podmanTest.Podman([]string{"pod", "create", "--name", "testHostNetwork", "--network", "host"})
|
podSession := podmanTest.Podman([]string{"pod", "create", "--name", "testHostNetwork", "--network", "host"})
|
||||||
podSession.WaitWithDefaultTimeout()
|
podSession.WaitWithDefaultTimeout()
|
||||||
@ -537,21 +554,6 @@ var _ = Describe("Podman generate kube", func() {
|
|||||||
Expect(inspect.OutputToString()).To(ContainSubstring(`"pid"`))
|
Expect(inspect.OutputToString()).To(ContainSubstring(`"pid"`))
|
||||||
})
|
})
|
||||||
|
|
||||||
It("podman generate kube multiple pods should fail", func() {
|
|
||||||
SkipIfRootlessCgroupsV1("Not supported for rootless + CGroupsV1")
|
|
||||||
pod1 := podmanTest.Podman([]string{"run", "-dt", "--pod", "new:pod1", ALPINE, "top"})
|
|
||||||
pod1.WaitWithDefaultTimeout()
|
|
||||||
Expect(pod1.ExitCode()).To(Equal(0))
|
|
||||||
|
|
||||||
pod2 := podmanTest.Podman([]string{"run", "-dt", "--pod", "new:pod2", ALPINE, "top"})
|
|
||||||
pod2.WaitWithDefaultTimeout()
|
|
||||||
Expect(pod2.ExitCode()).To(Equal(0))
|
|
||||||
|
|
||||||
kube := podmanTest.Podman([]string{"generate", "kube", "pod1", "pod2"})
|
|
||||||
kube.WaitWithDefaultTimeout()
|
|
||||||
Expect(kube.ExitCode()).ToNot(Equal(0))
|
|
||||||
})
|
|
||||||
|
|
||||||
It("podman generate kube with pods and containers should fail", func() {
|
It("podman generate kube with pods and containers should fail", func() {
|
||||||
pod1 := podmanTest.Podman([]string{"run", "-dt", "--pod", "new:pod1", ALPINE, "top"})
|
pod1 := podmanTest.Podman([]string{"run", "-dt", "--pod", "new:pod1", ALPINE, "top"})
|
||||||
pod1.WaitWithDefaultTimeout()
|
pod1.WaitWithDefaultTimeout()
|
||||||
@ -594,7 +596,7 @@ var _ = Describe("Podman generate kube", func() {
|
|||||||
Expect(kube.ExitCode()).To(Equal(0))
|
Expect(kube.ExitCode()).To(Equal(0))
|
||||||
})
|
})
|
||||||
|
|
||||||
It("podman generate kube with containers in a pod should fail", func() {
|
It("podman generate kube with containers in pods should fail", func() {
|
||||||
pod1 := podmanTest.Podman([]string{"run", "-dt", "--pod", "new:pod1", "--name", "top1", ALPINE, "top"})
|
pod1 := podmanTest.Podman([]string{"run", "-dt", "--pod", "new:pod1", "--name", "top1", ALPINE, "top"})
|
||||||
pod1.WaitWithDefaultTimeout()
|
pod1.WaitWithDefaultTimeout()
|
||||||
Expect(pod1.ExitCode()).To(Equal(0))
|
Expect(pod1.ExitCode()).To(Equal(0))
|
||||||
@ -603,7 +605,7 @@ var _ = Describe("Podman generate kube", func() {
|
|||||||
pod2.WaitWithDefaultTimeout()
|
pod2.WaitWithDefaultTimeout()
|
||||||
Expect(pod2.ExitCode()).To(Equal(0))
|
Expect(pod2.ExitCode()).To(Equal(0))
|
||||||
|
|
||||||
kube := podmanTest.Podman([]string{"generate", "kube", "pod1", "pod2"})
|
kube := podmanTest.Podman([]string{"generate", "kube", "top1", "top2"})
|
||||||
kube.WaitWithDefaultTimeout()
|
kube.WaitWithDefaultTimeout()
|
||||||
Expect(kube.ExitCode()).ToNot(Equal(0))
|
Expect(kube.ExitCode()).ToNot(Equal(0))
|
||||||
})
|
})
|
||||||
|
@ -357,7 +357,8 @@ func writeYaml(content string, fileName string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func generateKubeYaml(kind string, object interface{}, pathname string) error {
|
// getKubeYaml returns a kubernetes YAML document.
|
||||||
|
func getKubeYaml(kind string, object interface{}) (string, error) {
|
||||||
var yamlTemplate string
|
var yamlTemplate string
|
||||||
templateBytes := &bytes.Buffer{}
|
templateBytes := &bytes.Buffer{}
|
||||||
|
|
||||||
@ -369,19 +370,41 @@ func generateKubeYaml(kind string, object interface{}, pathname string) error {
|
|||||||
case "deployment":
|
case "deployment":
|
||||||
yamlTemplate = deploymentYamlTemplate
|
yamlTemplate = deploymentYamlTemplate
|
||||||
default:
|
default:
|
||||||
return fmt.Errorf("unsupported kubernetes kind")
|
return "", fmt.Errorf("unsupported kubernetes kind")
|
||||||
}
|
}
|
||||||
|
|
||||||
t, err := template.New(kind).Parse(yamlTemplate)
|
t, err := template.New(kind).Parse(yamlTemplate)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := t.Execute(templateBytes, object); err != nil {
|
if err := t.Execute(templateBytes, object); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
return templateBytes.String(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// generateKubeYaml writes a kubernetes YAML document.
|
||||||
|
func generateKubeYaml(kind string, object interface{}, pathname string) error {
|
||||||
|
k, err := getKubeYaml(kind, object)
|
||||||
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return writeYaml(templateBytes.String(), pathname)
|
return writeYaml(k, pathname)
|
||||||
|
}
|
||||||
|
|
||||||
|
// generateMultiDocKubeYaml writes multiple kube objects in one Yaml document.
|
||||||
|
func generateMultiDocKubeYaml(kubeObjects []string, pathname string) error {
|
||||||
|
var multiKube string
|
||||||
|
|
||||||
|
for _, k := range kubeObjects {
|
||||||
|
multiKube += "---\n"
|
||||||
|
multiKube += k
|
||||||
|
}
|
||||||
|
|
||||||
|
return writeYaml(multiKube, pathname)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ConfigMap describes the options a kube yaml can be configured at configmap level
|
// ConfigMap describes the options a kube yaml can be configured at configmap level
|
||||||
@ -1698,4 +1721,102 @@ MemoryReservation: {{ .HostConfig.MemoryReservation }}`})
|
|||||||
Expect(inspect.ExitCode()).To(Equal(0))
|
Expect(inspect.ExitCode()).To(Equal(0))
|
||||||
Expect(inspect.OutputToString()).To(Equal("true"))
|
Expect(inspect.OutputToString()).To(Equal("true"))
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// Multi doc related tests
|
||||||
|
It("podman play kube multi doc yaml", func() {
|
||||||
|
yamlDocs := []string{}
|
||||||
|
podNames := []string{}
|
||||||
|
|
||||||
|
serviceTemplate := `apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: %s
|
||||||
|
spec:
|
||||||
|
ports:
|
||||||
|
- port: 80
|
||||||
|
protocol: TCP
|
||||||
|
targetPort: 9376
|
||||||
|
selector:
|
||||||
|
app: %s
|
||||||
|
`
|
||||||
|
// generate servies, pods and deployments
|
||||||
|
for i := 0; i < 2; i++ {
|
||||||
|
podName := fmt.Sprintf("testPod%d", i)
|
||||||
|
deploymentName := fmt.Sprintf("testDeploy%d", i)
|
||||||
|
deploymentPodName := fmt.Sprintf("%s-pod-0", deploymentName)
|
||||||
|
|
||||||
|
podNames = append(podNames, podName)
|
||||||
|
podNames = append(podNames, deploymentPodName)
|
||||||
|
|
||||||
|
pod := getPod(withPodName(podName))
|
||||||
|
podDeployment := getPod(withPodName(deploymentName))
|
||||||
|
deployment := getDeployment(withPod(podDeployment))
|
||||||
|
deployment.Name = deploymentName
|
||||||
|
|
||||||
|
// add services
|
||||||
|
yamlDocs = append([]string{
|
||||||
|
fmt.Sprintf(serviceTemplate, podName, podName),
|
||||||
|
fmt.Sprintf(serviceTemplate, deploymentPodName, deploymentPodName)}, yamlDocs...)
|
||||||
|
|
||||||
|
// add pods
|
||||||
|
k, err := getKubeYaml("pod", pod)
|
||||||
|
Expect(err).To(BeNil())
|
||||||
|
yamlDocs = append(yamlDocs, k)
|
||||||
|
|
||||||
|
// add deployments
|
||||||
|
k, err = getKubeYaml("deployment", deployment)
|
||||||
|
Expect(err).To(BeNil())
|
||||||
|
yamlDocs = append(yamlDocs, k)
|
||||||
|
}
|
||||||
|
|
||||||
|
// generate multi doc yaml
|
||||||
|
err = generateMultiDocKubeYaml(yamlDocs, kubeYaml)
|
||||||
|
Expect(err).To(BeNil())
|
||||||
|
|
||||||
|
kube := podmanTest.Podman([]string{"play", "kube", kubeYaml})
|
||||||
|
kube.WaitWithDefaultTimeout()
|
||||||
|
Expect(kube.ExitCode()).To(Equal(0))
|
||||||
|
|
||||||
|
for _, n := range podNames {
|
||||||
|
inspect := podmanTest.Podman([]string{"inspect", n, "--format", "'{{ .State }}'"})
|
||||||
|
inspect.WaitWithDefaultTimeout()
|
||||||
|
Expect(inspect.ExitCode()).To(Equal(0))
|
||||||
|
Expect(inspect.OutputToString()).To(ContainSubstring(`Running`))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
It("podman play kube invalid multi doc yaml", func() {
|
||||||
|
yamlDocs := []string{}
|
||||||
|
|
||||||
|
serviceTemplate := `apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: %s
|
||||||
|
spec:
|
||||||
|
ports:
|
||||||
|
- port: 80
|
||||||
|
protocol: TCP
|
||||||
|
targetPort: 9376
|
||||||
|
selector:
|
||||||
|
app: %s
|
||||||
|
---
|
||||||
|
invalid kube kind
|
||||||
|
`
|
||||||
|
// add invalid multi doc yaml
|
||||||
|
yamlDocs = append(yamlDocs, fmt.Sprintf(serviceTemplate, "foo", "foo"))
|
||||||
|
|
||||||
|
// add pod
|
||||||
|
pod := getPod()
|
||||||
|
k, err := getKubeYaml("pod", pod)
|
||||||
|
Expect(err).To(BeNil())
|
||||||
|
yamlDocs = append(yamlDocs, k)
|
||||||
|
|
||||||
|
// generate multi doc yaml
|
||||||
|
err = generateMultiDocKubeYaml(yamlDocs, kubeYaml)
|
||||||
|
Expect(err).To(BeNil())
|
||||||
|
|
||||||
|
kube := podmanTest.Podman([]string{"play", "kube", kubeYaml})
|
||||||
|
kube.WaitWithDefaultTimeout()
|
||||||
|
Expect(kube.ExitCode()).To(Not(Equal(0)))
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
Reference in New Issue
Block a user