Merge pull request #324 from rtnpro/unsupported-keys-per-provider

Unsupported keys per provider
This commit is contained in:
Suraj Deshmukh 2016-12-21 19:08:42 +05:30 committed by GitHub
commit 48e3ba88cd
10 changed files with 475 additions and 139 deletions

View File

@ -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()]++
}
}
}
}

View File

@ -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

View 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, "', '"))
}
}
}

View File

@ -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

View File

@ -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, "', '"))
}
}
}

View File

@ -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

View File

@ -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

View File

@ -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, "', '"))
}
}
}

View File

@ -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

View File

@ -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