Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix environment variables interpolation #1524

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
65fd64c
fix: update get container name function
Sep 25, 2022
0417d41
fix: remove unecessary print in kubernetes test
Sep 25, 2022
d31b59a
add comments in the tests function
Sep 25, 2022
a54762c
fix: update env variables loading and interpolation
Oct 16, 2022
15e5107
test: add unit test of args interpolation
Oct 16, 2022
550ee6e
Revert "test: add unit test of args interpolation"
Oct 16, 2022
a715520
Revert "Revert "test: add unit test of args interpolation""
Oct 16, 2022
4d2500c
delete unecessary files
Oct 16, 2022
8050b9d
fix: clean branch work
Oct 16, 2022
979c145
fix go formatting
Oct 16, 2022
3bf5146
fix: update get container name function
Sep 25, 2022
e0fd818
fix: remove unecessary print in kubernetes test
Sep 25, 2022
3bdb331
add comments in the tests function
Sep 25, 2022
9e55f8b
fix: update env variables loading and interpolation
Oct 16, 2022
febdb05
test: add unit test of args interpolation
Oct 16, 2022
1516d2d
Revert "test: add unit test of args interpolation"
Oct 16, 2022
dab71a3
Revert "Revert "test: add unit test of args interpolation""
Oct 16, 2022
eb7c5e7
delete unecessary files
Oct 16, 2022
9e9d034
fix: clean branch work
Oct 16, 2022
26a2be1
fix go formatting
Oct 16, 2022
1b1e828
Merge branch 'fix-environment-variables-interpolation' of https://git…
Nov 12, 2022
5b0cd78
fix: add comment to create lb service method
Nov 14, 2022
46502ae
fix: resolve merge conflicts
Nov 14, 2022
5a58cd8
fix: resolve k8s utils cross compiling errors
Nov 14, 2022
38477ab
fix: resolve k8s utils cross compiling errors
Nov 14, 2022
8c8615e
fix: resolve linting errors
Nov 14, 2022
1173af5
fix: remove unnecessary newline
Nov 14, 2022
74114cc
fix: apply cross compile hints
Nov 15, 2022
b4dd24a
fix: fix docker pkg
Nov 15, 2022
afd5d0b
test: add e2e tests on the environment interpolation
Nov 18, 2022
4e2b3b3
test: fix the output k8s json
Nov 18, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions pkg/kobject/kobject.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ func (opt *ConvertOptions) IsPodController() bool {
return opt.IsDeploymentFlag || opt.IsDaemonSetFlag || opt.IsReplicationControllerFlag || opt.Controller != ""
}

// ServiceConfigGroup holds an array of a ServiceConfig objects.
type ServiceConfigGroup []ServiceConfig

// ServiceConfig holds the basic struct of a container
Expand Down
5 changes: 3 additions & 2 deletions pkg/loader/compose/v3.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,9 @@ func parseV3(files []string) (kobject.KomposeObject, error) {
// We load it in order to retrieve the parsed output configuration!
// This will output a github.com/docker/cli ServiceConfig
// Which is similar to our version of ServiceConfig
currentConfig, err := loader.Load(configDetails)
currentConfig, err := loader.Load(configDetails, func(options *loader.Options) {
options.SkipInterpolation = true
})
if err != nil {
return kobject.KomposeObject{}, err
}
Expand All @@ -129,7 +131,6 @@ func parseV3(files []string) (kobject.KomposeObject, error) {
if err != nil {
return kobject.KomposeObject{}, err
}

return komposeObject, nil
}

Expand Down
31 changes: 24 additions & 7 deletions pkg/transformer/kubernetes/k8sutils.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import (
"path"
"path/filepath"
"reflect"
"regexp"
"sort"
"strconv"
"strings"
Expand Down Expand Up @@ -382,6 +383,7 @@ func (k *Kubernetes) initSvcObject(name string, service kobject.ServiceConfig, p
return svc
}

// CreateLBService creates a k8s Load Balancer Service
func (k *Kubernetes) CreateLBService(name string, service kobject.ServiceConfig) []*api.Service {
var svcs []*api.Service
tcpPorts, udpPorts := k.ConfigLBServicePorts(service)
Expand Down Expand Up @@ -442,6 +444,8 @@ func (k *Kubernetes) CreateHeadlessService(name string, service kobject.ServiceC

return svc
}

// UpdateKubernetesObjectsMultipleContainers method updates the kubernetes objects with the necessary data
func (k *Kubernetes) UpdateKubernetesObjectsMultipleContainers(name string, service kobject.ServiceConfig, objects *[]runtime.Object, podSpec PodSpec) error {
// Configure annotations
annotations := transformer.ConfigAnnotations(service)
Expand Down Expand Up @@ -524,7 +528,7 @@ func (k *Kubernetes) UpdateKubernetesObjects(name string, service kobject.Servic
template.Spec.Containers[0].Name = GetContainerName(service)
template.Spec.Containers[0].Env = envs
template.Spec.Containers[0].Command = service.Command
template.Spec.Containers[0].Args = service.Args
template.Spec.Containers[0].Args = GetContainerArgs(service)
template.Spec.Containers[0].WorkingDir = service.WorkingDir
template.Spec.Containers[0].VolumeMounts = append(template.Spec.Containers[0].VolumeMounts, volumesMount...)
template.Spec.Containers[0].Stdin = service.Stdin
Expand Down Expand Up @@ -594,18 +598,18 @@ func (k *Kubernetes) UpdateKubernetesObjects(name string, service kobject.Servic
template.ObjectMeta.Labels = transformer.ConfigLabelsWithNetwork(name, service.Network)

// Configure the image pull policy
if policy, err := GetImagePullPolicy(name, service.ImagePullPolicy); err != nil {
policy, err := GetImagePullPolicy(name, service.ImagePullPolicy)
if err != nil {
return err
} else {
template.Spec.Containers[0].ImagePullPolicy = policy
}
template.Spec.Containers[0].ImagePullPolicy = policy

// Configure the container restart policy.
if restart, err := GetRestartPolicy(name, service.Restart); err != nil {
restart, err := GetRestartPolicy(name, service.Restart)
if err != nil {
return err
} else {
template.Spec.RestartPolicy = restart
}
template.Spec.RestartPolicy = restart

// Configure hostname/domain_name settings
if service.HostName != "" {
Expand Down Expand Up @@ -887,6 +891,7 @@ func FormatContainerName(name string) string {
return name
}

// GetContainerName returns the name of the container, from the service config object
func GetContainerName(service kobject.ServiceConfig) string {
name := service.Name
if len(service.ContainerName) > 0 {
Expand All @@ -899,3 +904,15 @@ func GetContainerName(service kobject.ServiceConfig) string {
func FormatResourceName(name string) string {
return strings.ToLower(strings.Replace(name, "_", "-", -1))
}

// GetContainerArgs update the interpolation of env variables if exists.
// example: [curl, $PROTOCOL://$DOMAIN] => [curl, $(PROTOCOL)://$(DOMAIN)]
func GetContainerArgs(service kobject.ServiceConfig) []string {
var args []string
re := regexp.MustCompile(`\$([a-zA-Z0-9]*)`)
for _, arg := range service.Args {
arg = re.ReplaceAllString(arg, `$($1)`)
args = append(args, arg)
}
return args
}
32 changes: 32 additions & 0 deletions pkg/transformer/kubernetes/k8sutils_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -597,3 +597,35 @@ func TestCreateServiceWithSpecialName(t *testing.T) {
}
}
}

func TestArgsInterpolation(t *testing.T) {
// An example service
service := kobject.ServiceConfig{
ContainerName: "name",
Image: "image",
Environment: []kobject.EnvVar{{Name: "PROTOCOL", Value: "https"}, {Name: "DOMAIN", Value: "google.com"}},
Port: []kobject.Ports{{HostPort: 123, ContainerPort: 456, Protocol: string(corev1.ProtocolTCP)}},
Command: []string{"curl"},
Args: []string{"$PROTOCOL://$DOMAIN/"},
}

// An example object generated via k8s runtime.Objects()
komposeObject := kobject.KomposeObject{
ServiceConfigs: map[string]kobject.ServiceConfig{"app": service},
}
k := Kubernetes{}
objects, err := k.Transform(komposeObject, kobject.ConvertOptions{CreateD: true, Replicas: 3})
if err != nil {
t.Error(errors.Wrap(err, "k.Transform failed"))
}

expectedArgs := []string{"$(PROTOCOL)://$(DOMAIN)/"}
for _, obj := range objects {
if deployment, ok := obj.(*appsv1.Deployment); ok {
args := deployment.Spec.Template.Spec.Containers[0].Args[0]
if args != expectedArgs[0] {
t.Errorf("Expected args %v upon conversion, actual %v", expectedArgs, args)
}
}
}
}
18 changes: 10 additions & 8 deletions pkg/transformer/kubernetes/kubernetes.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ type Kubernetes struct {
// PVCRequestSize (Persistent Volume Claim) has default size
const PVCRequestSize = "100Mi"

// ValidVolumeSet has the different types of valid volumes
var ValidVolumeSet = map[string]struct{}{"emptyDir": {}, "hostPath": {}, "configMap": {}, "persistentVolumeClaim": {}}

const (
Expand Down Expand Up @@ -432,6 +433,7 @@ func (k *Kubernetes) InitDS(name string, service kobject.ServiceConfig) *appsv1.
return ds
}

// InitSS method initialize a stateful set
func (k *Kubernetes) InitSS(name string, service kobject.ServiceConfig, replicas int) *appsv1.StatefulSet {
var podSpec api.PodSpec
if len(service.Configs) > 0 {
Expand Down Expand Up @@ -634,6 +636,7 @@ func ConfigPorts(service kobject.ServiceConfig) []api.ContainerPort {
return ports
}

// ConfigLBServicePorts method configure the ports of the k8s Load Balancer Service
func (k *Kubernetes) ConfigLBServicePorts(service kobject.ServiceConfig) ([]api.ServicePort, []api.ServicePort) {
var tcpPorts []api.ServicePort
var udpPorts []api.ServicePort
Expand Down Expand Up @@ -954,16 +957,15 @@ func (k *Kubernetes) ConfigVolumes(name string, service kobject.ServiceConfig) (
volsource = source
} else if useConfigMap {
log.Debugf("Use configmap volume")

if cm, err := k.IntiConfigMapFromFileOrDir(name, volumeName, volume.Host, service); err != nil {
cm, err := k.IntiConfigMapFromFileOrDir(name, volumeName, volume.Host, service)
if err != nil {
return nil, nil, nil, nil, err
} else {
cms = append(cms, cm)
volsource = k.ConfigConfigMapVolumeSource(volumeName, volume.Container, cm)
}
cms = append(cms, cm)
volsource = k.ConfigConfigMapVolumeSource(volumeName, volume.Container, cm)

if useSubPathMount(cm) {
volMount.SubPath = volsource.ConfigMap.Items[0].Path
}
if useSubPathMount(cm) {
volMount.SubPath = volsource.ConfigMap.Items[0].Path
}
} else {
volsource = k.ConfigPVCVolumeSource(volumeName, readonly)
Expand Down
14 changes: 14 additions & 0 deletions pkg/transformer/kubernetes/podspec.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,15 @@ import (
"k8s.io/apimachinery/pkg/util/intstr"
)

// PodSpec holds the spec of k8s pod.
type PodSpec struct {
api.PodSpec
}

// PodSpecOption holds the function to apply on a PodSpec
type PodSpecOption func(*PodSpec)

// AddContainer method is responsible for adding a new container to a k8s Pod.
func AddContainer(service kobject.ServiceConfig, opt kobject.ConvertOptions) PodSpecOption {
return func(podSpec *PodSpec) {
name := GetContainerName(service)
Expand Down Expand Up @@ -50,6 +53,7 @@ func AddContainer(service kobject.ServiceConfig, opt kobject.ConvertOptions) Pod
}
}

// TerminationGracePeriodSeconds method is responsible for attributing the grace period seconds option to a pod
func TerminationGracePeriodSeconds(name string, service kobject.ServiceConfig) PodSpecOption {
return func(podSpec *PodSpec) {
var err error
Expand Down Expand Up @@ -156,6 +160,7 @@ func SecurityContext(name string, service kobject.ServiceConfig) PodSpecOption {
}
}

// SetVolumeNames method return a set of volume names
func SetVolumeNames(volumes []api.Volume) mapset.Set {
set := mapset.NewSet()
for _, volume := range volumes {
Expand All @@ -164,6 +169,7 @@ func SetVolumeNames(volumes []api.Volume) mapset.Set {
return set
}

// SetVolumes method returns a method that adds the volumes to the pod spec
func SetVolumes(volumes []api.Volume) PodSpecOption {
return func(podSpec *PodSpec) {
volumesSet := SetVolumeNames(volumes)
Expand All @@ -179,6 +185,7 @@ func SetVolumes(volumes []api.Volume) PodSpecOption {
}
}

// SetVolumeMountPaths method returns a set of volumes mount path
func SetVolumeMountPaths(volumesMount []api.VolumeMount) mapset.Set {
set := mapset.NewSet()
for _, volumeMount := range volumesMount {
Expand All @@ -188,6 +195,7 @@ func SetVolumeMountPaths(volumesMount []api.VolumeMount) mapset.Set {
return set
}

// SetVolumeMounts returns a function which adds the volume mounts option to the pod spec
func SetVolumeMounts(volumesMount []api.VolumeMount) PodSpecOption {
return func(podSpec *PodSpec) {
volumesMountSet := SetVolumeMountPaths(volumesMount)
Expand Down Expand Up @@ -242,6 +250,7 @@ func RestartPolicy(name string, service kobject.ServiceConfig) PodSpecOption {
}
}

// HostName configure the host name of a pod
func HostName(service kobject.ServiceConfig) PodSpecOption {
return func(podSpec *PodSpec) {
// Configure hostname/domain_name settings
Expand All @@ -251,6 +260,7 @@ func HostName(service kobject.ServiceConfig) PodSpecOption {
}
}

// DomainName configure the domain name of a pod
func DomainName(service kobject.ServiceConfig) PodSpecOption {
return func(podSpec *PodSpec) {
if service.DomainName != "" {
Expand Down Expand Up @@ -299,25 +309,29 @@ func configProbe(healthCheck kobject.HealthCheck) *api.Probe {
return &probe
}

// ServiceAccountName is responsible for setting the service account name to the pod spec
func ServiceAccountName(serviceAccountName string) PodSpecOption {
return func(podSpec *PodSpec) {
podSpec.ServiceAccountName = serviceAccountName
}
}

// TopologySpreadConstraints is responsible for setting the topology spread constraints to the pod spec
func TopologySpreadConstraints(service kobject.ServiceConfig) PodSpecOption {
return func(podSpec *PodSpec) {
podSpec.TopologySpreadConstraints = ConfigTopologySpreadConstraints(service)
}
}

// Append is responsible for adding the pod spec options to the particular pod
func (podSpec *PodSpec) Append(ops ...PodSpecOption) *PodSpec {
for _, option := range ops {
option(podSpec)
}
return podSpec
}

// Get is responsible for returning the pod spec of a particular pod
func (podSpec *PodSpec) Get() api.PodSpec {
return podSpec.PodSpec
}
1 change: 1 addition & 0 deletions pkg/utils/docker/image.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ type Image struct {
Remote string // the image's remote identifier. (ie: registry/name[:tag])
}

// NewImageFromParsed method returns the docker image from the docker parser reference
func NewImageFromParsed(parsed *dockerparser.Reference) Image {
return Image{
Name: parsed.Name(),
Expand Down
1 change: 1 addition & 0 deletions pkg/utils/docker/tag.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ type Tag struct {
Client dockerlib.Client
}

// TagImage function is responsible for tagging the docker image
func (c *Tag) TagImage(image Image) error {
options := dockerlib.TagImageOptions{
Tag: image.Tag,
Expand Down
10 changes: 9 additions & 1 deletion script/test/cmd/tests_new.sh
Original file line number Diff line number Diff line change
Expand Up @@ -202,4 +202,12 @@ os_cmd="kompose --provider=openshift -f $KOMPOSE_ROOT/script/test/fixtures/mul
k8s_output="$KOMPOSE_ROOT/script/test/fixtures/multiple-type-volumes/output-k8s.json"
os_output="$KOMPOSE_ROOT/script/test/fixtures/multiple-type-volumes/output-os.json"
convert::expect_success_and_warning "$k8s_cmd" "$k8s_output"
convert::expect_success "$os_cmd" "$os_output"
convert::expect_success "$os_cmd" "$os_output"

# Test environment variables interpolation
k8s_cmd="kompose -f $KOMPOSE_ROOT/script/test/fixtures/envvars-interpolation/docker-compose.yaml convert --stdout -j --with-kompose-annotation=false"
os_cmd="kompose --provider=openshift -f $KOMPOSE_ROOT/script/test/fixtures/envvars-interpolation/docker-compose.yaml convert --stdout -j --with-kompose-annotation=false"
k8s_output="$KOMPOSE_ROOT/script/test/fixtures/envvars-interpolation/output-k8s.json"
os_output="$KOMPOSE_ROOT/script/test/fixtures/envvars-interpolation/output-os.json"
convert::expect_success_and_warning "$k8s_cmd" "$k8s_output"
convert::expect_success "$os_cmd" "$os_output"
13 changes: 13 additions & 0 deletions script/test/fixtures/envvars-interpolation/docker-compose.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
version: '3.5'

services:
myservice:
image: alpine
environment:
PROTOCOL: 'https'
DOMAIN: 'google.com'
command:
[
'curl',
'$PROTOCOL://$DOMAIN/',
]
Loading