forked from LaconicNetwork/kompose
Add v3 support
This does a major refactor on the compose.go functions as well as brings in a new era of v3 support to Kompose. Similar to how we utilize libcompose, we utilize docker/cli's "stack deploy" code which has a built-in v3 parser. We convert the parsed structure to our own and then convert it to Kubernetes/OpenShift artifacts.
This commit is contained in:
parent
683ae91823
commit
2b58307191
@ -18,18 +18,13 @@ package compose
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"io/ioutil"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
yaml "gopkg.in/yaml.v2"
|
||||
|
||||
log "github.com/Sirupsen/logrus"
|
||||
"github.com/docker/libcompose/config"
|
||||
"github.com/docker/libcompose/lookup"
|
||||
"github.com/docker/libcompose/project"
|
||||
"github.com/fatih/structs"
|
||||
"github.com/kubernetes-incubator/kompose/pkg/kobject"
|
||||
@ -134,277 +129,65 @@ func checkUnsupportedKey(composeProject *project.Project) []string {
|
||||
return keysFound
|
||||
}
|
||||
|
||||
// load environment variables from compose file
|
||||
func loadEnvVars(envars []string) []kobject.EnvVar {
|
||||
envs := []kobject.EnvVar{}
|
||||
for _, e := range envars {
|
||||
character := ""
|
||||
equalPos := strings.Index(e, "=")
|
||||
colonPos := strings.Index(e, ":")
|
||||
switch {
|
||||
case equalPos == -1 && colonPos == -1:
|
||||
character = ""
|
||||
case equalPos == -1 && colonPos != -1:
|
||||
character = ":"
|
||||
case equalPos != -1 && colonPos == -1:
|
||||
character = "="
|
||||
case equalPos != -1 && colonPos != -1:
|
||||
if equalPos > colonPos {
|
||||
character = ":"
|
||||
} else {
|
||||
character = "="
|
||||
}
|
||||
}
|
||||
|
||||
if character == "" {
|
||||
envs = append(envs, kobject.EnvVar{
|
||||
Name: e,
|
||||
Value: os.Getenv(e),
|
||||
})
|
||||
} else {
|
||||
values := strings.SplitN(e, character, 2)
|
||||
// try to get value from os env
|
||||
if values[1] == "" {
|
||||
values[1] = os.Getenv(values[0])
|
||||
}
|
||||
envs = append(envs, kobject.EnvVar{
|
||||
Name: values[0],
|
||||
Value: values[1],
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return envs
|
||||
}
|
||||
|
||||
// Load ports from compose file
|
||||
func loadPorts(composePorts []string) ([]kobject.Ports, error) {
|
||||
ports := []kobject.Ports{}
|
||||
character := ":"
|
||||
|
||||
// For each port listed
|
||||
for _, port := range composePorts {
|
||||
|
||||
// Get the TCP / UDP protocol. Checks to see if it splits in 2 with '/' character.
|
||||
// ex. 15000:15000/tcp
|
||||
// else, set a default protocol of using TCP
|
||||
proto := api.ProtocolTCP
|
||||
protocolCheck := strings.Split(port, "/")
|
||||
if len(protocolCheck) == 2 {
|
||||
if strings.EqualFold("tcp", protocolCheck[1]) {
|
||||
proto = api.ProtocolTCP
|
||||
} else if strings.EqualFold("udp", protocolCheck[1]) {
|
||||
proto = api.ProtocolUDP
|
||||
} else {
|
||||
return nil, fmt.Errorf("invalid protocol %q", protocolCheck[1])
|
||||
}
|
||||
}
|
||||
|
||||
// Split up the ports / IP without the "/tcp" or "/udp" appended to it
|
||||
justPorts := strings.Split(protocolCheck[0], character)
|
||||
|
||||
if len(justPorts) == 3 {
|
||||
// ex. 127.0.0.1:80:80
|
||||
|
||||
// Get the IP address
|
||||
hostIP := justPorts[0]
|
||||
ip := net.ParseIP(hostIP)
|
||||
if ip.To4() == nil && ip.To16() == nil {
|
||||
return nil, fmt.Errorf("%q contains an invalid IPv4 or IPv6 IP address", port)
|
||||
}
|
||||
|
||||
// Get the host port
|
||||
hostPortInt, err := strconv.Atoi(justPorts[1])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid host port %q valid example: 127.0.0.1:80:80", port)
|
||||
}
|
||||
|
||||
// Get the container port
|
||||
containerPortInt, err := strconv.Atoi(justPorts[2])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid container port %q valid example: 127.0.0.1:80:80", port)
|
||||
}
|
||||
|
||||
// Convert to a kobject struct with ports as well as IP
|
||||
ports = append(ports, kobject.Ports{
|
||||
HostPort: int32(hostPortInt),
|
||||
ContainerPort: int32(containerPortInt),
|
||||
HostIP: hostIP,
|
||||
Protocol: proto,
|
||||
})
|
||||
|
||||
} else if len(justPorts) == 2 {
|
||||
// ex. 80:80
|
||||
|
||||
// Get the host port
|
||||
hostPortInt, err := strconv.Atoi(justPorts[0])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid host port %q valid example: 80:80", port)
|
||||
}
|
||||
|
||||
// Get the container port
|
||||
containerPortInt, err := strconv.Atoi(justPorts[1])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid container port %q valid example: 80:80", port)
|
||||
}
|
||||
|
||||
// Convert to a kobject struct and add to the list of ports
|
||||
ports = append(ports, kobject.Ports{
|
||||
HostPort: int32(hostPortInt),
|
||||
ContainerPort: int32(containerPortInt),
|
||||
Protocol: proto,
|
||||
})
|
||||
|
||||
} else {
|
||||
// ex. 80
|
||||
|
||||
containerPortInt, err := strconv.Atoi(justPorts[0])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid container port %q valid example: 80", port)
|
||||
}
|
||||
ports = append(ports, kobject.Ports{
|
||||
ContainerPort: int32(containerPortInt),
|
||||
Protocol: proto,
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
return ports, nil
|
||||
}
|
||||
|
||||
// LoadFile loads compose file into KomposeObject
|
||||
// LoadFile loads a compose file into KomposeObject
|
||||
func (c *Compose) LoadFile(files []string) (kobject.KomposeObject, error) {
|
||||
komposeObject := kobject.KomposeObject{
|
||||
ServiceConfigs: make(map[string]kobject.ServiceConfig),
|
||||
LoadedFrom: "compose",
|
||||
}
|
||||
context := &project.Context{}
|
||||
context.ComposeFiles = files
|
||||
|
||||
if context.ResourceLookup == nil {
|
||||
context.ResourceLookup = &lookup.FileResourceLookup{}
|
||||
}
|
||||
// Load the json / yaml file in order to get the version value
|
||||
var version string
|
||||
|
||||
if context.EnvironmentLookup == nil {
|
||||
cwd, err := os.Getwd()
|
||||
for _, file := range files {
|
||||
composeVersion, err := getVersionFromFile(file)
|
||||
if err != nil {
|
||||
return kobject.KomposeObject{}, nil
|
||||
return kobject.KomposeObject{}, errors.Wrap(err, "Unable to load yaml/json file for version parsing")
|
||||
}
|
||||
context.EnvironmentLookup = &lookup.ComposableEnvLookup{
|
||||
Lookups: []config.EnvironmentLookup{
|
||||
&lookup.EnvfileLookup{
|
||||
Path: filepath.Join(cwd, ".env"),
|
||||
},
|
||||
&lookup.OsEnvLookup{},
|
||||
},
|
||||
|
||||
// Check that the previous file loaded matches.
|
||||
if len(files) > 0 && version != "" && version != composeVersion {
|
||||
return kobject.KomposeObject{}, errors.New("All Docker Compose files must be of the same version")
|
||||
}
|
||||
version = composeVersion
|
||||
}
|
||||
|
||||
// load compose file into composeObject
|
||||
composeObject := project.NewProject(context, nil, nil)
|
||||
err := composeObject.Parse()
|
||||
if err != nil {
|
||||
return kobject.KomposeObject{}, errors.Wrap(err, "composeObject.Parse() failed, Failed to load compose file")
|
||||
}
|
||||
log.Debugf("Docker Compose version: %s", version)
|
||||
|
||||
noSupKeys := checkUnsupportedKey(composeObject)
|
||||
for _, keyName := range noSupKeys {
|
||||
log.Warningf("Unsupported %s key - ignoring", keyName)
|
||||
}
|
||||
|
||||
for name, composeServiceConfig := range composeObject.ServiceConfigs.All() {
|
||||
serviceConfig := kobject.ServiceConfig{}
|
||||
serviceConfig.Image = composeServiceConfig.Image
|
||||
serviceConfig.Build = composeServiceConfig.Build.Context
|
||||
newName := normalizeServiceNames(composeServiceConfig.ContainerName)
|
||||
serviceConfig.ContainerName = newName
|
||||
if newName != composeServiceConfig.ContainerName {
|
||||
log.Infof("Container name in service %q has been changed from %q to %q", name, composeServiceConfig.ContainerName, newName)
|
||||
}
|
||||
serviceConfig.Command = composeServiceConfig.Entrypoint
|
||||
serviceConfig.Args = composeServiceConfig.Command
|
||||
serviceConfig.Dockerfile = composeServiceConfig.Build.Dockerfile
|
||||
serviceConfig.BuildArgs = composeServiceConfig.Build.Args
|
||||
|
||||
envs := loadEnvVars(composeServiceConfig.Environment)
|
||||
serviceConfig.Environment = envs
|
||||
|
||||
//Validate dockerfile path
|
||||
if filepath.IsAbs(serviceConfig.Dockerfile) {
|
||||
log.Fatalf("%q defined in service %q is an absolute path, it must be a relative path.", serviceConfig.Dockerfile, name)
|
||||
}
|
||||
|
||||
// load ports
|
||||
ports, err := loadPorts(composeServiceConfig.Ports)
|
||||
// Convert based on version
|
||||
switch version {
|
||||
// Use libcompose for 1 or 2
|
||||
// If blank, it's assumed it's 1 or 2
|
||||
case "", "1", "1.0", "2", "2.0":
|
||||
komposeObject, err := parseV1V2(files)
|
||||
if err != nil {
|
||||
return kobject.KomposeObject{}, errors.Wrap(err, "loadPorts failed. "+name+" failed to load ports from compose file")
|
||||
return kobject.KomposeObject{}, err
|
||||
}
|
||||
serviceConfig.Port = ports
|
||||
|
||||
serviceConfig.WorkingDir = composeServiceConfig.WorkingDir
|
||||
|
||||
if composeServiceConfig.Volumes != nil {
|
||||
for _, volume := range composeServiceConfig.Volumes.Volumes {
|
||||
v := normalizeServiceNames(volume.String())
|
||||
serviceConfig.Volumes = append(serviceConfig.Volumes, v)
|
||||
}
|
||||
return komposeObject, nil
|
||||
// Use docker/cli for 3
|
||||
case "3", "3.0":
|
||||
komposeObject, err := parseV3(files)
|
||||
if err != nil {
|
||||
return kobject.KomposeObject{}, err
|
||||
}
|
||||
|
||||
// canonical "Custom Labels" handler
|
||||
// Labels used to influence conversion of kompose will be handled
|
||||
// from here for docker-compose. Each loader will have such handler.
|
||||
for key, value := range composeServiceConfig.Labels {
|
||||
switch key {
|
||||
case "kompose.service.type":
|
||||
serviceType, err := handleServiceType(value)
|
||||
if err != nil {
|
||||
return kobject.KomposeObject{}, errors.Wrap(err, "handleServiceType failed")
|
||||
}
|
||||
|
||||
serviceConfig.ServiceType = serviceType
|
||||
case "kompose.service.expose":
|
||||
serviceConfig.ExposeService = strings.ToLower(value)
|
||||
}
|
||||
}
|
||||
|
||||
// convert compose labels to annotations
|
||||
serviceConfig.Annotations = map[string]string(composeServiceConfig.Labels)
|
||||
serviceConfig.CPUQuota = int64(composeServiceConfig.CPUQuota)
|
||||
serviceConfig.CapAdd = composeServiceConfig.CapAdd
|
||||
serviceConfig.CapDrop = composeServiceConfig.CapDrop
|
||||
serviceConfig.Pid = composeServiceConfig.Pid
|
||||
serviceConfig.Expose = composeServiceConfig.Expose
|
||||
serviceConfig.Privileged = composeServiceConfig.Privileged
|
||||
serviceConfig.Restart = composeServiceConfig.Restart
|
||||
serviceConfig.User = composeServiceConfig.User
|
||||
serviceConfig.VolumesFrom = composeServiceConfig.VolumesFrom
|
||||
serviceConfig.Stdin = composeServiceConfig.StdinOpen
|
||||
serviceConfig.Tty = composeServiceConfig.Tty
|
||||
serviceConfig.MemLimit = composeServiceConfig.MemLimit
|
||||
serviceConfig.TmpFs = composeServiceConfig.Tmpfs
|
||||
serviceConfig.StopGracePeriod = composeServiceConfig.StopGracePeriod
|
||||
komposeObject.ServiceConfigs[normalizeServiceNames(name)] = serviceConfig
|
||||
if normalizeServiceNames(name) != name {
|
||||
log.Infof("Service name in docker-compose has been changed from %q to %q", name, normalizeServiceNames(name))
|
||||
}
|
||||
}
|
||||
|
||||
return komposeObject, nil
|
||||
}
|
||||
|
||||
func handleServiceType(ServiceType string) (string, error) {
|
||||
switch strings.ToLower(ServiceType) {
|
||||
case "", "clusterip":
|
||||
return string(api.ServiceTypeClusterIP), nil
|
||||
case "nodeport":
|
||||
return string(api.ServiceTypeNodePort), nil
|
||||
case "loadbalancer":
|
||||
return string(api.ServiceTypeLoadBalancer), nil
|
||||
return komposeObject, nil
|
||||
default:
|
||||
return "", errors.New("Unknown value " + ServiceType + " , supported values are 'NodePort, ClusterIP or LoadBalancer'")
|
||||
return kobject.KomposeObject{}, fmt.Errorf("Version %s of Docker Compose is not supported. Please use version 1, 2 or 3", version)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func normalizeServiceNames(svcName string) string {
|
||||
return strings.Replace(svcName, "_", "-", -1)
|
||||
func getVersionFromFile(file string) (string, error) {
|
||||
type ComposeVersion struct {
|
||||
Version string `json:"version"` // This affects YAML as well
|
||||
}
|
||||
var version ComposeVersion
|
||||
|
||||
loadedFile, err := ioutil.ReadFile(file)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
err = yaml.Unmarshal(loadedFile, &version)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return version.Version, nil
|
||||
}
|
||||
|
||||
@ -25,12 +25,49 @@ import (
|
||||
"github.com/kubernetes-incubator/kompose/pkg/kobject"
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
|
||||
"github.com/docker/cli/cli/compose/types"
|
||||
"github.com/docker/libcompose/config"
|
||||
"github.com/docker/libcompose/project"
|
||||
"github.com/docker/libcompose/yaml"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
func TestLoadV3Volumes(t *testing.T) {
|
||||
vol := types.ServiceVolumeConfig{
|
||||
Type: "volume",
|
||||
Source: "/tmp/foobar",
|
||||
Target: "/tmp/foobar",
|
||||
ReadOnly: true,
|
||||
}
|
||||
volumes := []types.ServiceVolumeConfig{vol}
|
||||
output := loadV3Volumes(volumes)
|
||||
expected := "/tmp/foobar:/tmp/foobar:ro"
|
||||
|
||||
if output[0] != expected {
|
||||
t.Errorf("Expected %s, got %s", expected, output[0])
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestLoadV3Ports(t *testing.T) {
|
||||
port := types.ServicePortConfig{
|
||||
Target: 80,
|
||||
Published: 80,
|
||||
Protocol: "TCP",
|
||||
}
|
||||
ports := []types.ServicePortConfig{port}
|
||||
output := loadV3Ports(ports)
|
||||
expected := kobject.Ports{
|
||||
HostPort: 80,
|
||||
ContainerPort: 80,
|
||||
Protocol: api.Protocol("TCP"),
|
||||
}
|
||||
|
||||
if output[0] != expected {
|
||||
t.Errorf("Expected %s, got %s", expected, output[0])
|
||||
}
|
||||
}
|
||||
|
||||
// Test if service types are parsed properly on user input
|
||||
// give a service type and expect correct input
|
||||
func TestHandleServiceType(t *testing.T) {
|
||||
|
||||
102
pkg/loader/compose/utils.go
Normal file
102
pkg/loader/compose/utils.go
Normal file
@ -0,0 +1,102 @@
|
||||
/*
|
||||
Copyright 2016 The Kubernetes Authors All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package compose
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/kubernetes-incubator/kompose/pkg/kobject"
|
||||
"github.com/pkg/errors"
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
)
|
||||
|
||||
// load environment variables from compose file
|
||||
func loadEnvVars(envars []string) []kobject.EnvVar {
|
||||
envs := []kobject.EnvVar{}
|
||||
for _, e := range envars {
|
||||
character := ""
|
||||
equalPos := strings.Index(e, "=")
|
||||
colonPos := strings.Index(e, ":")
|
||||
switch {
|
||||
case equalPos == -1 && colonPos == -1:
|
||||
character = ""
|
||||
case equalPos == -1 && colonPos != -1:
|
||||
character = ":"
|
||||
case equalPos != -1 && colonPos == -1:
|
||||
character = "="
|
||||
case equalPos != -1 && colonPos != -1:
|
||||
if equalPos > colonPos {
|
||||
character = ":"
|
||||
} else {
|
||||
character = "="
|
||||
}
|
||||
}
|
||||
|
||||
if character == "" {
|
||||
envs = append(envs, kobject.EnvVar{
|
||||
Name: e,
|
||||
Value: os.Getenv(e),
|
||||
})
|
||||
} else {
|
||||
values := strings.SplitN(e, character, 2)
|
||||
// try to get value from os env
|
||||
if values[1] == "" {
|
||||
values[1] = os.Getenv(values[0])
|
||||
}
|
||||
envs = append(envs, kobject.EnvVar{
|
||||
Name: values[0],
|
||||
Value: values[1],
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return envs
|
||||
}
|
||||
|
||||
// getComposeFileDir returns compose file directory
|
||||
// Assume all the docker-compose files are in the same directory
|
||||
// TODO: fix (check if file exists)
|
||||
func getComposeFileDir(inputFiles []string) (string, error) {
|
||||
inputFile := inputFiles[0]
|
||||
if strings.Index(inputFile, "/") != 0 {
|
||||
workDir, err := os.Getwd()
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "Unable to retrieve compose file directory")
|
||||
}
|
||||
inputFile = filepath.Join(workDir, inputFile)
|
||||
}
|
||||
return filepath.Dir(inputFile), nil
|
||||
}
|
||||
|
||||
func handleServiceType(ServiceType string) (string, error) {
|
||||
switch strings.ToLower(ServiceType) {
|
||||
case "", "clusterip":
|
||||
return string(api.ServiceTypeClusterIP), nil
|
||||
case "nodeport":
|
||||
return string(api.ServiceTypeNodePort), nil
|
||||
case "loadbalancer":
|
||||
return string(api.ServiceTypeLoadBalancer), nil
|
||||
default:
|
||||
return "", errors.New("Unknown value " + ServiceType + " , supported values are 'NodePort, ClusterIP or LoadBalancer'")
|
||||
}
|
||||
}
|
||||
|
||||
func normalizeServiceNames(svcName string) string {
|
||||
return strings.Replace(svcName, "_", "-", -1)
|
||||
}
|
||||
268
pkg/loader/compose/v1v2.go
Normal file
268
pkg/loader/compose/v1v2.go
Normal file
@ -0,0 +1,268 @@
|
||||
/*
|
||||
Copyright 2016 The Kubernetes Authors All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package compose
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
|
||||
log "github.com/Sirupsen/logrus"
|
||||
"github.com/docker/libcompose/config"
|
||||
"github.com/docker/libcompose/lookup"
|
||||
"github.com/docker/libcompose/project"
|
||||
"github.com/kubernetes-incubator/kompose/pkg/kobject"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// Parse Docker Compose with libcompose (only supports v1 and v2). Eventually we will
|
||||
// switch to using only libcompose once v3 is supported.
|
||||
func parseV1V2(files []string) (kobject.KomposeObject, error) {
|
||||
|
||||
// Gather the appropriate context for parsing
|
||||
context := &project.Context{}
|
||||
context.ComposeFiles = files
|
||||
|
||||
if context.ResourceLookup == nil {
|
||||
context.ResourceLookup = &lookup.FileResourceLookup{}
|
||||
}
|
||||
|
||||
if context.EnvironmentLookup == nil {
|
||||
cwd, err := os.Getwd()
|
||||
if err != nil {
|
||||
return kobject.KomposeObject{}, nil
|
||||
}
|
||||
context.EnvironmentLookup = &lookup.ComposableEnvLookup{
|
||||
Lookups: []config.EnvironmentLookup{
|
||||
&lookup.EnvfileLookup{
|
||||
Path: filepath.Join(cwd, ".env"),
|
||||
},
|
||||
&lookup.OsEnvLookup{},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// Load the context and let's start parsing
|
||||
composeObject := project.NewProject(context, nil, nil)
|
||||
err := composeObject.Parse()
|
||||
if err != nil {
|
||||
return kobject.KomposeObject{}, errors.Wrap(err, "composeObject.Parse() failed, Failed to load compose file")
|
||||
}
|
||||
|
||||
noSupKeys := checkUnsupportedKey(composeObject)
|
||||
for _, keyName := range noSupKeys {
|
||||
log.Warningf("Unsupported %s key - ignoring", keyName)
|
||||
}
|
||||
|
||||
// Map the parsed struct to a struct we understand (kobject)
|
||||
komposeObject, err := libComposeToKomposeMapping(composeObject)
|
||||
if err != nil {
|
||||
return kobject.KomposeObject{}, err
|
||||
}
|
||||
|
||||
return komposeObject, nil
|
||||
}
|
||||
|
||||
// Load ports from compose file
|
||||
func loadPorts(composePorts []string) ([]kobject.Ports, error) {
|
||||
ports := []kobject.Ports{}
|
||||
character := ":"
|
||||
|
||||
// For each port listed
|
||||
for _, port := range composePorts {
|
||||
|
||||
// Get the TCP / UDP protocol. Checks to see if it splits in 2 with '/' character.
|
||||
// ex. 15000:15000/tcp
|
||||
// else, set a default protocol of using TCP
|
||||
proto := api.ProtocolTCP
|
||||
protocolCheck := strings.Split(port, "/")
|
||||
if len(protocolCheck) == 2 {
|
||||
if strings.EqualFold("tcp", protocolCheck[1]) {
|
||||
proto = api.ProtocolTCP
|
||||
} else if strings.EqualFold("udp", protocolCheck[1]) {
|
||||
proto = api.ProtocolUDP
|
||||
} else {
|
||||
return nil, fmt.Errorf("invalid protocol %q", protocolCheck[1])
|
||||
}
|
||||
}
|
||||
|
||||
// Split up the ports / IP without the "/tcp" or "/udp" appended to it
|
||||
justPorts := strings.Split(protocolCheck[0], character)
|
||||
|
||||
if len(justPorts) == 3 {
|
||||
// ex. 127.0.0.1:80:80
|
||||
|
||||
// Get the IP address
|
||||
hostIP := justPorts[0]
|
||||
ip := net.ParseIP(hostIP)
|
||||
if ip.To4() == nil && ip.To16() == nil {
|
||||
return nil, fmt.Errorf("%q contains an invalid IPv4 or IPv6 IP address", port)
|
||||
}
|
||||
|
||||
// Get the host port
|
||||
hostPortInt, err := strconv.Atoi(justPorts[1])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid host port %q valid example: 127.0.0.1:80:80", port)
|
||||
}
|
||||
|
||||
// Get the container port
|
||||
containerPortInt, err := strconv.Atoi(justPorts[2])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid container port %q valid example: 127.0.0.1:80:80", port)
|
||||
}
|
||||
|
||||
// Convert to a kobject struct with ports as well as IP
|
||||
ports = append(ports, kobject.Ports{
|
||||
HostPort: int32(hostPortInt),
|
||||
ContainerPort: int32(containerPortInt),
|
||||
HostIP: hostIP,
|
||||
Protocol: proto,
|
||||
})
|
||||
|
||||
} else if len(justPorts) == 2 {
|
||||
// ex. 80:80
|
||||
|
||||
// Get the host port
|
||||
hostPortInt, err := strconv.Atoi(justPorts[0])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid host port %q valid example: 80:80", port)
|
||||
}
|
||||
|
||||
// Get the container port
|
||||
containerPortInt, err := strconv.Atoi(justPorts[1])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid container port %q valid example: 80:80", port)
|
||||
}
|
||||
|
||||
// Convert to a kobject struct and add to the list of ports
|
||||
ports = append(ports, kobject.Ports{
|
||||
HostPort: int32(hostPortInt),
|
||||
ContainerPort: int32(containerPortInt),
|
||||
Protocol: proto,
|
||||
})
|
||||
|
||||
} else {
|
||||
// ex. 80
|
||||
|
||||
containerPortInt, err := strconv.Atoi(justPorts[0])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid container port %q valid example: 80", port)
|
||||
}
|
||||
ports = append(ports, kobject.Ports{
|
||||
ContainerPort: int32(containerPortInt),
|
||||
Protocol: proto,
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
return ports, nil
|
||||
}
|
||||
|
||||
// Uses libcompose's APIProject type and converts it to a Kompose object for us to understand
|
||||
func libComposeToKomposeMapping(composeObject *project.Project) (kobject.KomposeObject, error) {
|
||||
|
||||
// Initialize what's going to be returned
|
||||
komposeObject := kobject.KomposeObject{
|
||||
ServiceConfigs: make(map[string]kobject.ServiceConfig),
|
||||
LoadedFrom: "compose",
|
||||
}
|
||||
|
||||
// Here we "clean up" the service configuration so we return something that includes
|
||||
// all relevant information as well as avoid the unsupported keys as well.
|
||||
for name, composeServiceConfig := range composeObject.ServiceConfigs.All() {
|
||||
serviceConfig := kobject.ServiceConfig{}
|
||||
serviceConfig.Image = composeServiceConfig.Image
|
||||
serviceConfig.Build = composeServiceConfig.Build.Context
|
||||
newName := normalizeServiceNames(composeServiceConfig.ContainerName)
|
||||
serviceConfig.ContainerName = newName
|
||||
if newName != composeServiceConfig.ContainerName {
|
||||
log.Infof("Container name in service %q has been changed from %q to %q", name, composeServiceConfig.ContainerName, newName)
|
||||
}
|
||||
serviceConfig.Command = composeServiceConfig.Entrypoint
|
||||
serviceConfig.Args = composeServiceConfig.Command
|
||||
serviceConfig.Dockerfile = composeServiceConfig.Build.Dockerfile
|
||||
serviceConfig.BuildArgs = composeServiceConfig.Build.Args
|
||||
|
||||
envs := loadEnvVars(composeServiceConfig.Environment)
|
||||
serviceConfig.Environment = envs
|
||||
|
||||
//Validate dockerfile path
|
||||
if filepath.IsAbs(serviceConfig.Dockerfile) {
|
||||
log.Fatalf("%q defined in service %q is an absolute path, it must be a relative path.", serviceConfig.Dockerfile, name)
|
||||
}
|
||||
|
||||
// load ports
|
||||
ports, err := loadPorts(composeServiceConfig.Ports)
|
||||
if err != nil {
|
||||
return kobject.KomposeObject{}, errors.Wrap(err, "loadPorts failed. "+name+" failed to load ports from compose file")
|
||||
}
|
||||
serviceConfig.Port = ports
|
||||
|
||||
serviceConfig.WorkingDir = composeServiceConfig.WorkingDir
|
||||
|
||||
if composeServiceConfig.Volumes != nil {
|
||||
for _, volume := range composeServiceConfig.Volumes.Volumes {
|
||||
v := normalizeServiceNames(volume.String())
|
||||
serviceConfig.Volumes = append(serviceConfig.Volumes, v)
|
||||
}
|
||||
}
|
||||
|
||||
// canonical "Custom Labels" handler
|
||||
// Labels used to influence conversion of kompose will be handled
|
||||
// from here for docker-compose. Each loader will have such handler.
|
||||
for key, value := range composeServiceConfig.Labels {
|
||||
switch key {
|
||||
case "kompose.service.type":
|
||||
serviceType, err := handleServiceType(value)
|
||||
if err != nil {
|
||||
return kobject.KomposeObject{}, errors.Wrap(err, "handleServiceType failed")
|
||||
}
|
||||
|
||||
serviceConfig.ServiceType = serviceType
|
||||
case "kompose.service.expose":
|
||||
serviceConfig.ExposeService = strings.ToLower(value)
|
||||
}
|
||||
}
|
||||
|
||||
// convert compose labels to annotations
|
||||
serviceConfig.Annotations = map[string]string(composeServiceConfig.Labels)
|
||||
serviceConfig.CPUQuota = int64(composeServiceConfig.CPUQuota)
|
||||
serviceConfig.CapAdd = composeServiceConfig.CapAdd
|
||||
serviceConfig.CapDrop = composeServiceConfig.CapDrop
|
||||
serviceConfig.Pid = composeServiceConfig.Pid
|
||||
serviceConfig.Expose = composeServiceConfig.Expose
|
||||
serviceConfig.Privileged = composeServiceConfig.Privileged
|
||||
serviceConfig.Restart = composeServiceConfig.Restart
|
||||
serviceConfig.User = composeServiceConfig.User
|
||||
serviceConfig.VolumesFrom = composeServiceConfig.VolumesFrom
|
||||
serviceConfig.Stdin = composeServiceConfig.StdinOpen
|
||||
serviceConfig.Tty = composeServiceConfig.Tty
|
||||
serviceConfig.MemLimit = composeServiceConfig.MemLimit
|
||||
serviceConfig.TmpFs = composeServiceConfig.Tmpfs
|
||||
serviceConfig.StopGracePeriod = composeServiceConfig.StopGracePeriod
|
||||
komposeObject.ServiceConfigs[normalizeServiceNames(name)] = serviceConfig
|
||||
if normalizeServiceNames(name) != name {
|
||||
log.Infof("Service name in docker-compose has been changed from %q to %q", name, normalizeServiceNames(name))
|
||||
}
|
||||
}
|
||||
return komposeObject, nil
|
||||
}
|
||||
234
pkg/loader/compose/v3.go
Normal file
234
pkg/loader/compose/v3.go
Normal file
@ -0,0 +1,234 @@
|
||||
/*
|
||||
Copyright 2016 The Kubernetes Authors All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package compose
|
||||
|
||||
import (
|
||||
libcomposeyaml "github.com/docker/libcompose/yaml"
|
||||
"io/ioutil"
|
||||
"strings"
|
||||
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
|
||||
"github.com/docker/cli/cli/compose/loader"
|
||||
"github.com/docker/cli/cli/compose/types"
|
||||
|
||||
log "github.com/Sirupsen/logrus"
|
||||
"github.com/kubernetes-incubator/kompose/pkg/kobject"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// The purpose of this is not to deploy, but to be able to parse
|
||||
// v3 of Docker Compose into a suitable format. In this case, whatever is returned
|
||||
// by docker/cli's ServiceConfig
|
||||
func parseV3(files []string) (kobject.KomposeObject, error) {
|
||||
|
||||
// In order to get V3 parsing to work, we have to go through some preliminary steps
|
||||
// for us to hack up github.com/docker/cli in order to correctly convert to a kobject.KomposeObject
|
||||
|
||||
// Gather the working directory
|
||||
workingDir, err := getComposeFileDir(files)
|
||||
if err != nil {
|
||||
return kobject.KomposeObject{}, err
|
||||
}
|
||||
|
||||
// Load and then parse the YAML first!
|
||||
loadedFile, err := ioutil.ReadFile(files[0])
|
||||
if err != nil {
|
||||
return kobject.KomposeObject{}, err
|
||||
}
|
||||
|
||||
// Parse the Compose File
|
||||
parsedComposeFile, err := loader.ParseYAML(loadedFile)
|
||||
if err != nil {
|
||||
return kobject.KomposeObject{}, err
|
||||
}
|
||||
|
||||
// Config file
|
||||
configFile := types.ConfigFile{
|
||||
Filename: files[0],
|
||||
Config: parsedComposeFile,
|
||||
}
|
||||
|
||||
// Config details
|
||||
// Environment is nil as docker/cli loads the appropriate environmental values itself
|
||||
configDetails := types.ConfigDetails{
|
||||
WorkingDir: workingDir,
|
||||
ConfigFiles: []types.ConfigFile{configFile},
|
||||
Environment: nil,
|
||||
}
|
||||
|
||||
// Actual config
|
||||
// We load it in order to retrieve the parsed output configuration!
|
||||
// This will output a github.com/docker/cli ServiceConfig
|
||||
// Which is similar to our version of ServiceConfig
|
||||
config, err := loader.Load(configDetails)
|
||||
if err != nil {
|
||||
return kobject.KomposeObject{}, err
|
||||
}
|
||||
|
||||
// TODO: Check all "unsupported" keys and output details
|
||||
// Specifically, keys such as "volumes_from" are not supported in V3.
|
||||
|
||||
// Finally, we convert the object from docker/cli's ServiceConfig to our appropriate one
|
||||
komposeObject, err := dockerComposeToKomposeMapping(config)
|
||||
if err != nil {
|
||||
return kobject.KomposeObject{}, err
|
||||
}
|
||||
|
||||
return komposeObject, nil
|
||||
}
|
||||
|
||||
// Convert the Docker Compose v3 volumes to []string (the old way)
|
||||
// TODO: Check to see if it's a "bind" or "volume". Ignore for now.
|
||||
// TODO: Refactor it similar to loadV3Ports
|
||||
// See: https://docs.docker.com/compose/compose-file/#long-syntax-2
|
||||
func loadV3Volumes(volumes []types.ServiceVolumeConfig) []string {
|
||||
var volArray []string
|
||||
for _, vol := range volumes {
|
||||
|
||||
// There will *always* be Source when parsing
|
||||
v := normalizeServiceNames(vol.Source)
|
||||
|
||||
if vol.Target != "" {
|
||||
v = v + ":" + vol.Target
|
||||
}
|
||||
|
||||
if vol.ReadOnly {
|
||||
v = v + ":ro"
|
||||
}
|
||||
|
||||
volArray = append(volArray, v)
|
||||
}
|
||||
return volArray
|
||||
}
|
||||
|
||||
// Convert Docker Compose v3 ports to kobject.Ports
|
||||
func loadV3Ports(ports []types.ServicePortConfig) []kobject.Ports {
|
||||
komposePorts := []kobject.Ports{}
|
||||
|
||||
for _, port := range ports {
|
||||
|
||||
// Convert to a kobject struct with ports
|
||||
// NOTE: V3 doesn't use IP (they utilize Swarm instead for host-networking).
|
||||
// Thus, IP is blank.
|
||||
komposePorts = append(komposePorts, kobject.Ports{
|
||||
HostPort: int32(port.Published),
|
||||
ContainerPort: int32(port.Target),
|
||||
HostIP: "",
|
||||
Protocol: api.Protocol(strings.ToUpper(string(port.Protocol))),
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
return komposePorts
|
||||
}
|
||||
|
||||
func dockerComposeToKomposeMapping(composeObject *types.Config) (kobject.KomposeObject, error) {
|
||||
|
||||
// Step 1. Initialize what's going to be returned
|
||||
komposeObject := kobject.KomposeObject{
|
||||
ServiceConfigs: make(map[string]kobject.ServiceConfig),
|
||||
LoadedFrom: "compose",
|
||||
}
|
||||
|
||||
// Step 2. Parse through the object and conver it to kobject.KomposeObject!
|
||||
// Here we "clean up" the service configuration so we return something that includes
|
||||
// all relevant information as well as avoid the unsupported keys as well.
|
||||
for _, composeServiceConfig := range composeObject.Services {
|
||||
|
||||
// Standard import
|
||||
// No need to modify before importation
|
||||
name := composeServiceConfig.Name
|
||||
serviceConfig := kobject.ServiceConfig{}
|
||||
serviceConfig.Image = composeServiceConfig.Image
|
||||
serviceConfig.WorkingDir = composeServiceConfig.WorkingDir
|
||||
serviceConfig.Annotations = map[string]string(composeServiceConfig.Labels)
|
||||
serviceConfig.CapAdd = composeServiceConfig.CapAdd
|
||||
serviceConfig.CapDrop = composeServiceConfig.CapDrop
|
||||
serviceConfig.Expose = composeServiceConfig.Expose
|
||||
serviceConfig.Privileged = composeServiceConfig.Privileged
|
||||
serviceConfig.Restart = composeServiceConfig.Restart
|
||||
serviceConfig.User = composeServiceConfig.User
|
||||
serviceConfig.Stdin = composeServiceConfig.StdinOpen
|
||||
serviceConfig.Tty = composeServiceConfig.Tty
|
||||
serviceConfig.TmpFs = composeServiceConfig.Tmpfs
|
||||
serviceConfig.ContainerName = composeServiceConfig.ContainerName
|
||||
serviceConfig.Command = composeServiceConfig.Entrypoint
|
||||
serviceConfig.Args = composeServiceConfig.Command
|
||||
|
||||
// This is a bit messy since we use yaml.MemStringorInt
|
||||
// TODO: Refactor yaml.MemStringorInt in kobject.go to int64
|
||||
// Since Deploy.Resources.Limits does not initialize, we must check type Resources before continuing
|
||||
if (composeServiceConfig.Deploy.Resources != types.Resources{}) {
|
||||
serviceConfig.MemLimit = libcomposeyaml.MemStringorInt(composeServiceConfig.Deploy.Resources.Limits.MemoryBytes)
|
||||
}
|
||||
|
||||
// POOF. volumes_From is gone in v3. docker/cli will error out of volumes_from is added in v3
|
||||
// serviceConfig.VolumesFrom = composeServiceConfig.VolumesFrom
|
||||
|
||||
// TODO: Build is not yet supported, see:
|
||||
// https://github.com/docker/cli/blob/master/cli/compose/types/types.go#L9
|
||||
// We will have to *manually* add this / parse.
|
||||
// serviceConfig.Build = composeServiceConfig.Build.Context
|
||||
// serviceConfig.Dockerfile = composeServiceConfig.Build.Dockerfile
|
||||
|
||||
// Gather the environment values
|
||||
// DockerCompose uses map[string]*string while we use []string
|
||||
// So let's convert that using this hack
|
||||
for name, value := range composeServiceConfig.Environment {
|
||||
env := kobject.EnvVar{Name: name, Value: *value}
|
||||
serviceConfig.Environment = append(serviceConfig.Environment, env)
|
||||
}
|
||||
|
||||
// Parse the ports
|
||||
// v3 uses a new format called "long syntax" starting in 3.2
|
||||
// https://docs.docker.com/compose/compose-file/#ports
|
||||
serviceConfig.Port = loadV3Ports(composeServiceConfig.Ports)
|
||||
|
||||
// Parse the volumes
|
||||
// Again, in v3, we use the "long syntax" for volumes in terms of parsing
|
||||
// https://docs.docker.com/compose/compose-file/#long-syntax-2
|
||||
serviceConfig.Volumes = loadV3Volumes(composeServiceConfig.Volumes)
|
||||
|
||||
// Label handler
|
||||
// Labels used to influence conversion of kompose will be handled
|
||||
// from here for docker-compose. Each loader will have such handler.
|
||||
for key, value := range composeServiceConfig.Labels {
|
||||
switch key {
|
||||
case "kompose.service.type":
|
||||
serviceType, err := handleServiceType(value)
|
||||
if err != nil {
|
||||
return kobject.KomposeObject{}, errors.Wrap(err, "handleServiceType failed")
|
||||
}
|
||||
|
||||
serviceConfig.ServiceType = serviceType
|
||||
case "kompose.service.expose":
|
||||
serviceConfig.ExposeService = strings.ToLower(value)
|
||||
}
|
||||
}
|
||||
|
||||
// Log if the name will been changed
|
||||
if normalizeServiceNames(name) != name {
|
||||
log.Infof("Service name in docker-compose has been changed from %q to %q", name, normalizeServiceNames(name))
|
||||
}
|
||||
|
||||
// Final step, add to the array!
|
||||
komposeObject.ServiceConfigs[normalizeServiceNames(name)] = serviceConfig
|
||||
}
|
||||
|
||||
return komposeObject, nil
|
||||
}
|
||||
@ -249,4 +249,29 @@ convert::expect_success "kompose --provider=openshift convert --stdout -j" "$KOM
|
||||
# Return back to the original path
|
||||
cd $CURRENT_DIR
|
||||
|
||||
# Test V3 Support of Docker Compose
|
||||
|
||||
# Test volumes are passed correctly
|
||||
convert::expect_success "kompose convert --stdout -j -f $KOMPOSE_ROOT/script/test/fixtures/v3/docker-compose-volumes.yaml" "$KOMPOSE_ROOT/script/test/fixtures/v3/output-volumes-k8s.json"
|
||||
|
||||
# Test environment variables are passed correctly
|
||||
convert::expect_success "kompose convert --stdout -j -f $KOMPOSE_ROOT/script/test/fixtures/v3/docker-compose-env.yaml" "$KOMPOSE_ROOT/script/test/fixtures/v3/output-env-k8s.json"
|
||||
|
||||
# Test that two files that are different versions fail
|
||||
convert::expect_failure "kompose convert --stdout -j -f $KOMPOSE_ROOT/script/test/fixtures/v3/docker-compose.yaml -f $KOMPOSE_ROOT/script/test/fixtures/etherpad/docker-compose.yml"
|
||||
|
||||
# Kubernetes
|
||||
convert::expect_success "kompose convert --stdout -j -f $KOMPOSE_ROOT/script/test/fixtures/v3/docker-compose.yaml" "$KOMPOSE_ROOT/script/test/fixtures/v3/output-k8s.json"
|
||||
|
||||
# OpenShift
|
||||
convert::expect_success "kompose convert --provider=openshift --stdout -j -f $KOMPOSE_ROOT/script/test/fixtures/v3/docker-compose.yaml" "$KOMPOSE_ROOT/script/test/fixtures/v3/output-os.json"
|
||||
|
||||
# Test the "full example" from https://raw.githubusercontent.com/aanand/compose-file/master/loader/example1.env
|
||||
|
||||
# Kubernetes
|
||||
convert::expect_success_and_warning "kompose convert --stdout -j -f $KOMPOSE_ROOT/script/test/fixtures/v3/docker-compose-full-example.yaml" "$KOMPOSE_ROOT/script/test/fixtures/v3/output-k8s-full-example.json"
|
||||
|
||||
# Openshift
|
||||
convert::expect_success_and_warning "kompose convert --provider=openshift --stdout -j -f $KOMPOSE_ROOT/script/test/fixtures/v3/docker-compose-full-example.yaml" "$KOMPOSE_ROOT/script/test/fixtures/v3/output-os-full-example.json"
|
||||
|
||||
exit $EXIT_STATUS
|
||||
|
||||
6
script/test/fixtures/v3/docker-compose-env.yaml
vendored
Normal file
6
script/test/fixtures/v3/docker-compose-env.yaml
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
version: '3'
|
||||
services:
|
||||
foo:
|
||||
image: foo/bar:latest
|
||||
environment:
|
||||
FOO: foo
|
||||
268
script/test/fixtures/v3/docker-compose-full-example.yaml
vendored
Normal file
268
script/test/fixtures/v3/docker-compose-full-example.yaml
vendored
Normal file
@ -0,0 +1,268 @@
|
||||
version: "3"
|
||||
|
||||
services:
|
||||
foo:
|
||||
cap_add:
|
||||
- ALL
|
||||
|
||||
cap_drop:
|
||||
- NET_ADMIN
|
||||
- SYS_ADMIN
|
||||
|
||||
cgroup_parent: m-executor-abcd
|
||||
|
||||
# String or list
|
||||
command: bundle exec thin -p 3000
|
||||
# command: ["bundle", "exec", "thin", "-p", "3000"]
|
||||
|
||||
container_name: my-web-container
|
||||
|
||||
depends_on:
|
||||
- db
|
||||
- redis
|
||||
|
||||
deploy:
|
||||
mode: replicated
|
||||
replicas: 6
|
||||
labels: [FOO=BAR]
|
||||
update_config:
|
||||
parallelism: 3
|
||||
delay: 10s
|
||||
failure_action: continue
|
||||
monitor: 60s
|
||||
max_failure_ratio: 0.3
|
||||
resources:
|
||||
limits:
|
||||
cpus: '0.001'
|
||||
memory: 50M
|
||||
reservations:
|
||||
cpus: '0.0001'
|
||||
memory: 20M
|
||||
restart_policy:
|
||||
condition: on_failure
|
||||
delay: 5s
|
||||
max_attempts: 3
|
||||
window: 120s
|
||||
placement:
|
||||
constraints: [node=foo]
|
||||
|
||||
devices:
|
||||
- "/dev/ttyUSB0:/dev/ttyUSB0"
|
||||
|
||||
# String or list
|
||||
# dns: 8.8.8.8
|
||||
dns:
|
||||
- 8.8.8.8
|
||||
- 9.9.9.9
|
||||
|
||||
# String or list
|
||||
# dns_search: example.com
|
||||
dns_search:
|
||||
- dc1.example.com
|
||||
- dc2.example.com
|
||||
|
||||
domainname: foo.com
|
||||
|
||||
# String or list
|
||||
# entrypoint: /code/entrypoint.sh -p 3000
|
||||
entrypoint: ["/code/entrypoint.sh", "-p", "3000"]
|
||||
|
||||
# Items can be strings or numbers
|
||||
expose:
|
||||
- "3000"
|
||||
- 8000
|
||||
|
||||
external_links:
|
||||
- redis_1
|
||||
- project_db_1:mysql
|
||||
- project_db_1:postgresql
|
||||
|
||||
# Mapping or list
|
||||
# Mapping values must be strings
|
||||
# extra_hosts:
|
||||
# somehost: "162.242.195.82"
|
||||
# otherhost: "50.31.209.229"
|
||||
extra_hosts:
|
||||
- "somehost:162.242.195.82"
|
||||
- "otherhost:50.31.209.229"
|
||||
|
||||
hostname: foo
|
||||
|
||||
healthcheck:
|
||||
test: echo "hello world"
|
||||
interval: 10s
|
||||
timeout: 1s
|
||||
retries: 5
|
||||
|
||||
# Any valid image reference - repo, tag, id, sha
|
||||
image: redis
|
||||
# image: ubuntu:14.04
|
||||
# image: tutum/influxdb
|
||||
# image: example-registry.com:4000/postgresql
|
||||
# image: a4bc65fd
|
||||
# image: busybox@sha256:38a203e1986cf79639cfb9b2e1d6e773de84002feea2d4eb006b52004ee8502d
|
||||
|
||||
ipc: host
|
||||
|
||||
# Mapping or list
|
||||
# Mapping values can be strings, numbers or null
|
||||
labels:
|
||||
com.example.description: "Accounting webapp"
|
||||
com.example.number: 42
|
||||
com.example.empty-label:
|
||||
# labels:
|
||||
# - "com.example.description=Accounting webapp"
|
||||
# - "com.example.number=42"
|
||||
# - "com.example.empty-label"
|
||||
|
||||
links:
|
||||
- db
|
||||
- db:database
|
||||
- redis
|
||||
|
||||
logging:
|
||||
driver: syslog
|
||||
options:
|
||||
syslog-address: "tcp://192.168.0.42:123"
|
||||
|
||||
mac_address: 02:42:ac:11:65:43
|
||||
|
||||
# network_mode: "bridge"
|
||||
# network_mode: "host"
|
||||
# network_mode: "none"
|
||||
# Use the network mode of an arbitrary container from another service
|
||||
# network_mode: "service:db"
|
||||
# Use the network mode of another container, specified by name or id
|
||||
# network_mode: "container:some-container"
|
||||
network_mode: "container:0cfeab0f748b9a743dc3da582046357c6ef497631c1a016d28d2bf9b4f899f7b"
|
||||
|
||||
networks:
|
||||
some-network:
|
||||
aliases:
|
||||
- alias1
|
||||
- alias3
|
||||
other-network:
|
||||
ipv4_address: 172.16.238.10
|
||||
ipv6_address: 2001:3984:3989::10
|
||||
other-other-network:
|
||||
|
||||
pid: "host"
|
||||
|
||||
ports:
|
||||
- 3000
|
||||
- "3000-3005"
|
||||
- "8000:8000"
|
||||
- "9090-9091:8080-8081"
|
||||
- "49100:22"
|
||||
- "127.0.0.1:8001:8001"
|
||||
- "127.0.0.1:5000-5010:5000-5010"
|
||||
|
||||
privileged: true
|
||||
|
||||
read_only: true
|
||||
|
||||
restart: always
|
||||
|
||||
security_opt:
|
||||
- label=level:s0:c100,c200
|
||||
- label=type:svirt_apache_t
|
||||
|
||||
stdin_open: true
|
||||
|
||||
stop_grace_period: 20s
|
||||
|
||||
stop_signal: SIGUSR1
|
||||
|
||||
# String or list
|
||||
# tmpfs: /run
|
||||
tmpfs:
|
||||
- /run
|
||||
- /tmp
|
||||
|
||||
tty: true
|
||||
|
||||
ulimits:
|
||||
# Single number or mapping with soft + hard limits
|
||||
nproc: 65535
|
||||
nofile:
|
||||
soft: 20000
|
||||
hard: 40000
|
||||
|
||||
user: someone
|
||||
|
||||
volumes:
|
||||
# Just specify a path and let the Engine create a volume
|
||||
- /var/lib/mysql
|
||||
# Specify an absolute path mapping
|
||||
- /opt/data:/var/lib/mysql
|
||||
# Path on the host, relative to the Compose file
|
||||
- .:/code
|
||||
- ./static:/var/www/html
|
||||
# User-relative path
|
||||
- ~/configs:/etc/configs/:ro
|
||||
# Named volume
|
||||
- datavolume:/var/lib/mysql
|
||||
|
||||
working_dir: /code
|
||||
|
||||
networks:
|
||||
# Entries can be null, which specifies simply that a network
|
||||
# called "{project name}_some-network" should be created and
|
||||
# use the default driver
|
||||
some-network:
|
||||
|
||||
other-network:
|
||||
driver: overlay
|
||||
|
||||
driver_opts:
|
||||
# Values can be strings or numbers
|
||||
foo: "bar"
|
||||
baz: 1
|
||||
|
||||
ipam:
|
||||
driver: overlay
|
||||
# driver_opts:
|
||||
# # Values can be strings or numbers
|
||||
# com.docker.network.enable_ipv6: "true"
|
||||
# com.docker.network.numeric_value: 1
|
||||
config:
|
||||
- subnet: 172.16.238.0/24
|
||||
# gateway: 172.16.238.1
|
||||
- subnet: 2001:3984:3989::/64
|
||||
# gateway: 2001:3984:3989::1
|
||||
|
||||
external-network:
|
||||
# Specifies that a pre-existing network called "external-network"
|
||||
# can be referred to within this file as "external-network"
|
||||
external: true
|
||||
|
||||
other-external-network:
|
||||
# Specifies that a pre-existing network called "my-cool-network"
|
||||
# can be referred to within this file as "other-external-network"
|
||||
external:
|
||||
name: my-cool-network
|
||||
|
||||
volumes:
|
||||
# Entries can be null, which specifies simply that a volume
|
||||
# called "{project name}_some-volume" should be created and
|
||||
# use the default driver
|
||||
some-volume:
|
||||
|
||||
other-volume:
|
||||
driver: flocker
|
||||
|
||||
driver_opts:
|
||||
# Values can be strings or numbers
|
||||
foo: "bar"
|
||||
baz: 1
|
||||
|
||||
external-volume:
|
||||
# Specifies that a pre-existing volume called "external-volume"
|
||||
# can be referred to within this file as "external-volume"
|
||||
external: true
|
||||
|
||||
other-external-volume:
|
||||
# Specifies that a pre-existing volume called "my-cool-volume"
|
||||
# can be referred to within this file as "other-external-volume"
|
||||
external:
|
||||
name: my-cool-volume
|
||||
8
script/test/fixtures/v3/docker-compose-volumes.yaml
vendored
Normal file
8
script/test/fixtures/v3/docker-compose-volumes.yaml
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
version: "3"
|
||||
|
||||
services:
|
||||
|
||||
foobar:
|
||||
image: foo/bar:latest
|
||||
volumes:
|
||||
- /tmp/foo/bar
|
||||
24
script/test/fixtures/v3/docker-compose.yaml
vendored
Normal file
24
script/test/fixtures/v3/docker-compose.yaml
vendored
Normal file
@ -0,0 +1,24 @@
|
||||
version: "3"
|
||||
|
||||
services:
|
||||
|
||||
redis-master:
|
||||
image: gcr.io/google_containers/redis:e2e
|
||||
ports:
|
||||
- "6379"
|
||||
|
||||
redis-slave:
|
||||
image: gcr.io/google_samples/gb-redisslave:v1
|
||||
ports:
|
||||
- "6379"
|
||||
environment:
|
||||
- GET_HOSTS_FROM=dns
|
||||
|
||||
frontend:
|
||||
image: gcr.io/google-samples/gb-frontend:v4
|
||||
ports:
|
||||
- "80:80"
|
||||
environment:
|
||||
- GET_HOSTS_FROM=dns
|
||||
labels:
|
||||
kompose.service.type: LoadBalancer
|
||||
8
script/test/fixtures/v3/example1.env
vendored
Normal file
8
script/test/fixtures/v3/example1.env
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
# passed through
|
||||
FOO=1
|
||||
|
||||
# overridden in example2.env
|
||||
BAR=1
|
||||
|
||||
# overridden in full-example.yml
|
||||
BAZ=1
|
||||
1
script/test/fixtures/v3/example2.env
vendored
Normal file
1
script/test/fixtures/v3/example2.env
vendored
Normal file
@ -0,0 +1 @@
|
||||
BAR=2
|
||||
74
script/test/fixtures/v3/output-env-k8s.json
vendored
Normal file
74
script/test/fixtures/v3/output-env-k8s.json
vendored
Normal file
@ -0,0 +1,74 @@
|
||||
{
|
||||
"kind": "List",
|
||||
"apiVersion": "v1",
|
||||
"metadata": {},
|
||||
"items": [
|
||||
{
|
||||
"kind": "Service",
|
||||
"apiVersion": "v1",
|
||||
"metadata": {
|
||||
"name": "foo",
|
||||
"creationTimestamp": null,
|
||||
"labels": {
|
||||
"io.kompose.service": "foo"
|
||||
}
|
||||
},
|
||||
"spec": {
|
||||
"ports": [
|
||||
{
|
||||
"name": "headless",
|
||||
"port": 55555,
|
||||
"targetPort": 0
|
||||
}
|
||||
],
|
||||
"selector": {
|
||||
"io.kompose.service": "foo"
|
||||
},
|
||||
"clusterIP": "None"
|
||||
},
|
||||
"status": {
|
||||
"loadBalancer": {}
|
||||
}
|
||||
},
|
||||
{
|
||||
"kind": "Deployment",
|
||||
"apiVersion": "extensions/v1beta1",
|
||||
"metadata": {
|
||||
"name": "foo",
|
||||
"creationTimestamp": null,
|
||||
"labels": {
|
||||
"io.kompose.service": "foo"
|
||||
}
|
||||
},
|
||||
"spec": {
|
||||
"replicas": 1,
|
||||
"template": {
|
||||
"metadata": {
|
||||
"creationTimestamp": null,
|
||||
"labels": {
|
||||
"io.kompose.service": "foo"
|
||||
}
|
||||
},
|
||||
"spec": {
|
||||
"containers": [
|
||||
{
|
||||
"name": "foo",
|
||||
"image": "foo/bar:latest",
|
||||
"env": [
|
||||
{
|
||||
"name": "FOO",
|
||||
"value": "foo"
|
||||
}
|
||||
],
|
||||
"resources": {}
|
||||
}
|
||||
],
|
||||
"restartPolicy": "Always"
|
||||
}
|
||||
},
|
||||
"strategy": {}
|
||||
},
|
||||
"status": {}
|
||||
}
|
||||
]
|
||||
}
|
||||
509
script/test/fixtures/v3/output-k8s-full-example.json
vendored
Normal file
509
script/test/fixtures/v3/output-k8s-full-example.json
vendored
Normal file
@ -0,0 +1,509 @@
|
||||
{
|
||||
"kind": "List",
|
||||
"apiVersion": "v1",
|
||||
"metadata": {},
|
||||
"items": [
|
||||
{
|
||||
"kind": "Service",
|
||||
"apiVersion": "v1",
|
||||
"metadata": {
|
||||
"name": "foo",
|
||||
"creationTimestamp": null,
|
||||
"labels": {
|
||||
"io.kompose.service": "foo"
|
||||
},
|
||||
"annotations": {
|
||||
"com.example.description": "Accounting webapp",
|
||||
"com.example.empty-label": "",
|
||||
"com.example.number": "42"
|
||||
}
|
||||
},
|
||||
"spec": {
|
||||
"ports": [
|
||||
{
|
||||
"name": "3000",
|
||||
"port": 3000,
|
||||
"targetPort": 3000
|
||||
},
|
||||
{
|
||||
"name": "3000",
|
||||
"port": 3000,
|
||||
"targetPort": 3000
|
||||
},
|
||||
{
|
||||
"name": "3001",
|
||||
"port": 3001,
|
||||
"targetPort": 3001
|
||||
},
|
||||
{
|
||||
"name": "3002",
|
||||
"port": 3002,
|
||||
"targetPort": 3002
|
||||
},
|
||||
{
|
||||
"name": "3003",
|
||||
"port": 3003,
|
||||
"targetPort": 3003
|
||||
},
|
||||
{
|
||||
"name": "3004",
|
||||
"port": 3004,
|
||||
"targetPort": 3004
|
||||
},
|
||||
{
|
||||
"name": "3005",
|
||||
"port": 3005,
|
||||
"targetPort": 3005
|
||||
},
|
||||
{
|
||||
"name": "8000",
|
||||
"port": 8000,
|
||||
"targetPort": 8000
|
||||
},
|
||||
{
|
||||
"name": "9090",
|
||||
"port": 9090,
|
||||
"targetPort": 8080
|
||||
},
|
||||
{
|
||||
"name": "9091",
|
||||
"port": 9091,
|
||||
"targetPort": 8081
|
||||
},
|
||||
{
|
||||
"name": "49100",
|
||||
"port": 49100,
|
||||
"targetPort": 22
|
||||
},
|
||||
{
|
||||
"name": "8001",
|
||||
"port": 8001,
|
||||
"targetPort": 8001
|
||||
},
|
||||
{
|
||||
"name": "5000",
|
||||
"port": 5000,
|
||||
"targetPort": 5000
|
||||
},
|
||||
{
|
||||
"name": "5001",
|
||||
"port": 5001,
|
||||
"targetPort": 5001
|
||||
},
|
||||
{
|
||||
"name": "5002",
|
||||
"port": 5002,
|
||||
"targetPort": 5002
|
||||
},
|
||||
{
|
||||
"name": "5003",
|
||||
"port": 5003,
|
||||
"targetPort": 5003
|
||||
},
|
||||
{
|
||||
"name": "5004",
|
||||
"port": 5004,
|
||||
"targetPort": 5004
|
||||
},
|
||||
{
|
||||
"name": "5005",
|
||||
"port": 5005,
|
||||
"targetPort": 5005
|
||||
},
|
||||
{
|
||||
"name": "5006",
|
||||
"port": 5006,
|
||||
"targetPort": 5006
|
||||
},
|
||||
{
|
||||
"name": "5007",
|
||||
"port": 5007,
|
||||
"targetPort": 5007
|
||||
},
|
||||
{
|
||||
"name": "5008",
|
||||
"port": 5008,
|
||||
"targetPort": 5008
|
||||
},
|
||||
{
|
||||
"name": "5009",
|
||||
"port": 5009,
|
||||
"targetPort": 5009
|
||||
},
|
||||
{
|
||||
"name": "5010",
|
||||
"port": 5010,
|
||||
"targetPort": 5010
|
||||
}
|
||||
],
|
||||
"selector": {
|
||||
"io.kompose.service": "foo"
|
||||
}
|
||||
},
|
||||
"status": {
|
||||
"loadBalancer": {}
|
||||
}
|
||||
},
|
||||
{
|
||||
"kind": "Deployment",
|
||||
"apiVersion": "extensions/v1beta1",
|
||||
"metadata": {
|
||||
"name": "foo",
|
||||
"creationTimestamp": null,
|
||||
"labels": {
|
||||
"io.kompose.service": "foo"
|
||||
},
|
||||
"annotations": {
|
||||
"com.example.description": "Accounting webapp",
|
||||
"com.example.empty-label": "",
|
||||
"com.example.number": "42"
|
||||
}
|
||||
},
|
||||
"spec": {
|
||||
"replicas": 1,
|
||||
"template": {
|
||||
"metadata": {
|
||||
"creationTimestamp": null,
|
||||
"labels": {
|
||||
"io.kompose.service": "foo"
|
||||
}
|
||||
},
|
||||
"spec": {
|
||||
"volumes": [
|
||||
{
|
||||
"name": "foo-claim0",
|
||||
"persistentVolumeClaim": {
|
||||
"claimName": "foo-claim0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "foo-claim1",
|
||||
"persistentVolumeClaim": {
|
||||
"claimName": "foo-claim1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "foo-claim2",
|
||||
"persistentVolumeClaim": {
|
||||
"claimName": "foo-claim2"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "foo-claim3",
|
||||
"persistentVolumeClaim": {
|
||||
"claimName": "foo-claim3"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "foo-claim4",
|
||||
"persistentVolumeClaim": {
|
||||
"claimName": "foo-claim4",
|
||||
"readOnly": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "datavolume",
|
||||
"persistentVolumeClaim": {
|
||||
"claimName": "datavolume"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "foo-tmpfs0",
|
||||
"emptyDir": {
|
||||
"medium": "Memory"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "foo-tmpfs1",
|
||||
"emptyDir": {
|
||||
"medium": "Memory"
|
||||
}
|
||||
}
|
||||
],
|
||||
"containers": [
|
||||
{
|
||||
"name": "my-web-container",
|
||||
"image": "redis",
|
||||
"command": [
|
||||
"/code/entrypoint.sh",
|
||||
"-p",
|
||||
"3000"
|
||||
],
|
||||
"args": [
|
||||
"bundle",
|
||||
"exec",
|
||||
"thin",
|
||||
"-p",
|
||||
"3000"
|
||||
],
|
||||
"workingDir": "/code",
|
||||
"ports": [
|
||||
{
|
||||
"containerPort": 3000
|
||||
},
|
||||
{
|
||||
"containerPort": 3000
|
||||
},
|
||||
{
|
||||
"containerPort": 3001
|
||||
},
|
||||
{
|
||||
"containerPort": 3002
|
||||
},
|
||||
{
|
||||
"containerPort": 3003
|
||||
},
|
||||
{
|
||||
"containerPort": 3004
|
||||
},
|
||||
{
|
||||
"containerPort": 3005
|
||||
},
|
||||
{
|
||||
"containerPort": 8000
|
||||
},
|
||||
{
|
||||
"containerPort": 8080
|
||||
},
|
||||
{
|
||||
"containerPort": 8081
|
||||
},
|
||||
{
|
||||
"containerPort": 22
|
||||
},
|
||||
{
|
||||
"containerPort": 8001
|
||||
},
|
||||
{
|
||||
"containerPort": 5000
|
||||
},
|
||||
{
|
||||
"containerPort": 5001
|
||||
},
|
||||
{
|
||||
"containerPort": 5002
|
||||
},
|
||||
{
|
||||
"containerPort": 5003
|
||||
},
|
||||
{
|
||||
"containerPort": 5004
|
||||
},
|
||||
{
|
||||
"containerPort": 5005
|
||||
},
|
||||
{
|
||||
"containerPort": 5006
|
||||
},
|
||||
{
|
||||
"containerPort": 5007
|
||||
},
|
||||
{
|
||||
"containerPort": 5008
|
||||
},
|
||||
{
|
||||
"containerPort": 5009
|
||||
},
|
||||
{
|
||||
"containerPort": 5010
|
||||
}
|
||||
],
|
||||
"resources": {
|
||||
"limits": {
|
||||
"memory": "52428800"
|
||||
}
|
||||
},
|
||||
"volumeMounts": [
|
||||
{
|
||||
"name": "foo-claim0",
|
||||
"mountPath": "/var/lib/mysql"
|
||||
},
|
||||
{
|
||||
"name": "foo-claim1",
|
||||
"mountPath": "/var/lib/mysql"
|
||||
},
|
||||
{
|
||||
"name": "foo-claim2",
|
||||
"mountPath": "/code"
|
||||
},
|
||||
{
|
||||
"name": "foo-claim3",
|
||||
"mountPath": "/var/www/html"
|
||||
},
|
||||
{
|
||||
"name": "foo-claim4",
|
||||
"readOnly": true,
|
||||
"mountPath": "/etc/configs/"
|
||||
},
|
||||
{
|
||||
"name": "datavolume",
|
||||
"mountPath": "/var/lib/mysql"
|
||||
},
|
||||
{
|
||||
"name": "foo-tmpfs0",
|
||||
"mountPath": "/run"
|
||||
},
|
||||
{
|
||||
"name": "foo-tmpfs1",
|
||||
"mountPath": "/tmp"
|
||||
}
|
||||
],
|
||||
"securityContext": {
|
||||
"capabilities": {
|
||||
"add": [
|
||||
"ALL"
|
||||
],
|
||||
"drop": [
|
||||
"NET_ADMIN",
|
||||
"SYS_ADMIN"
|
||||
]
|
||||
},
|
||||
"privileged": true
|
||||
},
|
||||
"stdin": true,
|
||||
"tty": true
|
||||
}
|
||||
],
|
||||
"restartPolicy": "Always"
|
||||
}
|
||||
},
|
||||
"strategy": {
|
||||
"type": "Recreate"
|
||||
}
|
||||
},
|
||||
"status": {}
|
||||
},
|
||||
{
|
||||
"kind": "PersistentVolumeClaim",
|
||||
"apiVersion": "v1",
|
||||
"metadata": {
|
||||
"name": "foo-claim0",
|
||||
"creationTimestamp": null,
|
||||
"labels": {
|
||||
"io.kompose.service": "foo-claim0"
|
||||
}
|
||||
},
|
||||
"spec": {
|
||||
"accessModes": [
|
||||
"ReadWriteOnce"
|
||||
],
|
||||
"resources": {
|
||||
"requests": {
|
||||
"storage": "100Mi"
|
||||
}
|
||||
}
|
||||
},
|
||||
"status": {}
|
||||
},
|
||||
{
|
||||
"kind": "PersistentVolumeClaim",
|
||||
"apiVersion": "v1",
|
||||
"metadata": {
|
||||
"name": "foo-claim1",
|
||||
"creationTimestamp": null,
|
||||
"labels": {
|
||||
"io.kompose.service": "foo-claim1"
|
||||
}
|
||||
},
|
||||
"spec": {
|
||||
"accessModes": [
|
||||
"ReadWriteOnce"
|
||||
],
|
||||
"resources": {
|
||||
"requests": {
|
||||
"storage": "100Mi"
|
||||
}
|
||||
}
|
||||
},
|
||||
"status": {}
|
||||
},
|
||||
{
|
||||
"kind": "PersistentVolumeClaim",
|
||||
"apiVersion": "v1",
|
||||
"metadata": {
|
||||
"name": "foo-claim2",
|
||||
"creationTimestamp": null,
|
||||
"labels": {
|
||||
"io.kompose.service": "foo-claim2"
|
||||
}
|
||||
},
|
||||
"spec": {
|
||||
"accessModes": [
|
||||
"ReadWriteOnce"
|
||||
],
|
||||
"resources": {
|
||||
"requests": {
|
||||
"storage": "100Mi"
|
||||
}
|
||||
}
|
||||
},
|
||||
"status": {}
|
||||
},
|
||||
{
|
||||
"kind": "PersistentVolumeClaim",
|
||||
"apiVersion": "v1",
|
||||
"metadata": {
|
||||
"name": "foo-claim3",
|
||||
"creationTimestamp": null,
|
||||
"labels": {
|
||||
"io.kompose.service": "foo-claim3"
|
||||
}
|
||||
},
|
||||
"spec": {
|
||||
"accessModes": [
|
||||
"ReadWriteOnce"
|
||||
],
|
||||
"resources": {
|
||||
"requests": {
|
||||
"storage": "100Mi"
|
||||
}
|
||||
}
|
||||
},
|
||||
"status": {}
|
||||
},
|
||||
{
|
||||
"kind": "PersistentVolumeClaim",
|
||||
"apiVersion": "v1",
|
||||
"metadata": {
|
||||
"name": "foo-claim4",
|
||||
"creationTimestamp": null,
|
||||
"labels": {
|
||||
"io.kompose.service": "foo-claim4"
|
||||
}
|
||||
},
|
||||
"spec": {
|
||||
"accessModes": [
|
||||
"ReadOnlyMany"
|
||||
],
|
||||
"resources": {
|
||||
"requests": {
|
||||
"storage": "100Mi"
|
||||
}
|
||||
}
|
||||
},
|
||||
"status": {}
|
||||
},
|
||||
{
|
||||
"kind": "PersistentVolumeClaim",
|
||||
"apiVersion": "v1",
|
||||
"metadata": {
|
||||
"name": "datavolume",
|
||||
"creationTimestamp": null,
|
||||
"labels": {
|
||||
"io.kompose.service": "datavolume"
|
||||
}
|
||||
},
|
||||
"spec": {
|
||||
"accessModes": [
|
||||
"ReadWriteOnce"
|
||||
],
|
||||
"resources": {
|
||||
"requests": {
|
||||
"storage": "100Mi"
|
||||
}
|
||||
}
|
||||
},
|
||||
"status": {}
|
||||
}
|
||||
]
|
||||
}
|
||||
221
script/test/fixtures/v3/output-k8s.json
vendored
Normal file
221
script/test/fixtures/v3/output-k8s.json
vendored
Normal file
@ -0,0 +1,221 @@
|
||||
{
|
||||
"kind": "List",
|
||||
"apiVersion": "v1",
|
||||
"metadata": {},
|
||||
"items": [
|
||||
{
|
||||
"kind": "Service",
|
||||
"apiVersion": "v1",
|
||||
"metadata": {
|
||||
"name": "frontend",
|
||||
"creationTimestamp": null,
|
||||
"labels": {
|
||||
"io.kompose.service": "frontend"
|
||||
},
|
||||
"annotations": {
|
||||
"kompose.service.type": "LoadBalancer"
|
||||
}
|
||||
},
|
||||
"spec": {
|
||||
"ports": [
|
||||
{
|
||||
"name": "80",
|
||||
"port": 80,
|
||||
"targetPort": 80
|
||||
}
|
||||
],
|
||||
"selector": {
|
||||
"io.kompose.service": "frontend"
|
||||
},
|
||||
"type": "LoadBalancer"
|
||||
},
|
||||
"status": {
|
||||
"loadBalancer": {}
|
||||
}
|
||||
},
|
||||
{
|
||||
"kind": "Service",
|
||||
"apiVersion": "v1",
|
||||
"metadata": {
|
||||
"name": "redis-master",
|
||||
"creationTimestamp": null,
|
||||
"labels": {
|
||||
"io.kompose.service": "redis-master"
|
||||
}
|
||||
},
|
||||
"spec": {
|
||||
"ports": [
|
||||
{
|
||||
"name": "6379",
|
||||
"port": 6379,
|
||||
"targetPort": 6379
|
||||
}
|
||||
],
|
||||
"selector": {
|
||||
"io.kompose.service": "redis-master"
|
||||
}
|
||||
},
|
||||
"status": {
|
||||
"loadBalancer": {}
|
||||
}
|
||||
},
|
||||
{
|
||||
"kind": "Service",
|
||||
"apiVersion": "v1",
|
||||
"metadata": {
|
||||
"name": "redis-slave",
|
||||
"creationTimestamp": null,
|
||||
"labels": {
|
||||
"io.kompose.service": "redis-slave"
|
||||
}
|
||||
},
|
||||
"spec": {
|
||||
"ports": [
|
||||
{
|
||||
"name": "6379",
|
||||
"port": 6379,
|
||||
"targetPort": 6379
|
||||
}
|
||||
],
|
||||
"selector": {
|
||||
"io.kompose.service": "redis-slave"
|
||||
}
|
||||
},
|
||||
"status": {
|
||||
"loadBalancer": {}
|
||||
}
|
||||
},
|
||||
{
|
||||
"kind": "Deployment",
|
||||
"apiVersion": "extensions/v1beta1",
|
||||
"metadata": {
|
||||
"name": "frontend",
|
||||
"creationTimestamp": null,
|
||||
"labels": {
|
||||
"io.kompose.service": "frontend"
|
||||
},
|
||||
"annotations": {
|
||||
"kompose.service.type": "LoadBalancer"
|
||||
}
|
||||
},
|
||||
"spec": {
|
||||
"replicas": 1,
|
||||
"template": {
|
||||
"metadata": {
|
||||
"creationTimestamp": null,
|
||||
"labels": {
|
||||
"io.kompose.service": "frontend"
|
||||
}
|
||||
},
|
||||
"spec": {
|
||||
"containers": [
|
||||
{
|
||||
"name": "frontend",
|
||||
"image": "gcr.io/google-samples/gb-frontend:v4",
|
||||
"ports": [
|
||||
{
|
||||
"containerPort": 80
|
||||
}
|
||||
],
|
||||
"env": [
|
||||
{
|
||||
"name": "GET_HOSTS_FROM",
|
||||
"value": "dns"
|
||||
}
|
||||
],
|
||||
"resources": {}
|
||||
}
|
||||
],
|
||||
"restartPolicy": "Always"
|
||||
}
|
||||
},
|
||||
"strategy": {}
|
||||
},
|
||||
"status": {}
|
||||
},
|
||||
{
|
||||
"kind": "Deployment",
|
||||
"apiVersion": "extensions/v1beta1",
|
||||
"metadata": {
|
||||
"name": "redis-master",
|
||||
"creationTimestamp": null,
|
||||
"labels": {
|
||||
"io.kompose.service": "redis-master"
|
||||
}
|
||||
},
|
||||
"spec": {
|
||||
"replicas": 1,
|
||||
"template": {
|
||||
"metadata": {
|
||||
"creationTimestamp": null,
|
||||
"labels": {
|
||||
"io.kompose.service": "redis-master"
|
||||
}
|
||||
},
|
||||
"spec": {
|
||||
"containers": [
|
||||
{
|
||||
"name": "redis-master",
|
||||
"image": "gcr.io/google_containers/redis:e2e",
|
||||
"ports": [
|
||||
{
|
||||
"containerPort": 6379
|
||||
}
|
||||
],
|
||||
"resources": {}
|
||||
}
|
||||
],
|
||||
"restartPolicy": "Always"
|
||||
}
|
||||
},
|
||||
"strategy": {}
|
||||
},
|
||||
"status": {}
|
||||
},
|
||||
{
|
||||
"kind": "Deployment",
|
||||
"apiVersion": "extensions/v1beta1",
|
||||
"metadata": {
|
||||
"name": "redis-slave",
|
||||
"creationTimestamp": null,
|
||||
"labels": {
|
||||
"io.kompose.service": "redis-slave"
|
||||
}
|
||||
},
|
||||
"spec": {
|
||||
"replicas": 1,
|
||||
"template": {
|
||||
"metadata": {
|
||||
"creationTimestamp": null,
|
||||
"labels": {
|
||||
"io.kompose.service": "redis-slave"
|
||||
}
|
||||
},
|
||||
"spec": {
|
||||
"containers": [
|
||||
{
|
||||
"name": "redis-slave",
|
||||
"image": "gcr.io/google_samples/gb-redisslave:v1",
|
||||
"ports": [
|
||||
{
|
||||
"containerPort": 6379
|
||||
}
|
||||
],
|
||||
"env": [
|
||||
{
|
||||
"name": "GET_HOSTS_FROM",
|
||||
"value": "dns"
|
||||
}
|
||||
],
|
||||
"resources": {}
|
||||
}
|
||||
],
|
||||
"restartPolicy": "Always"
|
||||
}
|
||||
},
|
||||
"strategy": {}
|
||||
},
|
||||
"status": {}
|
||||
}
|
||||
]
|
||||
}
|
||||
560
script/test/fixtures/v3/output-os-full-example.json
vendored
Normal file
560
script/test/fixtures/v3/output-os-full-example.json
vendored
Normal file
@ -0,0 +1,560 @@
|
||||
{
|
||||
"kind": "List",
|
||||
"apiVersion": "v1",
|
||||
"metadata": {},
|
||||
"items": [
|
||||
{
|
||||
"kind": "Service",
|
||||
"apiVersion": "v1",
|
||||
"metadata": {
|
||||
"name": "foo",
|
||||
"creationTimestamp": null,
|
||||
"labels": {
|
||||
"io.kompose.service": "foo"
|
||||
},
|
||||
"annotations": {
|
||||
"com.example.description": "Accounting webapp",
|
||||
"com.example.empty-label": "",
|
||||
"com.example.number": "42"
|
||||
}
|
||||
},
|
||||
"spec": {
|
||||
"ports": [
|
||||
{
|
||||
"name": "3000",
|
||||
"port": 3000,
|
||||
"targetPort": 3000
|
||||
},
|
||||
{
|
||||
"name": "3000",
|
||||
"port": 3000,
|
||||
"targetPort": 3000
|
||||
},
|
||||
{
|
||||
"name": "3001",
|
||||
"port": 3001,
|
||||
"targetPort": 3001
|
||||
},
|
||||
{
|
||||
"name": "3002",
|
||||
"port": 3002,
|
||||
"targetPort": 3002
|
||||
},
|
||||
{
|
||||
"name": "3003",
|
||||
"port": 3003,
|
||||
"targetPort": 3003
|
||||
},
|
||||
{
|
||||
"name": "3004",
|
||||
"port": 3004,
|
||||
"targetPort": 3004
|
||||
},
|
||||
{
|
||||
"name": "3005",
|
||||
"port": 3005,
|
||||
"targetPort": 3005
|
||||
},
|
||||
{
|
||||
"name": "8000",
|
||||
"port": 8000,
|
||||
"targetPort": 8000
|
||||
},
|
||||
{
|
||||
"name": "9090",
|
||||
"port": 9090,
|
||||
"targetPort": 8080
|
||||
},
|
||||
{
|
||||
"name": "9091",
|
||||
"port": 9091,
|
||||
"targetPort": 8081
|
||||
},
|
||||
{
|
||||
"name": "49100",
|
||||
"port": 49100,
|
||||
"targetPort": 22
|
||||
},
|
||||
{
|
||||
"name": "8001",
|
||||
"port": 8001,
|
||||
"targetPort": 8001
|
||||
},
|
||||
{
|
||||
"name": "5000",
|
||||
"port": 5000,
|
||||
"targetPort": 5000
|
||||
},
|
||||
{
|
||||
"name": "5001",
|
||||
"port": 5001,
|
||||
"targetPort": 5001
|
||||
},
|
||||
{
|
||||
"name": "5002",
|
||||
"port": 5002,
|
||||
"targetPort": 5002
|
||||
},
|
||||
{
|
||||
"name": "5003",
|
||||
"port": 5003,
|
||||
"targetPort": 5003
|
||||
},
|
||||
{
|
||||
"name": "5004",
|
||||
"port": 5004,
|
||||
"targetPort": 5004
|
||||
},
|
||||
{
|
||||
"name": "5005",
|
||||
"port": 5005,
|
||||
"targetPort": 5005
|
||||
},
|
||||
{
|
||||
"name": "5006",
|
||||
"port": 5006,
|
||||
"targetPort": 5006
|
||||
},
|
||||
{
|
||||
"name": "5007",
|
||||
"port": 5007,
|
||||
"targetPort": 5007
|
||||
},
|
||||
{
|
||||
"name": "5008",
|
||||
"port": 5008,
|
||||
"targetPort": 5008
|
||||
},
|
||||
{
|
||||
"name": "5009",
|
||||
"port": 5009,
|
||||
"targetPort": 5009
|
||||
},
|
||||
{
|
||||
"name": "5010",
|
||||
"port": 5010,
|
||||
"targetPort": 5010
|
||||
}
|
||||
],
|
||||
"selector": {
|
||||
"io.kompose.service": "foo"
|
||||
}
|
||||
},
|
||||
"status": {
|
||||
"loadBalancer": {}
|
||||
}
|
||||
},
|
||||
{
|
||||
"kind": "DeploymentConfig",
|
||||
"apiVersion": "v1",
|
||||
"metadata": {
|
||||
"name": "foo",
|
||||
"creationTimestamp": null,
|
||||
"labels": {
|
||||
"io.kompose.service": "foo"
|
||||
},
|
||||
"annotations": {
|
||||
"com.example.description": "Accounting webapp",
|
||||
"com.example.empty-label": "",
|
||||
"com.example.number": "42"
|
||||
}
|
||||
},
|
||||
"spec": {
|
||||
"strategy": {
|
||||
"type": "Recreate",
|
||||
"resources": {}
|
||||
},
|
||||
"triggers": [
|
||||
{
|
||||
"type": "ConfigChange"
|
||||
},
|
||||
{
|
||||
"type": "ImageChange",
|
||||
"imageChangeParams": {
|
||||
"automatic": true,
|
||||
"containerNames": [
|
||||
"my-web-container"
|
||||
],
|
||||
"from": {
|
||||
"kind": "ImageStreamTag",
|
||||
"name": "foo:latest"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"replicas": 1,
|
||||
"test": false,
|
||||
"selector": {
|
||||
"io.kompose.service": "foo"
|
||||
},
|
||||
"template": {
|
||||
"metadata": {
|
||||
"creationTimestamp": null,
|
||||
"labels": {
|
||||
"io.kompose.service": "foo"
|
||||
}
|
||||
},
|
||||
"spec": {
|
||||
"volumes": [
|
||||
{
|
||||
"name": "foo-claim0",
|
||||
"persistentVolumeClaim": {
|
||||
"claimName": "foo-claim0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "foo-claim1",
|
||||
"persistentVolumeClaim": {
|
||||
"claimName": "foo-claim1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "foo-claim2",
|
||||
"persistentVolumeClaim": {
|
||||
"claimName": "foo-claim2"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "foo-claim3",
|
||||
"persistentVolumeClaim": {
|
||||
"claimName": "foo-claim3"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "foo-claim4",
|
||||
"persistentVolumeClaim": {
|
||||
"claimName": "foo-claim4",
|
||||
"readOnly": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "datavolume",
|
||||
"persistentVolumeClaim": {
|
||||
"claimName": "datavolume"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "foo-tmpfs0",
|
||||
"emptyDir": {
|
||||
"medium": "Memory"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "foo-tmpfs1",
|
||||
"emptyDir": {
|
||||
"medium": "Memory"
|
||||
}
|
||||
}
|
||||
],
|
||||
"containers": [
|
||||
{
|
||||
"name": "my-web-container",
|
||||
"image": " ",
|
||||
"command": [
|
||||
"/code/entrypoint.sh",
|
||||
"-p",
|
||||
"3000"
|
||||
],
|
||||
"args": [
|
||||
"bundle",
|
||||
"exec",
|
||||
"thin",
|
||||
"-p",
|
||||
"3000"
|
||||
],
|
||||
"workingDir": "/code",
|
||||
"ports": [
|
||||
{
|
||||
"containerPort": 3000
|
||||
},
|
||||
{
|
||||
"containerPort": 3000
|
||||
},
|
||||
{
|
||||
"containerPort": 3001
|
||||
},
|
||||
{
|
||||
"containerPort": 3002
|
||||
},
|
||||
{
|
||||
"containerPort": 3003
|
||||
},
|
||||
{
|
||||
"containerPort": 3004
|
||||
},
|
||||
{
|
||||
"containerPort": 3005
|
||||
},
|
||||
{
|
||||
"containerPort": 8000
|
||||
},
|
||||
{
|
||||
"containerPort": 8080
|
||||
},
|
||||
{
|
||||
"containerPort": 8081
|
||||
},
|
||||
{
|
||||
"containerPort": 22
|
||||
},
|
||||
{
|
||||
"containerPort": 8001
|
||||
},
|
||||
{
|
||||
"containerPort": 5000
|
||||
},
|
||||
{
|
||||
"containerPort": 5001
|
||||
},
|
||||
{
|
||||
"containerPort": 5002
|
||||
},
|
||||
{
|
||||
"containerPort": 5003
|
||||
},
|
||||
{
|
||||
"containerPort": 5004
|
||||
},
|
||||
{
|
||||
"containerPort": 5005
|
||||
},
|
||||
{
|
||||
"containerPort": 5006
|
||||
},
|
||||
{
|
||||
"containerPort": 5007
|
||||
},
|
||||
{
|
||||
"containerPort": 5008
|
||||
},
|
||||
{
|
||||
"containerPort": 5009
|
||||
},
|
||||
{
|
||||
"containerPort": 5010
|
||||
}
|
||||
],
|
||||
"resources": {
|
||||
"limits": {
|
||||
"memory": "52428800"
|
||||
}
|
||||
},
|
||||
"volumeMounts": [
|
||||
{
|
||||
"name": "foo-claim0",
|
||||
"mountPath": "/var/lib/mysql"
|
||||
},
|
||||
{
|
||||
"name": "foo-claim1",
|
||||
"mountPath": "/var/lib/mysql"
|
||||
},
|
||||
{
|
||||
"name": "foo-claim2",
|
||||
"mountPath": "/code"
|
||||
},
|
||||
{
|
||||
"name": "foo-claim3",
|
||||
"mountPath": "/var/www/html"
|
||||
},
|
||||
{
|
||||
"name": "foo-claim4",
|
||||
"readOnly": true,
|
||||
"mountPath": "/etc/configs/"
|
||||
},
|
||||
{
|
||||
"name": "datavolume",
|
||||
"mountPath": "/var/lib/mysql"
|
||||
},
|
||||
{
|
||||
"name": "foo-tmpfs0",
|
||||
"mountPath": "/run"
|
||||
},
|
||||
{
|
||||
"name": "foo-tmpfs1",
|
||||
"mountPath": "/tmp"
|
||||
}
|
||||
],
|
||||
"securityContext": {
|
||||
"capabilities": {
|
||||
"add": [
|
||||
"ALL"
|
||||
],
|
||||
"drop": [
|
||||
"NET_ADMIN",
|
||||
"SYS_ADMIN"
|
||||
]
|
||||
},
|
||||
"privileged": true
|
||||
},
|
||||
"stdin": true,
|
||||
"tty": true
|
||||
}
|
||||
],
|
||||
"restartPolicy": "Always"
|
||||
}
|
||||
}
|
||||
},
|
||||
"status": {}
|
||||
},
|
||||
{
|
||||
"kind": "ImageStream",
|
||||
"apiVersion": "v1",
|
||||
"metadata": {
|
||||
"name": "foo",
|
||||
"creationTimestamp": null,
|
||||
"labels": {
|
||||
"io.kompose.service": "foo"
|
||||
}
|
||||
},
|
||||
"spec": {
|
||||
"tags": [
|
||||
{
|
||||
"name": "latest",
|
||||
"annotations": null,
|
||||
"from": {
|
||||
"kind": "DockerImage",
|
||||
"name": "redis"
|
||||
},
|
||||
"generation": null,
|
||||
"importPolicy": {}
|
||||
}
|
||||
]
|
||||
},
|
||||
"status": {
|
||||
"dockerImageRepository": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"kind": "PersistentVolumeClaim",
|
||||
"apiVersion": "v1",
|
||||
"metadata": {
|
||||
"name": "foo-claim0",
|
||||
"creationTimestamp": null,
|
||||
"labels": {
|
||||
"io.kompose.service": "foo-claim0"
|
||||
}
|
||||
},
|
||||
"spec": {
|
||||
"accessModes": [
|
||||
"ReadWriteOnce"
|
||||
],
|
||||
"resources": {
|
||||
"requests": {
|
||||
"storage": "100Mi"
|
||||
}
|
||||
}
|
||||
},
|
||||
"status": {}
|
||||
},
|
||||
{
|
||||
"kind": "PersistentVolumeClaim",
|
||||
"apiVersion": "v1",
|
||||
"metadata": {
|
||||
"name": "foo-claim1",
|
||||
"creationTimestamp": null,
|
||||
"labels": {
|
||||
"io.kompose.service": "foo-claim1"
|
||||
}
|
||||
},
|
||||
"spec": {
|
||||
"accessModes": [
|
||||
"ReadWriteOnce"
|
||||
],
|
||||
"resources": {
|
||||
"requests": {
|
||||
"storage": "100Mi"
|
||||
}
|
||||
}
|
||||
},
|
||||
"status": {}
|
||||
},
|
||||
{
|
||||
"kind": "PersistentVolumeClaim",
|
||||
"apiVersion": "v1",
|
||||
"metadata": {
|
||||
"name": "foo-claim2",
|
||||
"creationTimestamp": null,
|
||||
"labels": {
|
||||
"io.kompose.service": "foo-claim2"
|
||||
}
|
||||
},
|
||||
"spec": {
|
||||
"accessModes": [
|
||||
"ReadWriteOnce"
|
||||
],
|
||||
"resources": {
|
||||
"requests": {
|
||||
"storage": "100Mi"
|
||||
}
|
||||
}
|
||||
},
|
||||
"status": {}
|
||||
},
|
||||
{
|
||||
"kind": "PersistentVolumeClaim",
|
||||
"apiVersion": "v1",
|
||||
"metadata": {
|
||||
"name": "foo-claim3",
|
||||
"creationTimestamp": null,
|
||||
"labels": {
|
||||
"io.kompose.service": "foo-claim3"
|
||||
}
|
||||
},
|
||||
"spec": {
|
||||
"accessModes": [
|
||||
"ReadWriteOnce"
|
||||
],
|
||||
"resources": {
|
||||
"requests": {
|
||||
"storage": "100Mi"
|
||||
}
|
||||
}
|
||||
},
|
||||
"status": {}
|
||||
},
|
||||
{
|
||||
"kind": "PersistentVolumeClaim",
|
||||
"apiVersion": "v1",
|
||||
"metadata": {
|
||||
"name": "foo-claim4",
|
||||
"creationTimestamp": null,
|
||||
"labels": {
|
||||
"io.kompose.service": "foo-claim4"
|
||||
}
|
||||
},
|
||||
"spec": {
|
||||
"accessModes": [
|
||||
"ReadOnlyMany"
|
||||
],
|
||||
"resources": {
|
||||
"requests": {
|
||||
"storage": "100Mi"
|
||||
}
|
||||
}
|
||||
},
|
||||
"status": {}
|
||||
},
|
||||
{
|
||||
"kind": "PersistentVolumeClaim",
|
||||
"apiVersion": "v1",
|
||||
"metadata": {
|
||||
"name": "datavolume",
|
||||
"creationTimestamp": null,
|
||||
"labels": {
|
||||
"io.kompose.service": "datavolume"
|
||||
}
|
||||
},
|
||||
"spec": {
|
||||
"accessModes": [
|
||||
"ReadWriteOnce"
|
||||
],
|
||||
"resources": {
|
||||
"requests": {
|
||||
"storage": "100Mi"
|
||||
}
|
||||
}
|
||||
},
|
||||
"status": {}
|
||||
}
|
||||
]
|
||||
}
|
||||
377
script/test/fixtures/v3/output-os.json
vendored
Normal file
377
script/test/fixtures/v3/output-os.json
vendored
Normal file
@ -0,0 +1,377 @@
|
||||
{
|
||||
"kind": "List",
|
||||
"apiVersion": "v1",
|
||||
"metadata": {},
|
||||
"items": [
|
||||
{
|
||||
"kind": "Service",
|
||||
"apiVersion": "v1",
|
||||
"metadata": {
|
||||
"name": "frontend",
|
||||
"creationTimestamp": null,
|
||||
"labels": {
|
||||
"io.kompose.service": "frontend"
|
||||
},
|
||||
"annotations": {
|
||||
"kompose.service.type": "LoadBalancer"
|
||||
}
|
||||
},
|
||||
"spec": {
|
||||
"ports": [
|
||||
{
|
||||
"name": "80",
|
||||
"port": 80,
|
||||
"targetPort": 80
|
||||
}
|
||||
],
|
||||
"selector": {
|
||||
"io.kompose.service": "frontend"
|
||||
},
|
||||
"type": "LoadBalancer"
|
||||
},
|
||||
"status": {
|
||||
"loadBalancer": {}
|
||||
}
|
||||
},
|
||||
{
|
||||
"kind": "Service",
|
||||
"apiVersion": "v1",
|
||||
"metadata": {
|
||||
"name": "redis-master",
|
||||
"creationTimestamp": null,
|
||||
"labels": {
|
||||
"io.kompose.service": "redis-master"
|
||||
}
|
||||
},
|
||||
"spec": {
|
||||
"ports": [
|
||||
{
|
||||
"name": "6379",
|
||||
"port": 6379,
|
||||
"targetPort": 6379
|
||||
}
|
||||
],
|
||||
"selector": {
|
||||
"io.kompose.service": "redis-master"
|
||||
}
|
||||
},
|
||||
"status": {
|
||||
"loadBalancer": {}
|
||||
}
|
||||
},
|
||||
{
|
||||
"kind": "Service",
|
||||
"apiVersion": "v1",
|
||||
"metadata": {
|
||||
"name": "redis-slave",
|
||||
"creationTimestamp": null,
|
||||
"labels": {
|
||||
"io.kompose.service": "redis-slave"
|
||||
}
|
||||
},
|
||||
"spec": {
|
||||
"ports": [
|
||||
{
|
||||
"name": "6379",
|
||||
"port": 6379,
|
||||
"targetPort": 6379
|
||||
}
|
||||
],
|
||||
"selector": {
|
||||
"io.kompose.service": "redis-slave"
|
||||
}
|
||||
},
|
||||
"status": {
|
||||
"loadBalancer": {}
|
||||
}
|
||||
},
|
||||
{
|
||||
"kind": "DeploymentConfig",
|
||||
"apiVersion": "v1",
|
||||
"metadata": {
|
||||
"name": "frontend",
|
||||
"creationTimestamp": null,
|
||||
"labels": {
|
||||
"io.kompose.service": "frontend"
|
||||
},
|
||||
"annotations": {
|
||||
"kompose.service.type": "LoadBalancer"
|
||||
}
|
||||
},
|
||||
"spec": {
|
||||
"strategy": {
|
||||
"resources": {}
|
||||
},
|
||||
"triggers": [
|
||||
{
|
||||
"type": "ConfigChange"
|
||||
},
|
||||
{
|
||||
"type": "ImageChange",
|
||||
"imageChangeParams": {
|
||||
"automatic": true,
|
||||
"containerNames": [
|
||||
"frontend"
|
||||
],
|
||||
"from": {
|
||||
"kind": "ImageStreamTag",
|
||||
"name": "frontend:v4"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"replicas": 1,
|
||||
"test": false,
|
||||
"selector": {
|
||||
"io.kompose.service": "frontend"
|
||||
},
|
||||
"template": {
|
||||
"metadata": {
|
||||
"creationTimestamp": null,
|
||||
"labels": {
|
||||
"io.kompose.service": "frontend"
|
||||
}
|
||||
},
|
||||
"spec": {
|
||||
"containers": [
|
||||
{
|
||||
"name": "frontend",
|
||||
"image": " ",
|
||||
"ports": [
|
||||
{
|
||||
"containerPort": 80
|
||||
}
|
||||
],
|
||||
"env": [
|
||||
{
|
||||
"name": "GET_HOSTS_FROM",
|
||||
"value": "dns"
|
||||
}
|
||||
],
|
||||
"resources": {}
|
||||
}
|
||||
],
|
||||
"restartPolicy": "Always"
|
||||
}
|
||||
}
|
||||
},
|
||||
"status": {}
|
||||
},
|
||||
{
|
||||
"kind": "ImageStream",
|
||||
"apiVersion": "v1",
|
||||
"metadata": {
|
||||
"name": "frontend",
|
||||
"creationTimestamp": null,
|
||||
"labels": {
|
||||
"io.kompose.service": "frontend"
|
||||
}
|
||||
},
|
||||
"spec": {
|
||||
"tags": [
|
||||
{
|
||||
"name": "v4",
|
||||
"annotations": null,
|
||||
"from": {
|
||||
"kind": "DockerImage",
|
||||
"name": "gcr.io/google-samples/gb-frontend:v4"
|
||||
},
|
||||
"generation": null,
|
||||
"importPolicy": {}
|
||||
}
|
||||
]
|
||||
},
|
||||
"status": {
|
||||
"dockerImageRepository": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"kind": "DeploymentConfig",
|
||||
"apiVersion": "v1",
|
||||
"metadata": {
|
||||
"name": "redis-master",
|
||||
"creationTimestamp": null,
|
||||
"labels": {
|
||||
"io.kompose.service": "redis-master"
|
||||
}
|
||||
},
|
||||
"spec": {
|
||||
"strategy": {
|
||||
"resources": {}
|
||||
},
|
||||
"triggers": [
|
||||
{
|
||||
"type": "ConfigChange"
|
||||
},
|
||||
{
|
||||
"type": "ImageChange",
|
||||
"imageChangeParams": {
|
||||
"automatic": true,
|
||||
"containerNames": [
|
||||
"redis-master"
|
||||
],
|
||||
"from": {
|
||||
"kind": "ImageStreamTag",
|
||||
"name": "redis-master:e2e"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"replicas": 1,
|
||||
"test": false,
|
||||
"selector": {
|
||||
"io.kompose.service": "redis-master"
|
||||
},
|
||||
"template": {
|
||||
"metadata": {
|
||||
"creationTimestamp": null,
|
||||
"labels": {
|
||||
"io.kompose.service": "redis-master"
|
||||
}
|
||||
},
|
||||
"spec": {
|
||||
"containers": [
|
||||
{
|
||||
"name": "redis-master",
|
||||
"image": " ",
|
||||
"ports": [
|
||||
{
|
||||
"containerPort": 6379
|
||||
}
|
||||
],
|
||||
"resources": {}
|
||||
}
|
||||
],
|
||||
"restartPolicy": "Always"
|
||||
}
|
||||
}
|
||||
},
|
||||
"status": {}
|
||||
},
|
||||
{
|
||||
"kind": "ImageStream",
|
||||
"apiVersion": "v1",
|
||||
"metadata": {
|
||||
"name": "redis-master",
|
||||
"creationTimestamp": null,
|
||||
"labels": {
|
||||
"io.kompose.service": "redis-master"
|
||||
}
|
||||
},
|
||||
"spec": {
|
||||
"tags": [
|
||||
{
|
||||
"name": "e2e",
|
||||
"annotations": null,
|
||||
"from": {
|
||||
"kind": "DockerImage",
|
||||
"name": "gcr.io/google_containers/redis:e2e"
|
||||
},
|
||||
"generation": null,
|
||||
"importPolicy": {}
|
||||
}
|
||||
]
|
||||
},
|
||||
"status": {
|
||||
"dockerImageRepository": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"kind": "DeploymentConfig",
|
||||
"apiVersion": "v1",
|
||||
"metadata": {
|
||||
"name": "redis-slave",
|
||||
"creationTimestamp": null,
|
||||
"labels": {
|
||||
"io.kompose.service": "redis-slave"
|
||||
}
|
||||
},
|
||||
"spec": {
|
||||
"strategy": {
|
||||
"resources": {}
|
||||
},
|
||||
"triggers": [
|
||||
{
|
||||
"type": "ConfigChange"
|
||||
},
|
||||
{
|
||||
"type": "ImageChange",
|
||||
"imageChangeParams": {
|
||||
"automatic": true,
|
||||
"containerNames": [
|
||||
"redis-slave"
|
||||
],
|
||||
"from": {
|
||||
"kind": "ImageStreamTag",
|
||||
"name": "redis-slave:v1"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"replicas": 1,
|
||||
"test": false,
|
||||
"selector": {
|
||||
"io.kompose.service": "redis-slave"
|
||||
},
|
||||
"template": {
|
||||
"metadata": {
|
||||
"creationTimestamp": null,
|
||||
"labels": {
|
||||
"io.kompose.service": "redis-slave"
|
||||
}
|
||||
},
|
||||
"spec": {
|
||||
"containers": [
|
||||
{
|
||||
"name": "redis-slave",
|
||||
"image": " ",
|
||||
"ports": [
|
||||
{
|
||||
"containerPort": 6379
|
||||
}
|
||||
],
|
||||
"env": [
|
||||
{
|
||||
"name": "GET_HOSTS_FROM",
|
||||
"value": "dns"
|
||||
}
|
||||
],
|
||||
"resources": {}
|
||||
}
|
||||
],
|
||||
"restartPolicy": "Always"
|
||||
}
|
||||
}
|
||||
},
|
||||
"status": {}
|
||||
},
|
||||
{
|
||||
"kind": "ImageStream",
|
||||
"apiVersion": "v1",
|
||||
"metadata": {
|
||||
"name": "redis-slave",
|
||||
"creationTimestamp": null,
|
||||
"labels": {
|
||||
"io.kompose.service": "redis-slave"
|
||||
}
|
||||
},
|
||||
"spec": {
|
||||
"tags": [
|
||||
{
|
||||
"name": "v1",
|
||||
"annotations": null,
|
||||
"from": {
|
||||
"kind": "DockerImage",
|
||||
"name": "gcr.io/google_samples/gb-redisslave:v1"
|
||||
},
|
||||
"generation": null,
|
||||
"importPolicy": {}
|
||||
}
|
||||
]
|
||||
},
|
||||
"status": {
|
||||
"dockerImageRepository": ""
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
106
script/test/fixtures/v3/output-volumes-k8s.json
vendored
Normal file
106
script/test/fixtures/v3/output-volumes-k8s.json
vendored
Normal file
@ -0,0 +1,106 @@
|
||||
{
|
||||
"kind": "List",
|
||||
"apiVersion": "v1",
|
||||
"metadata": {},
|
||||
"items": [
|
||||
{
|
||||
"kind": "Service",
|
||||
"apiVersion": "v1",
|
||||
"metadata": {
|
||||
"name": "foobar",
|
||||
"creationTimestamp": null,
|
||||
"labels": {
|
||||
"io.kompose.service": "foobar"
|
||||
}
|
||||
},
|
||||
"spec": {
|
||||
"ports": [
|
||||
{
|
||||
"name": "headless",
|
||||
"port": 55555,
|
||||
"targetPort": 0
|
||||
}
|
||||
],
|
||||
"selector": {
|
||||
"io.kompose.service": "foobar"
|
||||
},
|
||||
"clusterIP": "None"
|
||||
},
|
||||
"status": {
|
||||
"loadBalancer": {}
|
||||
}
|
||||
},
|
||||
{
|
||||
"kind": "Deployment",
|
||||
"apiVersion": "extensions/v1beta1",
|
||||
"metadata": {
|
||||
"name": "foobar",
|
||||
"creationTimestamp": null,
|
||||
"labels": {
|
||||
"io.kompose.service": "foobar"
|
||||
}
|
||||
},
|
||||
"spec": {
|
||||
"replicas": 1,
|
||||
"template": {
|
||||
"metadata": {
|
||||
"creationTimestamp": null,
|
||||
"labels": {
|
||||
"io.kompose.service": "foobar"
|
||||
}
|
||||
},
|
||||
"spec": {
|
||||
"volumes": [
|
||||
{
|
||||
"name": "foobar-claim0",
|
||||
"persistentVolumeClaim": {
|
||||
"claimName": "foobar-claim0"
|
||||
}
|
||||
}
|
||||
],
|
||||
"containers": [
|
||||
{
|
||||
"name": "foobar",
|
||||
"image": "foo/bar:latest",
|
||||
"resources": {},
|
||||
"volumeMounts": [
|
||||
{
|
||||
"name": "foobar-claim0",
|
||||
"mountPath": "/tmp/foo/bar"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"restartPolicy": "Always"
|
||||
}
|
||||
},
|
||||
"strategy": {
|
||||
"type": "Recreate"
|
||||
}
|
||||
},
|
||||
"status": {}
|
||||
},
|
||||
{
|
||||
"kind": "PersistentVolumeClaim",
|
||||
"apiVersion": "v1",
|
||||
"metadata": {
|
||||
"name": "foobar-claim0",
|
||||
"creationTimestamp": null,
|
||||
"labels": {
|
||||
"io.kompose.service": "foobar-claim0"
|
||||
}
|
||||
},
|
||||
"spec": {
|
||||
"accessModes": [
|
||||
"ReadWriteOnce"
|
||||
],
|
||||
"resources": {
|
||||
"requests": {
|
||||
"storage": "100Mi"
|
||||
}
|
||||
}
|
||||
},
|
||||
"status": {}
|
||||
}
|
||||
]
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user