forked from LaconicNetwork/kompose
Network Key Translation Feature and test cases (#1195)
This commit is contained in:
1 parent
c13d50ee17
commit
ac2b852955
18 files changed
+606
-40
No files matched your search
@@ -30,7 +30,7 @@ import (
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// StdinData is data bytes read from stdin
|
||||
//StdinData is data bytes read from stdin
|
||||
var StdinData []byte
|
||||
|
||||
// Compose is docker compose file loader, implements Loader interface
|
||||
@@ -72,20 +72,16 @@ func checkUnsupportedKey(composeProject *project.Project) []string {
|
||||
"Ulimits": false,
|
||||
"Net": false,
|
||||
"Sysctls": false,
|
||||
"Networks": false, // there are special checks for Network in checkUnsupportedKey function
|
||||
"Links": false,
|
||||
//"Networks": false, // We shall be spporting network now. There are special checks for Network in checkUnsupportedKey function
|
||||
"Links": false,
|
||||
}
|
||||
|
||||
// collect all keys found in project
|
||||
var keysFound []string
|
||||
|
||||
// Root level keys are not yet supported
|
||||
// Root level keys are not yet supported except Network
|
||||
// Check to see if the default network is available and length is only equal to one.
|
||||
// Else, warn the user that root level networks are not supported (yet)
|
||||
if _, ok := composeProject.NetworkConfigs["default"]; ok && len(composeProject.NetworkConfigs) == 1 {
|
||||
log.Debug("Default network found")
|
||||
} else if len(composeProject.NetworkConfigs) > 0 {
|
||||
keysFound = append(keysFound, "root level networks")
|
||||
}
|
||||
|
||||
// Root level volumes are not yet supported
|
||||
@@ -117,8 +113,6 @@ func checkUnsupportedKey(composeProject *project.Project) []string {
|
||||
if len(serviceConfig.Networks.Networks) == 1 && serviceConfig.Networks.Networks[0].Name == "default" {
|
||||
// this is empty Network definition, skip it
|
||||
continue
|
||||
} else {
|
||||
yamlTagName = "networks"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -260,7 +260,7 @@ func TestUnsupportedKeys(t *testing.T) {
|
||||
Ports: []string{}, // test empty array
|
||||
Networks: &yaml.Networks{
|
||||
Networks: []*yaml.Network{
|
||||
&yaml.Network{
|
||||
{
|
||||
Name: "net1",
|
||||
},
|
||||
},
|
||||
@@ -275,19 +275,19 @@ func TestUnsupportedKeys(t *testing.T) {
|
||||
Ports: []string{}, // test empty array
|
||||
Networks: &yaml.Networks{
|
||||
Networks: []*yaml.Network{
|
||||
&yaml.Network{
|
||||
{
|
||||
Name: "net1",
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
projectWithNetworks.VolumeConfigs = map[string]*config.VolumeConfig{
|
||||
"foo": &config.VolumeConfig{
|
||||
"foo": {
|
||||
Driver: "storage",
|
||||
},
|
||||
}
|
||||
projectWithNetworks.NetworkConfigs = map[string]*config.NetworkConfig{
|
||||
"foo": &config.NetworkConfig{
|
||||
"foo": {
|
||||
Driver: "bridge",
|
||||
},
|
||||
}
|
||||
@@ -304,7 +304,7 @@ func TestUnsupportedKeys(t *testing.T) {
|
||||
projectWithDefaultNetwork.ServiceConfigs.Add("foo", &config.ServiceConfig{
|
||||
Networks: &yaml.Networks{
|
||||
Networks: []*yaml.Network{
|
||||
&yaml.Network{
|
||||
{
|
||||
Name: "default",
|
||||
},
|
||||
},
|
||||
@@ -318,11 +318,8 @@ func TestUnsupportedKeys(t *testing.T) {
|
||||
}{
|
||||
"With Networks (service and root level)": {
|
||||
projectWithNetworks,
|
||||
[]string{"root level networks", "root level volumes", "networks"},
|
||||
},
|
||||
"Empty Networks on Service level": {
|
||||
projectWithEmptyNetwork,
|
||||
[]string{"networks"},
|
||||
//root level network and network are now supported"
|
||||
[]string{"root level volumes"},
|
||||
},
|
||||
"Default root level Network": {
|
||||
projectWithDefaultNetwork,
|
||||
@@ -359,6 +356,29 @@ func TestNormalizeServiceNames(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestNormalizeNetworkNames(t *testing.T) {
|
||||
testCases := []struct {
|
||||
composeNetworkName string
|
||||
normalizedNetworkName string
|
||||
}{
|
||||
{"foo_bar", "foobar"},
|
||||
{"foo", "foo"},
|
||||
{"FOO", "foo"},
|
||||
{"foo.bar", "foo.bar"},
|
||||
//{"", ""},
|
||||
}
|
||||
|
||||
for _, testCase := range testCases {
|
||||
returnValue, err := normalizeNetworkNames(testCase.composeNetworkName)
|
||||
if err != nil {
|
||||
t.Log("Unxpected error, got ", err)
|
||||
}
|
||||
if returnValue != testCase.normalizedNetworkName {
|
||||
t.Logf("Expected %q, got %q", testCase.normalizedNetworkName, returnValue)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestCheckLabelsPorts(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
|
||||
@@ -131,6 +131,17 @@ func normalizeVolumes(svcName string) string {
|
||||
return strings.Replace(svcName, "_", "-", -1)
|
||||
}
|
||||
|
||||
func normalizeNetworkNames(netName string) (string, error) {
|
||||
netval := strings.ToLower(netName)
|
||||
regString := ("[^A-Za-z0-9.-]+")
|
||||
reg, err := regexp.Compile(regString)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
netval = reg.ReplaceAllString(netval, "")
|
||||
return netval, nil
|
||||
}
|
||||
|
||||
// ReadFile read data from file or stdin
|
||||
func ReadFile(fileName string) ([]byte, error) {
|
||||
if fileName == "-" {
|
||||
|
||||
@@ -24,8 +24,6 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
|
||||
"github.com/docker/libcompose/config"
|
||||
"github.com/docker/libcompose/lookup"
|
||||
"github.com/docker/libcompose/project"
|
||||
@@ -33,6 +31,7 @@ import (
|
||||
"github.com/kubernetes/kompose/pkg/transformer"
|
||||
"github.com/pkg/errors"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
)
|
||||
|
||||
// Parse Docker Compose with libcompose (only supports v1 and v2). Eventually we will
|
||||
@@ -279,6 +278,15 @@ func libComposeToKomposeMapping(composeObject *project.Project) (kobject.Kompose
|
||||
serviceConfig.TmpFs = composeServiceConfig.Tmpfs
|
||||
serviceConfig.StopGracePeriod = composeServiceConfig.StopGracePeriod
|
||||
|
||||
if composeServiceConfig.Networks != nil {
|
||||
if len(composeServiceConfig.Networks.Networks) > 0 {
|
||||
for _, value := range composeServiceConfig.Networks.Networks {
|
||||
if value.Name != "default" {
|
||||
serviceConfig.Network = append(serviceConfig.Network, value.RealName)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Get GroupAdd, group should be mentioned in gid format but not the group name
|
||||
groupAdd, err := getGroupAdd(composeServiceConfig.GroupAdd)
|
||||
if err != nil {
|
||||
|
||||
@@ -281,6 +281,24 @@ func dockerComposeToKomposeMapping(composeObject *types.Config) (kobject.Kompose
|
||||
serviceConfig.HostName = composeServiceConfig.Hostname
|
||||
serviceConfig.DomainName = composeServiceConfig.DomainName
|
||||
|
||||
//Adding network key related info
|
||||
if len(composeServiceConfig.Networks) == 0 {
|
||||
if defaultNetwork, ok := composeObject.Networks["default"]; ok {
|
||||
serviceConfig.Network = append(serviceConfig.Network, defaultNetwork.Name)
|
||||
}
|
||||
} else {
|
||||
var alias = ""
|
||||
for key := range composeServiceConfig.Networks {
|
||||
alias = key
|
||||
netName := composeObject.Networks[alias].Name
|
||||
// if Network Name Field is empty in the docker-compose definition
|
||||
// we will use the alias name defined in service config file
|
||||
if netName == "" {
|
||||
netName = alias
|
||||
}
|
||||
serviceConfig.Network = append(serviceConfig.Network, netName)
|
||||
}
|
||||
}
|
||||
//
|
||||
// Deploy keys
|
||||
//
|
||||
|
||||
@@ -501,7 +501,7 @@ func (k *Kubernetes) UpdateKubernetesObjects(name string, service kobject.Servic
|
||||
template.Spec.SecurityContext = podSecurityContext
|
||||
}
|
||||
template.Spec.Containers[0].Ports = ports
|
||||
template.ObjectMeta.Labels = transformer.ConfigLabels(name)
|
||||
template.ObjectMeta.Labels = transformer.ConfigLabelsWithNetwork(name, service.Network)
|
||||
|
||||
// Configure the image pull policy
|
||||
switch service.ImagePullPolicy {
|
||||
|
||||
@@ -49,11 +49,12 @@ import (
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"path/filepath"
|
||||
|
||||
"github.com/kubernetes/kompose/pkg/loader/compose"
|
||||
"github.com/pkg/errors"
|
||||
"k8s.io/kubernetes/pkg/api/meta"
|
||||
"k8s.io/kubernetes/pkg/labels"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
// Kubernetes implements Transformer interface and represents Kubernetes transformer
|
||||
@@ -303,14 +304,18 @@ func (k *Kubernetes) InitD(name string, service kobject.ServiceConfig, replicas
|
||||
},
|
||||
Spec: extensions.DeploymentSpec{
|
||||
Replicas: int32(replicas),
|
||||
|
||||
Template: api.PodTemplateSpec{
|
||||
ObjectMeta: api.ObjectMeta{
|
||||
//Labels: transformer.ConfigLabels(name),
|
||||
Annotations: transformer.ConfigAnnotations(service),
|
||||
},
|
||||
Spec: podSpec,
|
||||
},
|
||||
},
|
||||
}
|
||||
dc.Spec.Template.Labels = transformer.ConfigLabels(name)
|
||||
|
||||
return dc
|
||||
}
|
||||
|
||||
@@ -823,6 +828,36 @@ func (k *Kubernetes) InitPod(name string, service kobject.ServiceConfig) *api.Po
|
||||
return &pod
|
||||
}
|
||||
|
||||
// CreateNetworkPolicy initializes Network policy
|
||||
func (k *Kubernetes) CreateNetworkPolicy(name string, networkName string) (*extensions.NetworkPolicy, error) {
|
||||
|
||||
str := "true"
|
||||
np := &extensions.NetworkPolicy{
|
||||
TypeMeta: unversioned.TypeMeta{
|
||||
Kind: "NetworkPolicy",
|
||||
APIVersion: "extensions/v1beta1",
|
||||
},
|
||||
ObjectMeta: api.ObjectMeta{
|
||||
Name: networkName,
|
||||
//Labels: transformer.ConfigLabels(name)(name),
|
||||
},
|
||||
Spec: extensions.NetworkPolicySpec{
|
||||
PodSelector: unversioned.LabelSelector{
|
||||
MatchLabels: map[string]string{"io.kompose.network/" + networkName: str},
|
||||
},
|
||||
Ingress: []extensions.NetworkPolicyIngressRule{{
|
||||
From: []extensions.NetworkPolicyPeer{{
|
||||
PodSelector: &unversioned.LabelSelector{
|
||||
MatchLabels: map[string]string{"io.kompose.network/" + networkName: str},
|
||||
},
|
||||
}},
|
||||
}},
|
||||
},
|
||||
}
|
||||
|
||||
return np, nil
|
||||
}
|
||||
|
||||
// Transform maps komposeObject to k8s objects
|
||||
// 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, error) {
|
||||
@@ -906,11 +941,29 @@ func (k *Kubernetes) Transform(komposeObject kobject.KomposeObject, opt kobject.
|
||||
return nil, errors.Wrap(err, "Error transforming Kubernetes objects")
|
||||
}
|
||||
|
||||
if len(service.Network) > 0 {
|
||||
|
||||
for _, net := range service.Network {
|
||||
|
||||
log.Infof("Network %s is detected at Source, shall be converted to equivalent NetworkPolicy at Destination", net)
|
||||
np, err := k.CreateNetworkPolicy(name, net)
|
||||
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "Unable to create Network Policy for network %v for service %v", net, name)
|
||||
}
|
||||
objects = append(objects, np)
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
allobjects = append(allobjects, objects...)
|
||||
|
||||
}
|
||||
|
||||
// sort all object so Services are first
|
||||
k.SortServicesFirst(&allobjects)
|
||||
|
||||
return allobjects, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@ func newServiceConfig() kobject.ServiceConfig {
|
||||
WorkingDir: "dir",
|
||||
Args: []string{"arg1", "arg2"},
|
||||
VolList: []string{"/tmp/volume"},
|
||||
Network: []string{"network1", "network2"}, // not supported
|
||||
Network: []string{"network1", "network2"}, // supported
|
||||
Labels: nil,
|
||||
Annotations: map[string]string{"abc": "def"},
|
||||
CPUQuota: 1, // not supported
|
||||
@@ -278,15 +278,15 @@ func TestKomposeConvert(t *testing.T) {
|
||||
opt kobject.ConvertOptions
|
||||
expectedNumObjs int
|
||||
}{
|
||||
// objects generated are deployment, service and pvc
|
||||
"Convert to Deployments (D)": {newKomposeObject(), kobject.ConvertOptions{CreateD: true, Replicas: replicas, IsReplicaSetFlag: true}, 3},
|
||||
"Convert to Deployments (D) with v3 replicas": {newKomposeObject(), kobject.ConvertOptions{CreateD: true}, 3},
|
||||
"Convert to DaemonSets (DS)": {newKomposeObject(), kobject.ConvertOptions{CreateDS: true}, 3},
|
||||
"Convert to ReplicationController(RC)": {newKomposeObject(), kobject.ConvertOptions{CreateRC: true, Replicas: replicas, IsReplicaSetFlag: true}, 3},
|
||||
"Convert to ReplicationController(RC) with v3 replicas ": {newKomposeObject(), kobject.ConvertOptions{CreateRC: true}, 3},
|
||||
// objects generated are deployment, service nework policies (2) and pvc
|
||||
"Convert to Deployments (D)": {newKomposeObject(), kobject.ConvertOptions{CreateD: true, Replicas: replicas, IsReplicaSetFlag: true}, 5},
|
||||
"Convert to Deployments (D) with v3 replicas": {newKomposeObject(), kobject.ConvertOptions{CreateD: true}, 5},
|
||||
"Convert to DaemonSets (DS)": {newKomposeObject(), kobject.ConvertOptions{CreateDS: true}, 5},
|
||||
"Convert to ReplicationController(RC)": {newKomposeObject(), kobject.ConvertOptions{CreateRC: true, Replicas: replicas, IsReplicaSetFlag: true}, 5},
|
||||
"Convert to ReplicationController(RC) with v3 replicas ": {newKomposeObject(), kobject.ConvertOptions{CreateRC: true}, 5},
|
||||
// objects generated are deployment, daemonset, ReplicationController, service and pvc
|
||||
"Convert to D, DS, and RC": {newKomposeObject(), kobject.ConvertOptions{CreateD: true, CreateDS: true, CreateRC: true, Replicas: replicas, IsReplicaSetFlag: true}, 5},
|
||||
"Convert to D, DS, and RC with v3 replicas": {newKomposeObject(), kobject.ConvertOptions{CreateD: true, CreateDS: true, CreateRC: true}, 5},
|
||||
"Convert to D, DS, and RC": {newKomposeObject(), kobject.ConvertOptions{CreateD: true, CreateDS: true, CreateRC: true, Replicas: replicas, IsReplicaSetFlag: true}, 7},
|
||||
"Convert to D, DS, and RC with v3 replicas": {newKomposeObject(), kobject.ConvertOptions{CreateD: true, CreateDS: true, CreateRC: true}, 7},
|
||||
// TODO: add more tests
|
||||
}
|
||||
|
||||
@@ -306,6 +306,7 @@ func TestKomposeConvert(t *testing.T) {
|
||||
name := "app"
|
||||
labels := transformer.ConfigLabels(name)
|
||||
config := test.komposeObject.ServiceConfigs[name]
|
||||
labelsWithNetwork := transformer.ConfigLabelsWithNetwork(name, config.Network)
|
||||
// Check results
|
||||
for _, obj := range objs {
|
||||
if svc, ok := obj.(*api.Service); ok {
|
||||
@@ -319,7 +320,7 @@ func TestKomposeConvert(t *testing.T) {
|
||||
}
|
||||
if test.opt.CreateD {
|
||||
if d, ok := obj.(*extensions.Deployment); ok {
|
||||
if err := checkPodTemplate(config, d.Spec.Template, labels); err != nil {
|
||||
if err := checkPodTemplate(config, d.Spec.Template, labelsWithNetwork); err != nil {
|
||||
t.Errorf("%v", err)
|
||||
}
|
||||
if err := checkMeta(config, d.ObjectMeta, name, true); err != nil {
|
||||
@@ -345,7 +346,7 @@ func TestKomposeConvert(t *testing.T) {
|
||||
}
|
||||
if test.opt.CreateDS {
|
||||
if ds, ok := obj.(*extensions.DaemonSet); ok {
|
||||
if err := checkPodTemplate(config, ds.Spec.Template, labels); err != nil {
|
||||
if err := checkPodTemplate(config, ds.Spec.Template, labelsWithNetwork); err != nil {
|
||||
t.Errorf("%v", err)
|
||||
}
|
||||
if err := checkMeta(config, ds.ObjectMeta, name, true); err != nil {
|
||||
@@ -359,7 +360,7 @@ func TestKomposeConvert(t *testing.T) {
|
||||
}
|
||||
if test.opt.CreateRC {
|
||||
if rc, ok := obj.(*api.ReplicationController); ok {
|
||||
if err := checkPodTemplate(config, *rc.Spec.Template, labels); err != nil {
|
||||
if err := checkPodTemplate(config, *rc.Spec.Template, labelsWithNetwork); err != nil {
|
||||
t.Errorf("%v", err)
|
||||
}
|
||||
if err := checkMeta(config, rc.ObjectMeta, name, true); err != nil {
|
||||
@@ -386,7 +387,7 @@ func TestKomposeConvert(t *testing.T) {
|
||||
// TODO: k8s & openshift transformer is now separated; either separate the test or combine the transformer
|
||||
if test.opt.CreateDeploymentConfig {
|
||||
if dc, ok := obj.(*deployapi.DeploymentConfig); ok {
|
||||
if err := checkPodTemplate(config, *dc.Spec.Template, labels); err != nil {
|
||||
if err := checkPodTemplate(config, *dc.Spec.Template, labelsWithNetwork); err != nil {
|
||||
t.Errorf("%v", err)
|
||||
}
|
||||
if err := checkMeta(config, dc.ObjectMeta, name, true); err != nil {
|
||||
|
||||
@@ -107,13 +107,27 @@ func isPath(substring string) bool {
|
||||
return strings.Contains(substring, "/") || substring == "."
|
||||
}
|
||||
|
||||
// ConfigLabels configures label
|
||||
// ConfigLabels configures label name alone
|
||||
func ConfigLabels(name string) map[string]string {
|
||||
return map[string]string{Selector: name}
|
||||
}
|
||||
|
||||
// ConfigLabels configures label and add Network Information in labels
|
||||
func ConfigLabelsWithNetwork(name string, net []string) map[string]string {
|
||||
|
||||
labels := map[string]string{}
|
||||
labels[Selector] = name
|
||||
|
||||
for _, n := range net {
|
||||
labels["io.kompose.network/"+n] = "true"
|
||||
}
|
||||
return labels
|
||||
//return map[string]string{Selector: name, "Network": net}
|
||||
}
|
||||
|
||||
// ConfigAnnotations configures annotations
|
||||
func ConfigAnnotations(service kobject.ServiceConfig) map[string]string {
|
||||
|
||||
annotations := map[string]string{}
|
||||
for key, value := range service.Annotations {
|
||||
annotations[key] = value
|
||||
|
||||
Reference in new issue
Block a user