Skip to content

Commit

Permalink
adds a label for initContainers, test and user-guide (#1840)
Browse files Browse the repository at this point in the history
* adds a label for initContainers, test and user-guide

Signed-off-by: jose luis <[email protected]>

* solved suggestion version from 2 to 3, coments

Signed-off-by: jose luis <[email protected]>

* test e2e

Signed-off-by: jose luis <[email protected]>

* add target to kompose build

Signed-off-by: jose luis <[email protected]>

* chore(deps)(deps): bump golang.org/x/tools from 0.16.1 to 0.19.0 (#1836)

Bumps [golang.org/x/tools](https://github.com/golang/tools) from 0.16.1 to 0.19.0.
- [Release notes](https://github.com/golang/tools/releases)
- [Commits](golang/tools@v0.16.1...v0.19.0)

---
updated-dependencies:
- dependency-name: golang.org/x/tools
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* changed var names contaers to containers
changed labels to kompose.init.container.name, kompose.init.container.image, kompose.init.container.command
fixed documentation, tests and e2e
also merged main with new commits to this branch

Signed-off-by: jose luis <[email protected]>

---------

Signed-off-by: jose luis <[email protected]>
Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Kubernetes Prow Robot <[email protected]>
  • Loading branch information
3 people authored Apr 8, 2024
1 parent 14152d4 commit c9c1080
Show file tree
Hide file tree
Showing 7 changed files with 346 additions and 1 deletion.
45 changes: 45 additions & 0 deletions docs/user-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,9 @@ The currently supported options are:
| kompose.cronjob.schedule | kubernetes cronjob schedule (for example: '1 * * * *') |
| kompose.cronjob.concurrency_policy | 'Forbid' / 'Allow' / 'Never' / '' |
| kompose.cronjob.backoff_limit | kubernetes cronjob backoff limit (for example: '6') |
| kompose.init.containers.name | kubernetes init container name |
| kompose.init.containers.image | kubernetes init container image |
| kompose.init.containers.command | kubernetes init container commands |

**Note**: `kompose.service.type` label should be defined with `ports` only (except for headless service), otherwise `kompose` will fail.

Expand Down Expand Up @@ -467,6 +470,48 @@ services:
labels:
kompose.volume.sub-path: pg-data
```

- `kompose.init.containers.name` is used to specify the name of the Init Containers for a Pod [Init Container Name](https://kubernetes.io/docs/concepts/workloads/pods/init-containers/)

For example:

```yaml
version: '3'
services:
example-service:
image: example-image
labels:
kompose.init.containers.name: "initcontainername"
```

- `kompose.init.containers.image` defines image to use for the Init Containers [Init Container Image](https://kubernetes.io/docs/concepts/workloads/pods/init-containers/)

For example:

```yaml
version: '3'
services:
example-service:
image: example-image
labels:
kompose.init.containers.image: perl
```


- `kompose.init.containers.command` defines the command that the Init Containers will run after they are started [Init Container Command](https://kubernetes.io/docs/concepts/workloads/pods/init-containers/)

For example:

```yaml
version: '3'
services:
example-service:
image: example-image
labels:
kompose.init.containers.command: ["perl", "-Mbignum=bpi", "-wle", "print bpi(2000)"]
kompose.init.containers.image: perl
```

## Restart

If you want to create normal pods without controller you can use `restart` construct of compose to define that. Follow table below to see what happens on the `restart` value.
Expand Down
6 changes: 6 additions & 0 deletions pkg/loader/compose/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,12 @@ const (
LabelCronJobConcurrencyPolicy = "kompose.cronjob.concurrency_policy"
// LabelCronJobBackoffLimit defines the job backoff limit
LabelCronJobBackoffLimit = "kompose.cronjob.backoff_limit"
// LabelInitContainerName defines name resource
LabelInitContainerName = "kompose.init.containers.name"
// LabelInitContainerImage defines image to pull
LabelInitContainerImage = "kompose.init.containers.image"
// LabelInitContainerCommand defines commands
LabelInitContainerCommand = "kompose.init.containers.command"
)

// load environment variables from compose file
Expand Down
47 changes: 46 additions & 1 deletion pkg/transformer/kubernetes/k8sutils.go
Original file line number Diff line number Diff line change
Expand Up @@ -654,7 +654,7 @@ func (k *Kubernetes) UpdateKubernetesObjects(name string, service kobject.Servic
if serviceAccountName, ok := service.Labels[compose.LabelServiceAccountName]; ok {
template.Spec.ServiceAccountName = serviceAccountName
}

fillInitContainers(template, service)
return nil
}

Expand Down Expand Up @@ -985,3 +985,48 @@ func reformatSecretConfigUnderscoreWithDash(secretConfig types.ServiceSecretConf

return newSecretConfig
}

// fillInitContainers looks for an initContainer resources and its passed as labels
// if there is no image, it does not fill the initContainer
// https://kubernetes.io/docs/concepts/workloads/pods/init-containers/
func fillInitContainers(template *api.PodTemplateSpec, service kobject.ServiceConfig) {
resourceImage, exist := service.Labels[compose.LabelInitContainerImage]
if !exist || resourceImage == "" {
return
}
resourceName, exist := service.Labels[compose.LabelInitContainerName]
if !exist || resourceName == "" {
resourceName = "init-service"
}

template.Spec.InitContainers = append(template.Spec.InitContainers, api.Container{
Name: resourceName,
Command: parseContainerCommandsFromStr(service.Labels[compose.LabelInitContainerCommand]),
Image: resourceImage,
})
}

// parseContainerCommandsFromStr parses a string containing comma-separated commands
// returns a slice of strings or a single command
// example:
// [ "bundle", "exec", "thin", "-p", "3000" ]
//
// example:
// [ "bundle exec thin -p 3000" ]
func parseContainerCommandsFromStr(line string) []string {
if line == "" {
return []string{}
}
var commands []string
if strings.Contains(line, ",") {
line = strings.TrimSpace(strings.Trim(line, "[]"))
commands = strings.Split(line, ",")
// remove space "'
for i := range commands {
commands[i] = strings.TrimSpace(strings.Trim(commands[i], `"' `))
}
} else {
commands = append(commands, line)
}
return commands
}
207 changes: 207 additions & 0 deletions pkg/transformer/kubernetes/k8sutils_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import (
"github.com/kubernetes/kompose/pkg/testutils"
"github.com/pkg/errors"
appsv1 "k8s.io/api/apps/v1"
api "k8s.io/api/core/v1"
corev1 "k8s.io/api/core/v1"
)

Expand Down Expand Up @@ -738,3 +739,209 @@ func TestRemoveEmptyInterfaces(t *testing.T) {
})
}
}

func Test_parseContainerCommandsFromStr(t *testing.T) {
tests := []struct {
name string
line string
want []string
}{
{
name: "line command without spaces in between",
line: `[ "bundle", "exec", "thin", "-p", "3000" ]`,
want: []string{
"bundle", "exec", "thin", "-p", "3000",
},
},
{
name: `line command spaces inside ""`,
line: `[ " bundle ", " exec ", " thin ", " -p ", "3000" ]`,
want: []string{
"bundle", "exec", "thin", "-p", "3000",
},
},
{
name: `more use cases for line command spaces inside ""`,
line: `[ " bundle ", "exec ", " thin ", " -p ", "3000 " ]`,
want: []string{
"bundle", "exec", "thin", "-p", "3000",
},
},
{
name: `line command without [] and ""`,
line: `bundle exec thin -p 3000`,
want: []string{
"bundle exec thin -p 3000",
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := parseContainerCommandsFromStr(tt.line); !reflect.DeepEqual(got, tt.want) {
t.Errorf("parseContainerCommandsFromStr() = %v, want %v", got, tt.want)
}
})
}
}

func Test_fillInitContainers(t *testing.T) {
type args struct {
template *api.PodTemplateSpec
service kobject.ServiceConfig
}
tests := []struct {
name string
args args
want []corev1.Container
}{
{
name: "Testing init container are generated from labels with ,",
args: args{
template: &api.PodTemplateSpec{},
service: kobject.ServiceConfig{
Labels: map[string]string{
compose.LabelInitContainerName: "name",
compose.LabelInitContainerImage: "image",
compose.LabelInitContainerCommand: `[ "bundle", "exec", "thin", "-p", "3000" ]`,
},
},
},
want: []corev1.Container{
{
Name: "name",
Image: "image",
Command: []string{
"bundle", "exec", "thin", "-p", "3000",
},
},
},
},
{
name: "Testing init container are generated from labels without ,",
args: args{
template: &api.PodTemplateSpec{},
service: kobject.ServiceConfig{
Labels: map[string]string{
compose.LabelInitContainerName: "name",
compose.LabelInitContainerImage: "image",
compose.LabelInitContainerCommand: `bundle exec thin -p 3000`,
},
},
},
want: []corev1.Container{
{
Name: "name",
Image: "image",
Command: []string{
`bundle exec thin -p 3000`,
},
},
},
},
{
name: `Testing init container with long command with vars inside and ''`,
args: args{
template: &api.PodTemplateSpec{},
service: kobject.ServiceConfig{
Labels: map[string]string{
compose.LabelInitContainerName: "init-myservice",
compose.LabelInitContainerImage: "busybox:1.28",
compose.LabelInitContainerCommand: `['sh', '-c', "until nslookup myservice.$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace).svc.cluster.local; do echo waiting for myservice; sleep 2; done"]`,
},
},
},
want: []corev1.Container{
{
Name: "init-myservice",
Image: "busybox:1.28",
Command: []string{
"sh", "-c", `until nslookup myservice.$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace).svc.cluster.local; do echo waiting for myservice; sleep 2; done`,
},
},
},
},
{
name: `without image`,
args: args{
template: &api.PodTemplateSpec{},
service: kobject.ServiceConfig{
Labels: map[string]string{
compose.LabelInitContainerName: "init-myservice",
compose.LabelInitContainerImage: "",
compose.LabelInitContainerCommand: `['sh', '-c', "until nslookup myservice.$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace).svc.cluster.local; do echo waiting for myservice; sleep 2; done"]`,
},
},
},
want: nil,
},
{
name: `Testing init container without name`,
args: args{
template: &api.PodTemplateSpec{},
service: kobject.ServiceConfig{
Labels: map[string]string{
compose.LabelInitContainerName: "",
compose.LabelInitContainerImage: "busybox:1.28",
compose.LabelInitContainerCommand: `['sh', '-c', "until nslookup myservice.$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace).svc.cluster.local; do echo waiting for myservice; sleep 2; done"]`,
},
},
},
want: []corev1.Container{
{
Name: "init-service",
Image: "busybox:1.28",
Command: []string{
"sh", "-c", `until nslookup myservice.$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace).svc.cluster.local; do echo waiting for myservice; sleep 2; done`,
},
},
},
},
{
name: `Testing init container without command`,
args: args{
template: &api.PodTemplateSpec{},
service: kobject.ServiceConfig{
Labels: map[string]string{
compose.LabelInitContainerName: "init-service",
compose.LabelInitContainerImage: "busybox:1.28",
compose.LabelInitContainerCommand: ``,
},
},
},
want: []corev1.Container{
{
Name: "init-service",
Image: "busybox:1.28",
Command: []string{},
},
},
},
{
name: `Testing init container without command`,
args: args{
template: &api.PodTemplateSpec{},
service: kobject.ServiceConfig{
Labels: map[string]string{
compose.LabelInitContainerName: "init-service",
compose.LabelInitContainerImage: "busybox:1.28",
},
},
},
want: []corev1.Container{
{
Name: "init-service",
Image: "busybox:1.28",
Command: []string{},
},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
fillInitContainers(tt.args.template, tt.args.service)
if !reflect.DeepEqual(tt.args.template.Spec.InitContainers, tt.want) {
t.Errorf("Test_fillInitContainers Fail got %v, want %v", tt.args.template.Spec.InitContainers, tt.want)
}
})
}
}
5 changes: 5 additions & 0 deletions script/test/cmd/tests_new.sh
Original file line number Diff line number Diff line change
Expand Up @@ -339,3 +339,8 @@ os_cmd="kompose -f $KOMPOSE_ROOT/script/test/fixtures/resources-lowercase/compos
os_output="$KOMPOSE_ROOT/script/test/fixtures/resources-lowercase/output-os.yaml"
convert::expect_success "$k8s_cmd" "$k8s_output" || exit 1
convert::expect_success "$os_cmd" "$os_output" || exit 1

# Test resources to generate initcontainer
k8s_cmd="kompose -f $KOMPOSE_ROOT/script/test/fixtures/initcontainer/compose.yaml convert --stdout --with-kompose-annotation=false"
k8s_output="$KOMPOSE_ROOT/script/test/fixtures/initcontainer/output-k8s.yaml"
convert::expect_success_and_warning "$k8s_cmd" "$k8s_output" || exit 1
8 changes: 8 additions & 0 deletions script/test/fixtures/initcontainer/compose.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
version: "3"
services:
web:
image: nginx
labels:
kompose.init.containers.name: "init-myservice"
kompose.init.containers.image: "busybox:1.28"
kompose.init.containers.command: '["sh", "-c", "until nslookup myservice.$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace).svc.cluster.local; do echo waiting for myservice; sleep 2; done"]'
29 changes: 29 additions & 0 deletions script/test/fixtures/initcontainer/output-k8s.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
---
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
io.kompose.service: web
name: web
spec:
replicas: 1
selector:
matchLabels:
io.kompose.service: web
template:
metadata:
labels:
io.kompose.network/initcontainer-default: "true"
io.kompose.service: web
spec:
containers:
- image: nginx
name: web
initContainers:
- command:
- sh
- -c
- until nslookup myservice.$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace).svc.cluster.local; do echo waiting for myservice; sleep 2; done
image: busybox:1.28
name: init-myservice
restartPolicy: Always

0 comments on commit c9c1080

Please sign in to comment.