From e4f9b59b4dbbf645edb5963551b791f6dba5a64b Mon Sep 17 00:00:00 2001 From: Tomas Kral Date: Mon, 12 Dec 2016 16:26:36 +0100 Subject: [PATCH] Separate unsupported key check for every loader --- pkg/kobject/kobject.go | 97 +--------------------------- pkg/loader/bundle/bundle.go | 56 +++++++++++++++- pkg/loader/compose/compose.go | 117 +++++++++++++++++++++++++++++----- pkg/loader/loader.go | 1 + 4 files changed, 159 insertions(+), 112 deletions(-) diff --git a/pkg/kobject/kobject.go b/pkg/kobject/kobject.go index 1d5554ae..a52506b4 100644 --- a/pkg/kobject/kobject.go +++ b/pkg/kobject/kobject.go @@ -16,89 +16,7 @@ limitations under the License. package kobject -import ( - "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", -} +import "k8s.io/kubernetes/pkg/api" // KomposeObject holds the generic struct of Kompose transformation type KomposeObject struct { @@ -144,6 +62,7 @@ type ServiceConfig struct { User string VolumesFrom []string ServiceType string + Build string } // EnvVar holds the environment variable struct of a container @@ -158,15 +77,3 @@ type Ports struct { ContainerPort int32 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()]++ - } - } - } -} diff --git a/pkg/loader/bundle/bundle.go b/pkg/loader/bundle/bundle.go index 2459f563..3a7f318e 100644 --- a/pkg/loader/bundle/bundle.go +++ b/pkg/loader/bundle/bundle.go @@ -21,11 +21,13 @@ import ( "fmt" "io" "io/ioutil" + "reflect" "strings" "k8s.io/kubernetes/pkg/api" "github.com/Sirupsen/logrus" + "github.com/fatih/structs" "github.com/kubernetes-incubator/kompose/pkg/kobject" ) @@ -57,6 +59,53 @@ type Port struct { 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 + // also counts how many times was given key found in service + // to make sure that we show warning only once for every key + var unsupportedKey = map[string]int{ + "Networks": 0, + } + + // 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() { + 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 metter if it is in unsupportedKey or not + continue + } + } + if counter, ok := unsupportedKey[f.Name()]; ok { + if counter == 0 { + keysFound = append(keysFound, jsonTagName) + } + unsupportedKey[f.Name()]++ + } + } + } + } + return keysFound +} + // load image from dab file func loadImage(service Service) (string, string) { character := "@" @@ -129,6 +178,7 @@ func loadPorts(service Service) ([]kobject.Ports, string) { func (b *Bundle) LoadFile(file string) kobject.KomposeObject { komposeObject := kobject.KomposeObject{ ServiceConfigs: make(map[string]kobject.ServiceConfig), + LoadedFrom: "bundle", } buf, err := ioutil.ReadFile(file) @@ -141,8 +191,12 @@ func (b *Bundle) LoadFile(file string) kobject.KomposeObject { 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 { - kobject.CheckUnsupportedKey(service) serviceConfig := kobject.ServiceConfig{} serviceConfig.Command = service.Command diff --git a/pkg/loader/compose/compose.go b/pkg/loader/compose/compose.go index c11a7cc1..1db19a97 100644 --- a/pkg/loader/compose/compose.go +++ b/pkg/loader/compose/compose.go @@ -20,6 +20,7 @@ import ( "fmt" "os" "path/filepath" + "reflect" "strconv" "strings" @@ -29,12 +30,107 @@ import ( "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" ) 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 + // also counts how many times was given key found in service + // to make sure that we show warning only once for every key + var unsupportedKey = map[string]int{ + "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, // there are special checks for Network in checkUnsupportedKey function996607 + } + + // 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() { + 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 metter if it is in unsupportedKey or not + continue + } + } + + if counter, ok := unsupportedKey[f.Name()]; ok { + //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" + } + } + if counter == 0 { + keysFound = append(keysFound, yamlTagName) + } + unsupportedKey[f.Name()]++ + } + } + } + } + return keysFound +} + // load environment variables from compose file func loadEnvVars(envars []string) []kobject.EnvVar { envs := []kobject.EnvVar{} @@ -132,6 +228,7 @@ func loadPorts(composePorts []string) ([]kobject.Ports, error) { func (c *Compose) LoadFile(file string) kobject.KomposeObject { komposeObject := kobject.KomposeObject{ ServiceConfigs: make(map[string]kobject.ServiceConfig), + LoadedFrom: "compose", } context := &project.Context{} if file == "" { @@ -168,31 +265,19 @@ func (c *Compose) LoadFile(file string) kobject.KomposeObject { // transform composeObject into komposeObject composeServiceNames := composeObject.ServiceConfigs.Keys() - // volume config and network config are not supported - if len(composeObject.NetworkConfigs) > 0 { - logrus.Warningf("Unsupported network configuration of compose v2 - ignoring") + noSupKeys := checkUnsupportedKey(composeObject) + for _, keyName := range noSupKeys { + 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 { 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.Image = composeServiceConfig.Image serviceConfig.ContainerName = composeServiceConfig.ContainerName serviceConfig.Command = composeServiceConfig.Entrypoint serviceConfig.Args = composeServiceConfig.Command + serviceConfig.Build = composeServiceConfig.Build.Context envs := loadEnvVars(composeServiceConfig.Environment) serviceConfig.Environment = envs diff --git a/pkg/loader/loader.go b/pkg/loader/loader.go index eff70f0e..97a821a5 100644 --- a/pkg/loader/loader.go +++ b/pkg/loader/loader.go @@ -27,6 +27,7 @@ import ( type Loader interface { LoadFile(file string) kobject.KomposeObject + ///Name() string } // GetLoader returns loader for given format