forked from LaconicNetwork/kompose
Merge pull request #324 from rtnpro/unsupported-keys-per-provider
Unsupported keys per provider
This commit is contained in:
commit
48e3ba88cd
@ -16,93 +16,15 @@ limitations under the License.
|
|||||||
|
|
||||||
package kobject
|
package kobject
|
||||||
|
|
||||||
import (
|
import "k8s.io/kubernetes/pkg/api"
|
||||||
"github.com/Sirupsen/logrus"
|
|
||||||
"github.com/fatih/structs"
|
|
||||||
"k8s.io/kubernetes/pkg/api"
|
|
||||||
)
|
|
||||||
|
|
||||||
var unsupportedKey = map[string]int{
|
|
||||||
"Build": 0,
|
|
||||||
"CgroupParent": 0,
|
|
||||||
"Devices": 0,
|
|
||||||
"DependsOn": 0,
|
|
||||||
"DNS": 0,
|
|
||||||
"DNSSearch": 0,
|
|
||||||
"DomainName": 0,
|
|
||||||
"EnvFile": 0,
|
|
||||||
"Extends": 0,
|
|
||||||
"ExternalLinks": 0,
|
|
||||||
"ExtraHosts": 0,
|
|
||||||
"Hostname": 0,
|
|
||||||
"Ipc": 0,
|
|
||||||
"Logging": 0,
|
|
||||||
"MacAddress": 0,
|
|
||||||
"MemLimit": 0,
|
|
||||||
"MemSwapLimit": 0,
|
|
||||||
"NetworkMode": 0,
|
|
||||||
"Pid": 0,
|
|
||||||
"SecurityOpt": 0,
|
|
||||||
"ShmSize": 0,
|
|
||||||
"StopSignal": 0,
|
|
||||||
"VolumeDriver": 0,
|
|
||||||
"Uts": 0,
|
|
||||||
"ReadOnly": 0,
|
|
||||||
"StdinOpen": 0,
|
|
||||||
"Tty": 0,
|
|
||||||
"Ulimits": 0,
|
|
||||||
"Dockerfile": 0,
|
|
||||||
"Net": 0,
|
|
||||||
"Networks": 0,
|
|
||||||
}
|
|
||||||
|
|
||||||
var composeOptions = map[string]string{
|
|
||||||
"Build": "build",
|
|
||||||
"CapAdd": "cap_add",
|
|
||||||
"CapDrop": "cap_drop",
|
|
||||||
"CPUSet": "cpuset",
|
|
||||||
"CPUShares": "cpu_shares",
|
|
||||||
"CPUQuota": "cpu_quota",
|
|
||||||
"CgroupParent": "cgroup_parent",
|
|
||||||
"Devices": "devices",
|
|
||||||
"DependsOn": "depends_on",
|
|
||||||
"DNS": "dns",
|
|
||||||
"DNSSearch": "dns_search",
|
|
||||||
"DomainName": "domainname",
|
|
||||||
"Entrypoint": "entrypoint",
|
|
||||||
"EnvFile": "env_file",
|
|
||||||
"Expose": "expose",
|
|
||||||
"Extends": "extends",
|
|
||||||
"ExternalLinks": "external_links",
|
|
||||||
"ExtraHosts": "extra_hosts",
|
|
||||||
"Hostname": "hostname",
|
|
||||||
"Ipc": "ipc",
|
|
||||||
"Logging": "logging",
|
|
||||||
"MacAddress": "mac_address",
|
|
||||||
"MemLimit": "mem_limit",
|
|
||||||
"MemSwapLimit": "memswap_limit",
|
|
||||||
"NetworkMode": "network_mode",
|
|
||||||
"Networks": "networks",
|
|
||||||
"Pid": "pid",
|
|
||||||
"SecurityOpt": "security_opt",
|
|
||||||
"ShmSize": "shm_size",
|
|
||||||
"StopSignal": "stop_signal",
|
|
||||||
"VolumeDriver": "volume_driver",
|
|
||||||
"VolumesFrom": "volumes_from",
|
|
||||||
"Uts": "uts",
|
|
||||||
"ReadOnly": "read_only",
|
|
||||||
"StdinOpen": "stdin_open",
|
|
||||||
"Tty": "tty",
|
|
||||||
"User": "user",
|
|
||||||
"Ulimits": "ulimits",
|
|
||||||
"Dockerfile": "dockerfile",
|
|
||||||
"Net": "net",
|
|
||||||
"Args": "args",
|
|
||||||
}
|
|
||||||
|
|
||||||
// KomposeObject holds the generic struct of Kompose transformation
|
// KomposeObject holds the generic struct of Kompose transformation
|
||||||
type KomposeObject struct {
|
type KomposeObject struct {
|
||||||
ServiceConfigs map[string]ServiceConfig
|
ServiceConfigs map[string]ServiceConfig
|
||||||
|
// LoadedFrom is name of the loader that created KomposeObject
|
||||||
|
// Transformer need to know origin format in order to tell user what tag is not supported in origin format
|
||||||
|
// as they can have different names. For example environment variables are called environment in compose but Env in bundle.
|
||||||
|
LoadedFrom string
|
||||||
}
|
}
|
||||||
|
|
||||||
type ConvertOptions struct {
|
type ConvertOptions struct {
|
||||||
@ -122,28 +44,30 @@ type ConvertOptions struct {
|
|||||||
|
|
||||||
// ServiceConfig holds the basic struct of a container
|
// ServiceConfig holds the basic struct of a container
|
||||||
type ServiceConfig struct {
|
type ServiceConfig struct {
|
||||||
|
// use tags to mark from what element this value comes
|
||||||
ContainerName string
|
ContainerName string
|
||||||
Image string
|
Image string `compose:"image",bundle:"Image"`
|
||||||
Environment []EnvVar
|
Environment []EnvVar `compose:"environment",bundle:"Env"`
|
||||||
Port []Ports
|
Port []Ports `compose:"ports",bundle:"Ports"`
|
||||||
Command []string
|
Command []string `compose:"command",bundle:"Command"`
|
||||||
WorkingDir string
|
WorkingDir string `compose:"",bundle:"WorkingDir"`
|
||||||
Args []string
|
Args []string `compose:"args",bundle:"Args"`
|
||||||
Volumes []string
|
Volumes []string `compose:"volumes",bundle:"Volumes"`
|
||||||
Network []string
|
Network []string `compose:"network",bundle:"Networks"`
|
||||||
Labels map[string]string
|
Labels map[string]string `compose:"labels",bundle:"Labels"`
|
||||||
Annotations map[string]string
|
Annotations map[string]string `compose:"",bundle:""`
|
||||||
CPUSet string
|
CPUSet string `compose:"cpuset",bundle:""`
|
||||||
CPUShares int64
|
CPUShares int64 `compose:"cpu_shares",bundle:""`
|
||||||
CPUQuota int64
|
CPUQuota int64 `compose:"cpu_quota",bundle:""`
|
||||||
CapAdd []string
|
CapAdd []string `compose:"cap_add",bundle:""`
|
||||||
CapDrop []string
|
CapDrop []string `compose:"cap_drop",bundle:""`
|
||||||
Expose []string
|
Expose []string `compose:"expose",bundle:""`
|
||||||
Privileged bool
|
Privileged bool `compose:"privileged",bundle:""`
|
||||||
Restart string
|
Restart string `compose:"restart",bundle:""`
|
||||||
User string
|
User string `compose:"user",bundle:"User"`
|
||||||
VolumesFrom []string
|
VolumesFrom []string `compose:"volumes_from",bundle:""`
|
||||||
ServiceType string
|
ServiceType string `compose:"kompose.service.type",bundle:""`
|
||||||
|
Build string `compose:"build",bundle:""`
|
||||||
}
|
}
|
||||||
|
|
||||||
// EnvVar holds the environment variable struct of a container
|
// EnvVar holds the environment variable struct of a container
|
||||||
@ -158,15 +82,3 @@ type Ports struct {
|
|||||||
ContainerPort int32
|
ContainerPort int32
|
||||||
Protocol api.Protocol
|
Protocol api.Protocol
|
||||||
}
|
}
|
||||||
|
|
||||||
func CheckUnsupportedKey(service interface{}) {
|
|
||||||
s := structs.New(service)
|
|
||||||
for _, f := range s.Fields() {
|
|
||||||
if f.IsExported() && !f.IsZero() && f.Name() != "Networks" {
|
|
||||||
if count, ok := unsupportedKey[f.Name()]; ok && count == 0 {
|
|
||||||
logrus.Warningf("Unsupported key %s - ignoring", composeOptions[f.Name()])
|
|
||||||
unsupportedKey[f.Name()]++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@ -21,11 +21,13 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
"reflect"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"k8s.io/kubernetes/pkg/api"
|
"k8s.io/kubernetes/pkg/api"
|
||||||
|
|
||||||
"github.com/Sirupsen/logrus"
|
"github.com/Sirupsen/logrus"
|
||||||
|
"github.com/fatih/structs"
|
||||||
"github.com/kubernetes-incubator/kompose/pkg/kobject"
|
"github.com/kubernetes-incubator/kompose/pkg/kobject"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -57,6 +59,51 @@ type Port struct {
|
|||||||
Port uint32
|
Port uint32
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// checkUnsupportedKey checks if dab contains
|
||||||
|
// keys that are not supported by this loader.
|
||||||
|
// list of all unsupported keys are stored in unsupportedKey variable
|
||||||
|
// returns list of unsupported JSON/YAML keys
|
||||||
|
func checkUnsupportedKey(bundleStruct *Bundlefile) []string {
|
||||||
|
// list of all unsupported keys for this loader
|
||||||
|
// this is map to make searching for keys easier
|
||||||
|
// to make sure that unsupported key is not going to be reported twice
|
||||||
|
// by keeping record if already saw this key in another service
|
||||||
|
var unsupportedKey = map[string]bool{
|
||||||
|
"Networks": false,
|
||||||
|
}
|
||||||
|
|
||||||
|
// collect all keys found in project
|
||||||
|
var keysFound []string
|
||||||
|
for _, service := range bundleStruct.Services {
|
||||||
|
// this reflection is used in check for empty arrays
|
||||||
|
val := reflect.ValueOf(service)
|
||||||
|
s := structs.New(service)
|
||||||
|
|
||||||
|
for _, f := range s.Fields() {
|
||||||
|
// Check if given key is among unsupported keys, and skip it if we already saw this key
|
||||||
|
if alreadySaw, ok := unsupportedKey[f.Name()]; ok && !alreadySaw {
|
||||||
|
if f.IsExported() && !f.IsZero() {
|
||||||
|
jsonTagName := strings.Split(f.Tag("json"), ",")[0]
|
||||||
|
if jsonTagName == "" {
|
||||||
|
jsonTagName = f.Name()
|
||||||
|
}
|
||||||
|
// IsZero returns false for empty array/slice ([])
|
||||||
|
// this check if field is Slice, and then it checks its size
|
||||||
|
if field := val.FieldByName(f.Name()); field.Kind() == reflect.Slice {
|
||||||
|
if field.Len() == 0 {
|
||||||
|
// array is empty it doesn't matter if it is in unsupportedKey or not
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
keysFound = append(keysFound, jsonTagName)
|
||||||
|
unsupportedKey[f.Name()] = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return keysFound
|
||||||
|
}
|
||||||
|
|
||||||
// load image from dab file
|
// load image from dab file
|
||||||
func loadImage(service Service) (string, string) {
|
func loadImage(service Service) (string, string) {
|
||||||
character := "@"
|
character := "@"
|
||||||
@ -129,6 +176,7 @@ func loadPorts(service Service) ([]kobject.Ports, string) {
|
|||||||
func (b *Bundle) LoadFile(file string) kobject.KomposeObject {
|
func (b *Bundle) LoadFile(file string) kobject.KomposeObject {
|
||||||
komposeObject := kobject.KomposeObject{
|
komposeObject := kobject.KomposeObject{
|
||||||
ServiceConfigs: make(map[string]kobject.ServiceConfig),
|
ServiceConfigs: make(map[string]kobject.ServiceConfig),
|
||||||
|
LoadedFrom: "bundle",
|
||||||
}
|
}
|
||||||
|
|
||||||
buf, err := ioutil.ReadFile(file)
|
buf, err := ioutil.ReadFile(file)
|
||||||
@ -141,8 +189,12 @@ func (b *Bundle) LoadFile(file string) kobject.KomposeObject {
|
|||||||
logrus.Fatalf("Failed to parse bundles file: %s", err)
|
logrus.Fatalf("Failed to parse bundles file: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
noSupKeys := checkUnsupportedKey(bundle)
|
||||||
|
for _, keyName := range noSupKeys {
|
||||||
|
logrus.Warningf("Unsupported %s key - ignoring", keyName)
|
||||||
|
}
|
||||||
|
|
||||||
for name, service := range bundle.Services {
|
for name, service := range bundle.Services {
|
||||||
kobject.CheckUnsupportedKey(service)
|
|
||||||
|
|
||||||
serviceConfig := kobject.ServiceConfig{}
|
serviceConfig := kobject.ServiceConfig{}
|
||||||
serviceConfig.Command = service.Command
|
serviceConfig.Command = service.Command
|
||||||
|
|||||||
87
pkg/loader/bundle/bundle_test.go
Normal file
87
pkg/loader/bundle/bundle_test.go
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
/*
|
||||||
|
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 bundle
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
// TestUnsupportedKeys test checkUnsupportedKey function with various
|
||||||
|
// docker-compose projects
|
||||||
|
func TestUnsupportedKeys(t *testing.T) {
|
||||||
|
user := "user"
|
||||||
|
workDir := "workDir"
|
||||||
|
|
||||||
|
fullBundle := Bundlefile{
|
||||||
|
Version: "0.1",
|
||||||
|
Services: map[string]Service{
|
||||||
|
"foo": Service{
|
||||||
|
Image: "image",
|
||||||
|
Command: []string{"cmd"},
|
||||||
|
Args: []string{"arg"},
|
||||||
|
Env: []string{"env"},
|
||||||
|
Labels: map[string]string{"key": "value"},
|
||||||
|
Ports: []Port{Port{Protocol: "tcp", Port: uint32(80)}},
|
||||||
|
WorkingDir: &workDir, //there is no other way to get pointer to string
|
||||||
|
User: &user,
|
||||||
|
Networks: []string{"net"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
bundleWithEmptyNetworks := Bundlefile{
|
||||||
|
Version: "0.1",
|
||||||
|
Services: map[string]Service{
|
||||||
|
"foo": Service{
|
||||||
|
Image: "image",
|
||||||
|
Command: []string{"cmd"},
|
||||||
|
Args: []string{"arg"},
|
||||||
|
Env: []string{"env"},
|
||||||
|
Labels: map[string]string{"key": "value"},
|
||||||
|
Ports: []Port{Port{Protocol: "tcp", Port: uint32(80)}},
|
||||||
|
WorkingDir: &workDir, //there is no other way to get pointer to string
|
||||||
|
User: &user,
|
||||||
|
Networks: []string{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
// define all test cases for checkUnsupportedKey function
|
||||||
|
testCases := map[string]struct {
|
||||||
|
bundleFile Bundlefile
|
||||||
|
expectedUnsupportedKeys []string
|
||||||
|
}{
|
||||||
|
"Full Bundle": {
|
||||||
|
fullBundle,
|
||||||
|
[]string{"Networks"},
|
||||||
|
},
|
||||||
|
"Bundle with empty Networks": {
|
||||||
|
bundleWithEmptyNetworks,
|
||||||
|
[]string(nil),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for name, test := range testCases {
|
||||||
|
t.Log("Test case:", name)
|
||||||
|
keys := checkUnsupportedKey(&test.bundleFile)
|
||||||
|
if !reflect.DeepEqual(keys, test.expectedUnsupportedKeys) {
|
||||||
|
t.Errorf("ERROR: Expecting unsupported keys: ['%s']. Got: ['%s']", strings.Join(test.expectedUnsupportedKeys, "', '"), strings.Join(keys, "', '"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -20,6 +20,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"reflect"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
@ -29,12 +30,105 @@ import (
|
|||||||
"github.com/docker/libcompose/config"
|
"github.com/docker/libcompose/config"
|
||||||
"github.com/docker/libcompose/lookup"
|
"github.com/docker/libcompose/lookup"
|
||||||
"github.com/docker/libcompose/project"
|
"github.com/docker/libcompose/project"
|
||||||
|
"github.com/fatih/structs"
|
||||||
"github.com/kubernetes-incubator/kompose/pkg/kobject"
|
"github.com/kubernetes-incubator/kompose/pkg/kobject"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Compose struct {
|
type Compose struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// checkUnsupportedKey checks if libcompose project contains
|
||||||
|
// keys that are not supported by this loader.
|
||||||
|
// list of all unsupported keys are stored in unsupportedKey variable
|
||||||
|
// returns list of unsupported YAML keys from docker-compose
|
||||||
|
func checkUnsupportedKey(composeProject *project.Project) []string {
|
||||||
|
|
||||||
|
// list of all unsupported keys for this loader
|
||||||
|
// this is map to make searching for keys easier
|
||||||
|
// to make sure that unsupported key is not going to be reported twice
|
||||||
|
// by keeping record if already saw this key in another service
|
||||||
|
var unsupportedKey = map[string]bool{
|
||||||
|
"CgroupParent": false,
|
||||||
|
"Devices": false,
|
||||||
|
"DependsOn": false,
|
||||||
|
"DNS": false,
|
||||||
|
"DNSSearch": false,
|
||||||
|
"DomainName": false,
|
||||||
|
"EnvFile": false,
|
||||||
|
"Extends": false,
|
||||||
|
"ExternalLinks": false,
|
||||||
|
"ExtraHosts": false,
|
||||||
|
"Hostname": false,
|
||||||
|
"Ipc": false,
|
||||||
|
"Logging": false,
|
||||||
|
"MacAddress": false,
|
||||||
|
"MemLimit": false,
|
||||||
|
"MemSwapLimit": false,
|
||||||
|
"NetworkMode": false,
|
||||||
|
"Pid": false,
|
||||||
|
"SecurityOpt": false,
|
||||||
|
"ShmSize": false,
|
||||||
|
"StopSignal": false,
|
||||||
|
"VolumeDriver": false,
|
||||||
|
"Uts": false,
|
||||||
|
"ReadOnly": false,
|
||||||
|
"StdinOpen": false,
|
||||||
|
"Tty": false,
|
||||||
|
"Ulimits": false,
|
||||||
|
"Dockerfile": false,
|
||||||
|
"Net": false,
|
||||||
|
"Networks": false, // there are special checks for Network in checkUnsupportedKey function
|
||||||
|
}
|
||||||
|
|
||||||
|
// collect all keys found in project
|
||||||
|
var keysFound []string
|
||||||
|
|
||||||
|
// Root level keys
|
||||||
|
// volume config and network config are not supported
|
||||||
|
if len(composeProject.NetworkConfigs) > 0 {
|
||||||
|
keysFound = append(keysFound, "root level networks")
|
||||||
|
}
|
||||||
|
if len(composeProject.VolumeConfigs) > 0 {
|
||||||
|
keysFound = append(keysFound, "root level volumes")
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, serviceConfig := range composeProject.ServiceConfigs.All() {
|
||||||
|
// this reflection is used in check for empty arrays
|
||||||
|
val := reflect.ValueOf(serviceConfig).Elem()
|
||||||
|
s := structs.New(serviceConfig)
|
||||||
|
|
||||||
|
for _, f := range s.Fields() {
|
||||||
|
// Check if given key is among unsupported keys, and skip it if we already saw this key
|
||||||
|
if alreadySaw, ok := unsupportedKey[f.Name()]; ok && !alreadySaw {
|
||||||
|
if f.IsExported() && !f.IsZero() {
|
||||||
|
// IsZero returns false for empty array/slice ([])
|
||||||
|
// this check if field is Slice, and then it checks its size
|
||||||
|
if field := val.FieldByName(f.Name()); field.Kind() == reflect.Slice {
|
||||||
|
if field.Len() == 0 {
|
||||||
|
// array is empty it doesn't matter if it is in unsupportedKey or not
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//get yaml tag name instad of variable name
|
||||||
|
yamlTagName := strings.Split(f.Tag("yaml"), ",")[0]
|
||||||
|
if f.Name() == "Networks" {
|
||||||
|
// networks always contains one default element, even it isn't declared in compose v2.
|
||||||
|
if len(serviceConfig.Networks.Networks) == 1 && serviceConfig.Networks.Networks[0].Name == "default" {
|
||||||
|
// this is empty Network definition, skip it
|
||||||
|
continue
|
||||||
|
} else {
|
||||||
|
yamlTagName = "networks"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
keysFound = append(keysFound, yamlTagName)
|
||||||
|
unsupportedKey[f.Name()] = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return keysFound
|
||||||
|
}
|
||||||
|
|
||||||
// load environment variables from compose file
|
// load environment variables from compose file
|
||||||
func loadEnvVars(envars []string) []kobject.EnvVar {
|
func loadEnvVars(envars []string) []kobject.EnvVar {
|
||||||
envs := []kobject.EnvVar{}
|
envs := []kobject.EnvVar{}
|
||||||
@ -132,6 +226,7 @@ func loadPorts(composePorts []string) ([]kobject.Ports, error) {
|
|||||||
func (c *Compose) LoadFile(file string) kobject.KomposeObject {
|
func (c *Compose) LoadFile(file string) kobject.KomposeObject {
|
||||||
komposeObject := kobject.KomposeObject{
|
komposeObject := kobject.KomposeObject{
|
||||||
ServiceConfigs: make(map[string]kobject.ServiceConfig),
|
ServiceConfigs: make(map[string]kobject.ServiceConfig),
|
||||||
|
LoadedFrom: "compose",
|
||||||
}
|
}
|
||||||
context := &project.Context{}
|
context := &project.Context{}
|
||||||
if file == "" {
|
if file == "" {
|
||||||
@ -168,31 +263,19 @@ func (c *Compose) LoadFile(file string) kobject.KomposeObject {
|
|||||||
// transform composeObject into komposeObject
|
// transform composeObject into komposeObject
|
||||||
composeServiceNames := composeObject.ServiceConfigs.Keys()
|
composeServiceNames := composeObject.ServiceConfigs.Keys()
|
||||||
|
|
||||||
// volume config and network config are not supported
|
noSupKeys := checkUnsupportedKey(composeObject)
|
||||||
if len(composeObject.NetworkConfigs) > 0 {
|
for _, keyName := range noSupKeys {
|
||||||
logrus.Warningf("Unsupported network configuration of compose v2 - ignoring")
|
logrus.Warningf("Unsupported %s key - ignoring", keyName)
|
||||||
}
|
}
|
||||||
if len(composeObject.VolumeConfigs) > 0 {
|
|
||||||
logrus.Warningf("Unsupported volume configuration of compose v2 - ignoring")
|
|
||||||
}
|
|
||||||
|
|
||||||
networksWarningFound := false
|
|
||||||
|
|
||||||
for _, name := range composeServiceNames {
|
for _, name := range composeServiceNames {
|
||||||
if composeServiceConfig, ok := composeObject.ServiceConfigs.Get(name); ok {
|
if composeServiceConfig, ok := composeObject.ServiceConfigs.Get(name); ok {
|
||||||
//FIXME: networks always contains one default element, even it isn't declared in compose v2.
|
|
||||||
if composeServiceConfig.Networks != nil && len(composeServiceConfig.Networks.Networks) > 0 &&
|
|
||||||
composeServiceConfig.Networks.Networks[0].Name != "default" &&
|
|
||||||
!networksWarningFound {
|
|
||||||
logrus.Warningf("Unsupported key networks - ignoring")
|
|
||||||
networksWarningFound = true
|
|
||||||
}
|
|
||||||
kobject.CheckUnsupportedKey(composeServiceConfig)
|
|
||||||
serviceConfig := kobject.ServiceConfig{}
|
serviceConfig := kobject.ServiceConfig{}
|
||||||
serviceConfig.Image = composeServiceConfig.Image
|
serviceConfig.Image = composeServiceConfig.Image
|
||||||
serviceConfig.ContainerName = composeServiceConfig.ContainerName
|
serviceConfig.ContainerName = composeServiceConfig.ContainerName
|
||||||
serviceConfig.Command = composeServiceConfig.Entrypoint
|
serviceConfig.Command = composeServiceConfig.Entrypoint
|
||||||
serviceConfig.Args = composeServiceConfig.Command
|
serviceConfig.Args = composeServiceConfig.Command
|
||||||
|
serviceConfig.Build = composeServiceConfig.Build.Context
|
||||||
|
|
||||||
envs := loadEnvVars(composeServiceConfig.Environment)
|
envs := loadEnvVars(composeServiceConfig.Environment)
|
||||||
serviceConfig.Environment = envs
|
serviceConfig.Environment = envs
|
||||||
|
|||||||
@ -18,9 +18,15 @@ package compose
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
|
"reflect"
|
||||||
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/kubernetes-incubator/kompose/pkg/kobject"
|
"github.com/kubernetes-incubator/kompose/pkg/kobject"
|
||||||
|
|
||||||
|
"github.com/docker/libcompose/config"
|
||||||
|
"github.com/docker/libcompose/project"
|
||||||
|
"github.com/docker/libcompose/yaml"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Test if service types are parsed properly on user input
|
// Test if service types are parsed properly on user input
|
||||||
@ -112,3 +118,98 @@ func TestLoadEnvVar(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestUnsupportedKeys test checkUnsupportedKey function with various
|
||||||
|
// docker-compose projects
|
||||||
|
func TestUnsupportedKeys(t *testing.T) {
|
||||||
|
// create project that will be used in test cases
|
||||||
|
projectWithNetworks := project.NewProject(&project.Context{}, nil, nil)
|
||||||
|
projectWithNetworks.ServiceConfigs = config.NewServiceConfigs()
|
||||||
|
projectWithNetworks.ServiceConfigs.Add("foo", &config.ServiceConfig{
|
||||||
|
Image: "foo/bar",
|
||||||
|
Build: yaml.Build{
|
||||||
|
Context: "./build",
|
||||||
|
},
|
||||||
|
Hostname: "localhost",
|
||||||
|
Ports: []string{}, // test empty array
|
||||||
|
Networks: &yaml.Networks{
|
||||||
|
Networks: []*yaml.Network{
|
||||||
|
&yaml.Network{
|
||||||
|
Name: "net1",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
projectWithNetworks.ServiceConfigs.Add("bar", &config.ServiceConfig{
|
||||||
|
Image: "bar/foo",
|
||||||
|
Build: yaml.Build{
|
||||||
|
Context: "./build",
|
||||||
|
},
|
||||||
|
Hostname: "localhost",
|
||||||
|
Ports: []string{}, // test empty array
|
||||||
|
Networks: &yaml.Networks{
|
||||||
|
Networks: []*yaml.Network{
|
||||||
|
&yaml.Network{
|
||||||
|
Name: "net1",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
projectWithNetworks.VolumeConfigs = map[string]*config.VolumeConfig{
|
||||||
|
"foo": &config.VolumeConfig{
|
||||||
|
Driver: "storage",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
projectWithNetworks.NetworkConfigs = map[string]*config.NetworkConfig{
|
||||||
|
"foo": &config.NetworkConfig{
|
||||||
|
Driver: "bridge",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
projectWithEmptyNetwork := project.NewProject(&project.Context{}, nil, nil)
|
||||||
|
projectWithEmptyNetwork.ServiceConfigs = config.NewServiceConfigs()
|
||||||
|
projectWithEmptyNetwork.ServiceConfigs.Add("foo", &config.ServiceConfig{
|
||||||
|
Networks: &yaml.Networks{},
|
||||||
|
})
|
||||||
|
|
||||||
|
projectWithDefaultNetwork := project.NewProject(&project.Context{}, nil, nil)
|
||||||
|
projectWithDefaultNetwork.ServiceConfigs = config.NewServiceConfigs()
|
||||||
|
|
||||||
|
projectWithDefaultNetwork.ServiceConfigs.Add("foo", &config.ServiceConfig{
|
||||||
|
Networks: &yaml.Networks{
|
||||||
|
Networks: []*yaml.Network{
|
||||||
|
&yaml.Network{
|
||||||
|
Name: "default",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
// define all test cases for checkUnsupportedKey function
|
||||||
|
testCases := map[string]struct {
|
||||||
|
composeProject *project.Project
|
||||||
|
expectedUnsupportedKeys []string
|
||||||
|
}{
|
||||||
|
"With Networks (service and root level)": {
|
||||||
|
projectWithNetworks,
|
||||||
|
[]string{"root level networks", "root level volumes", "hostname", "networks"},
|
||||||
|
},
|
||||||
|
"Empty Networks on Service level": {
|
||||||
|
projectWithEmptyNetwork,
|
||||||
|
[]string{"networks"},
|
||||||
|
},
|
||||||
|
"Default root level Network": {
|
||||||
|
projectWithDefaultNetwork,
|
||||||
|
[]string(nil),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for name, test := range testCases {
|
||||||
|
t.Log("Test case:", name)
|
||||||
|
keys := checkUnsupportedKey(test.composeProject)
|
||||||
|
if !reflect.DeepEqual(keys, test.expectedUnsupportedKeys) {
|
||||||
|
t.Errorf("ERROR: Expecting unsupported keys: ['%s']. Got: ['%s']", strings.Join(test.expectedUnsupportedKeys, "', '"), strings.Join(keys, "', '"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|||||||
@ -27,6 +27,7 @@ import (
|
|||||||
|
|
||||||
type Loader interface {
|
type Loader interface {
|
||||||
LoadFile(file string) kobject.KomposeObject
|
LoadFile(file string) kobject.KomposeObject
|
||||||
|
///Name() string
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetLoader returns loader for given format
|
// GetLoader returns loader for given format
|
||||||
|
|||||||
@ -18,11 +18,13 @@ package kubernetes
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"reflect"
|
||||||
"sort"
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/Sirupsen/logrus"
|
"github.com/Sirupsen/logrus"
|
||||||
|
"github.com/fatih/structs"
|
||||||
"github.com/kubernetes-incubator/kompose/pkg/kobject"
|
"github.com/kubernetes-incubator/kompose/pkg/kobject"
|
||||||
"github.com/kubernetes-incubator/kompose/pkg/transformer"
|
"github.com/kubernetes-incubator/kompose/pkg/transformer"
|
||||||
deployapi "github.com/openshift/origin/pkg/deploy/api"
|
deployapi "github.com/openshift/origin/pkg/deploy/api"
|
||||||
@ -52,6 +54,52 @@ type Kubernetes struct {
|
|||||||
// used when undeploying resources from kubernetes
|
// used when undeploying resources from kubernetes
|
||||||
const TIMEOUT = 300
|
const TIMEOUT = 300
|
||||||
|
|
||||||
|
// list of all unsupported keys for this transformer
|
||||||
|
// Keys are names of variables in kobject struct.
|
||||||
|
// this is map to make searching for keys easier
|
||||||
|
// to make sure that unsupported key is not going to be reported twice
|
||||||
|
// by keeping record if already saw this key in another service
|
||||||
|
var unsupportedKey = map[string]bool{
|
||||||
|
"Build": false,
|
||||||
|
}
|
||||||
|
|
||||||
|
// checkUnsupportedKey checks if given komposeObject contains
|
||||||
|
// keys that are not supported by this tranfomer.
|
||||||
|
// list of all unsupported keys are stored in unsupportedKey variable
|
||||||
|
// returns list of TODO: ....
|
||||||
|
func (k *Kubernetes) CheckUnsupportedKey(komposeObject *kobject.KomposeObject, unsupportedKey map[string]bool) []string {
|
||||||
|
// collect all keys found in project
|
||||||
|
var keysFound []string
|
||||||
|
|
||||||
|
for _, serviceConfig := range komposeObject.ServiceConfigs {
|
||||||
|
// this reflection is used in check for empty arrays
|
||||||
|
val := reflect.ValueOf(serviceConfig)
|
||||||
|
s := structs.New(serviceConfig)
|
||||||
|
|
||||||
|
for _, f := range s.Fields() {
|
||||||
|
// Check if given key is among unsupported keys, and skip it if we already saw this key
|
||||||
|
if alreadySaw, ok := unsupportedKey[f.Name()]; ok && !alreadySaw {
|
||||||
|
|
||||||
|
if f.IsExported() && !f.IsZero() {
|
||||||
|
// IsZero returns false for empty array/slice ([])
|
||||||
|
// this check if field is Slice, and then it checks its size
|
||||||
|
if field := val.FieldByName(f.Name()); field.Kind() == reflect.Slice {
|
||||||
|
if field.Len() == 0 {
|
||||||
|
// array is empty it doesn't matter if it is in unsupportedKey or not
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//get tag from kobject service configure
|
||||||
|
tag := f.Tag(komposeObject.LoadedFrom)
|
||||||
|
keysFound = append(keysFound, tag)
|
||||||
|
unsupportedKey[f.Name()] = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return keysFound
|
||||||
|
}
|
||||||
|
|
||||||
// Init RC object
|
// Init RC object
|
||||||
func (k *Kubernetes) InitRC(name string, service kobject.ServiceConfig, replicas int) *api.ReplicationController {
|
func (k *Kubernetes) InitRC(name string, service kobject.ServiceConfig, replicas int) *api.ReplicationController {
|
||||||
rc := &api.ReplicationController{
|
rc := &api.ReplicationController{
|
||||||
@ -351,6 +399,12 @@ func (k *Kubernetes) InitPod(name string, service kobject.ServiceConfig) *api.Po
|
|||||||
// Transform maps komposeObject to k8s objects
|
// Transform maps komposeObject to k8s objects
|
||||||
// returns object that are already sorted in the way that Services are first
|
// returns object that are already sorted in the way that Services are first
|
||||||
func (k *Kubernetes) Transform(komposeObject kobject.KomposeObject, opt kobject.ConvertOptions) []runtime.Object {
|
func (k *Kubernetes) Transform(komposeObject kobject.KomposeObject, opt kobject.ConvertOptions) []runtime.Object {
|
||||||
|
|
||||||
|
noSupKeys := k.CheckUnsupportedKey(&komposeObject, unsupportedKey)
|
||||||
|
for _, keyName := range noSupKeys {
|
||||||
|
logrus.Warningf("Kubernetes provider doesn't support %s key - ignoring", keyName)
|
||||||
|
}
|
||||||
|
|
||||||
// this will hold all the converted data
|
// this will hold all the converted data
|
||||||
var allobjects []runtime.Object
|
var allobjects []runtime.Object
|
||||||
|
|
||||||
|
|||||||
@ -18,6 +18,8 @@ package kubernetes
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"reflect"
|
||||||
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
deployapi "github.com/openshift/origin/pkg/deploy/api"
|
deployapi "github.com/openshift/origin/pkg/deploy/api"
|
||||||
@ -353,3 +355,36 @@ func TestConvertRestartOptions(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestUnsupportedKeys test checkUnsupportedKey function
|
||||||
|
func TestUnsupportedKeys(t *testing.T) {
|
||||||
|
|
||||||
|
kobjectWithBuild := newKomposeObject()
|
||||||
|
kobjectWithBuild.LoadedFrom = "compose"
|
||||||
|
serviceConfig := kobjectWithBuild.ServiceConfigs["app"]
|
||||||
|
serviceConfig.Build = "./asdf"
|
||||||
|
serviceConfig.Network = []string{}
|
||||||
|
kobjectWithBuild.ServiceConfigs = map[string]kobject.ServiceConfig{"app": serviceConfig}
|
||||||
|
|
||||||
|
// define all test cases for checkUnsupportedKey function
|
||||||
|
testCases := map[string]struct {
|
||||||
|
bundleFile kobject.KomposeObject
|
||||||
|
expectedUnsupportedKeys []string
|
||||||
|
}{
|
||||||
|
"Full Bundle": {
|
||||||
|
kobjectWithBuild,
|
||||||
|
[]string{"build"},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
k := Kubernetes{}
|
||||||
|
|
||||||
|
for name, test := range testCases {
|
||||||
|
t.Log("Test case:", name)
|
||||||
|
keys := k.CheckUnsupportedKey(&test.bundleFile, unsupportedKey)
|
||||||
|
if !reflect.DeepEqual(keys, test.expectedUnsupportedKeys) {
|
||||||
|
t.Errorf("ERROR: Expecting unsupported keys: ['%s']. Got: ['%s']", strings.Join(test.expectedUnsupportedKeys, "', '"), strings.Join(keys, "', '"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|||||||
@ -33,11 +33,12 @@ import (
|
|||||||
oclient "github.com/openshift/origin/pkg/client"
|
oclient "github.com/openshift/origin/pkg/client"
|
||||||
ocliconfig "github.com/openshift/origin/pkg/cmd/cli/config"
|
ocliconfig "github.com/openshift/origin/pkg/cmd/cli/config"
|
||||||
|
|
||||||
|
"time"
|
||||||
|
|
||||||
deployapi "github.com/openshift/origin/pkg/deploy/api"
|
deployapi "github.com/openshift/origin/pkg/deploy/api"
|
||||||
deploymentconfigreaper "github.com/openshift/origin/pkg/deploy/cmd"
|
deploymentconfigreaper "github.com/openshift/origin/pkg/deploy/cmd"
|
||||||
imageapi "github.com/openshift/origin/pkg/image/api"
|
imageapi "github.com/openshift/origin/pkg/image/api"
|
||||||
"k8s.io/kubernetes/pkg/kubectl"
|
"k8s.io/kubernetes/pkg/kubectl"
|
||||||
"time"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type OpenShift struct {
|
type OpenShift struct {
|
||||||
@ -51,6 +52,13 @@ type OpenShift struct {
|
|||||||
// used when undeploying resources from OpenShift
|
// used when undeploying resources from OpenShift
|
||||||
const TIMEOUT = 300
|
const TIMEOUT = 300
|
||||||
|
|
||||||
|
// list of all unsupported keys for this transformer
|
||||||
|
// Keys are names of variables in kobject struct.
|
||||||
|
// this is map to make searching for keys easier
|
||||||
|
// to make sure that unsupported key is not going to be reported twice
|
||||||
|
// by keeping record if already saw this key in another service
|
||||||
|
var unsupportedKey = map[string]bool{}
|
||||||
|
|
||||||
// getImageTag get tag name from image name
|
// getImageTag get tag name from image name
|
||||||
// if no tag is specified return 'latest'
|
// if no tag is specified return 'latest'
|
||||||
func getImageTag(image string) string {
|
func getImageTag(image string) string {
|
||||||
@ -151,6 +159,10 @@ func (o *OpenShift) initDeploymentConfig(name string, service kobject.ServiceCon
|
|||||||
// Transform maps komposeObject to openshift objects
|
// Transform maps komposeObject to openshift objects
|
||||||
// returns objects that are already sorted in the way that Services are first
|
// returns objects that are already sorted in the way that Services are first
|
||||||
func (o *OpenShift) Transform(komposeObject kobject.KomposeObject, opt kobject.ConvertOptions) []runtime.Object {
|
func (o *OpenShift) Transform(komposeObject kobject.KomposeObject, opt kobject.ConvertOptions) []runtime.Object {
|
||||||
|
noSupKeys := o.Kubernetes.CheckUnsupportedKey(&komposeObject, unsupportedKey)
|
||||||
|
for _, keyName := range noSupKeys {
|
||||||
|
logrus.Warningf("OpenShift provider doesn't support %s key - ignoring", keyName)
|
||||||
|
}
|
||||||
// this will hold all the converted data
|
// this will hold all the converted data
|
||||||
var allobjects []runtime.Object
|
var allobjects []runtime.Object
|
||||||
|
|
||||||
|
|||||||
@ -26,9 +26,9 @@ convert::expect_failure "kompose -f $KOMPOSE_ROOT/script/test/fixtures/etherpad/
|
|||||||
convert::expect_warning "kompose -f $KOMPOSE_ROOT/script/test/fixtures/etherpad/docker-compose-no-ports.yml convert --stdout" "Service cannot be created because of missing port."
|
convert::expect_warning "kompose -f $KOMPOSE_ROOT/script/test/fixtures/etherpad/docker-compose-no-ports.yml convert --stdout" "Service cannot be created because of missing port."
|
||||||
export $(cat $KOMPOSE_ROOT/script/test/fixtures/etherpad/envs)
|
export $(cat $KOMPOSE_ROOT/script/test/fixtures/etherpad/envs)
|
||||||
# kubernetes test
|
# kubernetes test
|
||||||
convert::expect_success_and_warning "kompose -f $KOMPOSE_ROOT/script/test/fixtures/etherpad/docker-compose.yml convert --stdout" "$KOMPOSE_ROOT/script/test/fixtures/etherpad/output-k8s.json" "Unsupported key depends_on - ignoring"
|
convert::expect_success_and_warning "kompose -f $KOMPOSE_ROOT/script/test/fixtures/etherpad/docker-compose.yml convert --stdout" "$KOMPOSE_ROOT/script/test/fixtures/etherpad/output-k8s.json" "Unsupported depends_on key - ignoring"
|
||||||
# openshift test
|
# openshift test
|
||||||
convert::expect_success_and_warning "kompose --provider=openshift -f $KOMPOSE_ROOT/script/test/fixtures/etherpad/docker-compose.yml convert --stdout" "$KOMPOSE_ROOT/script/test/fixtures/etherpad/output-os.json" "Unsupported key depends_on - ignoring"
|
convert::expect_success_and_warning "kompose --provider=openshift -f $KOMPOSE_ROOT/script/test/fixtures/etherpad/docker-compose.yml convert --stdout" "$KOMPOSE_ROOT/script/test/fixtures/etherpad/output-os.json" "Unsupported depends_on key - ignoring"
|
||||||
unset $(cat $KOMPOSE_ROOT/script/test/fixtures/etherpad/envs | cut -d'=' -f1)
|
unset $(cat $KOMPOSE_ROOT/script/test/fixtures/etherpad/envs | cut -d'=' -f1)
|
||||||
|
|
||||||
######
|
######
|
||||||
@ -44,10 +44,9 @@ unset $(cat $KOMPOSE_ROOT/script/test/fixtures/gitlab/envs | cut -d'=' -f1)
|
|||||||
######
|
######
|
||||||
# Tests related to docker-compose file in /script/test/fixtures/ngnix-node-redis
|
# Tests related to docker-compose file in /script/test/fixtures/ngnix-node-redis
|
||||||
# kubernetes test
|
# kubernetes test
|
||||||
convert::expect_success_and_warning "kompose -f $KOMPOSE_ROOT/script/test/fixtures/ngnix-node-redis/docker-compose.yml convert --stdout" "$KOMPOSE_ROOT/script/test/fixtures/ngnix-node-redis/output-k8s.json" "Unsupported key build - ignoring"
|
convert::expect_success_and_warning "kompose -f $KOMPOSE_ROOT/script/test/fixtures/ngnix-node-redis/docker-compose.yml convert --stdout" "$KOMPOSE_ROOT/script/test/fixtures/ngnix-node-redis/output-k8s.json" "Kubernetes provider doesn't support build key - ignoring"
|
||||||
# openshift test
|
# openshift test
|
||||||
convert::expect_success_and_warning "kompose --provider=openshift -f $KOMPOSE_ROOT/script/test/fixtures/ngnix-node-redis/docker-compose.yml convert --stdout" "$KOMPOSE_ROOT/script/test/fixtures/ngnix-node-redis/output-os.json" "Unsupported key build - ignoring"
|
convert::expect_success "kompose --provider=openshift -f $KOMPOSE_ROOT/script/test/fixtures/ngnix-node-redis/docker-compose.yml convert --stdout" "$KOMPOSE_ROOT/script/test/fixtures/ngnix-node-redis/output-os.json"
|
||||||
|
|
||||||
|
|
||||||
######
|
######
|
||||||
# Tests related to docker-compose file in /script/test/fixtures/entrypoint-command
|
# Tests related to docker-compose file in /script/test/fixtures/entrypoint-command
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user