forked from LaconicNetwork/kompose
Add env_file + ConfigMaps feature to Kompose
When using env_file with Docker Compose, a ConfigMap will be generated
For example:
```sh
▶ ./kompose convert -f
script/test/fixtures/configmaps/docker-compose.yml
INFO Kubernetes file "redis-service.yaml" created
INFO Kubernetes file "redis-deployment.yaml" created
INFO Kubernetes file "foo-env-configmap.yaml" created
INFO Kubernetes file "bar-env-configmap.yaml" created
```
File:
```yaml
version: '3'
services:
redis:
image: 'bitnami/redis:latest'
environment:
- ALLOW_EMPTY_PASSWORD=no
# Env file will override environment / warn!
env_file:
- "foo.env"
- bar.env
labels:
kompose.service.type: nodeport
ports:
- '6379:6379'
```
To:
```yaml
apiVersion: v1
data:
ALLOW_EMPTY_PASSWORD: "yes"
kind: ConfigMap
metadata:
creationTimestamp: null
name: foo-env
```
```yaml
...
- env:
- name: ALLOW_EMPTY_PASSWORD
valueFrom:
configMapKeyRef:
key: ALLOW_EMPTY_PASSWORD
name: foo-env
```
This commit is contained in:
@@ -22,6 +22,7 @@ import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"strconv"
|
||||
@@ -31,6 +32,7 @@ import (
|
||||
|
||||
log "github.com/Sirupsen/logrus"
|
||||
"github.com/ghodss/yaml"
|
||||
"github.com/joho/godotenv"
|
||||
"github.com/kubernetes/kompose/pkg/kobject"
|
||||
"github.com/kubernetes/kompose/pkg/transformer"
|
||||
|
||||
@@ -330,9 +332,13 @@ func (k *Kubernetes) CreateHeadlessService(name string, service kobject.ServiceC
|
||||
}
|
||||
|
||||
// UpdateKubernetesObjects loads configurations to k8s objects
|
||||
func (k *Kubernetes) UpdateKubernetesObjects(name string, service kobject.ServiceConfig, objects *[]runtime.Object) error {
|
||||
func (k *Kubernetes) UpdateKubernetesObjects(name string, service kobject.ServiceConfig, opt kobject.ConvertOptions, objects *[]runtime.Object) error {
|
||||
|
||||
// Configure the environment variables.
|
||||
envs := k.ConfigEnvs(name, service)
|
||||
envs, err := k.ConfigEnvs(name, service, opt)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Unable to load env variables")
|
||||
}
|
||||
|
||||
// Configure the container volumes.
|
||||
volumesMount, volumes, pvc, err := k.ConfigVolumes(name, service)
|
||||
@@ -570,3 +576,27 @@ func DurationStrToSecondsInt(s string) (*int64, error) {
|
||||
r := (int64)(duration.Seconds())
|
||||
return &r, nil
|
||||
}
|
||||
|
||||
func GetEnvsFromFile(file string, opt kobject.ConvertOptions) (map[string]string, error) {
|
||||
// Get the correct file context / directory
|
||||
composeDir, err := transformer.GetComposeFileDir(opt.InputFiles)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "Unable to load file context")
|
||||
}
|
||||
fileLocation := path.Join(composeDir, file)
|
||||
|
||||
// Load environment variables from file
|
||||
envLoad, err := godotenv.Read(fileLocation)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "Unable to read env_file")
|
||||
}
|
||||
|
||||
return envLoad, nil
|
||||
}
|
||||
|
||||
func FormatEnvName(name string) string {
|
||||
envName := strings.Trim(name, "./")
|
||||
envName = strings.Replace(envName, ".", "-", -1)
|
||||
envName = strings.Replace(envName, "/", "-", -1)
|
||||
return envName
|
||||
}
|
||||
|
||||
@@ -158,6 +158,33 @@ func (k *Kubernetes) InitSvc(name string, service kobject.ServiceConfig) *api.Se
|
||||
return svc
|
||||
}
|
||||
|
||||
// InitConfigMap initialized a ConfigMap object
|
||||
func (k *Kubernetes) InitConfigMap(name string, service kobject.ServiceConfig, opt kobject.ConvertOptions, envFile string) *api.ConfigMap {
|
||||
|
||||
envs, err := GetEnvsFromFile(envFile, opt)
|
||||
if err != nil {
|
||||
log.Fatalf("Unable to retrieve env file: %s", err)
|
||||
}
|
||||
|
||||
// Remove root pathing
|
||||
// replace all other slashes / preiods
|
||||
envName := FormatEnvName(envFile)
|
||||
|
||||
// In order to differentiate files, we append to the name and remove '.env' if applicate from the file name
|
||||
configMap := &api.ConfigMap{
|
||||
TypeMeta: unversioned.TypeMeta{
|
||||
Kind: "ConfigMap",
|
||||
APIVersion: "v1",
|
||||
},
|
||||
ObjectMeta: api.ObjectMeta{
|
||||
Name: envName,
|
||||
},
|
||||
Data: envs,
|
||||
}
|
||||
|
||||
return configMap
|
||||
}
|
||||
|
||||
// InitD initializes Kubernetes Deployment object
|
||||
func (k *Kubernetes) InitD(name string, service kobject.ServiceConfig, replicas int) *extensions.Deployment {
|
||||
dc := &extensions.Deployment{
|
||||
@@ -476,19 +503,59 @@ func (k *Kubernetes) ConfigPVCVolumeSource(name string, readonly bool) *api.Volu
|
||||
}
|
||||
|
||||
// ConfigEnvs configures the environment variables.
|
||||
func (k *Kubernetes) ConfigEnvs(name string, service kobject.ServiceConfig) []api.EnvVar {
|
||||
func (k *Kubernetes) ConfigEnvs(name string, service kobject.ServiceConfig, opt kobject.ConvertOptions) ([]api.EnvVar, error) {
|
||||
|
||||
envs := transformer.EnvSort{}
|
||||
for _, v := range service.Environment {
|
||||
envs = append(envs, api.EnvVar{
|
||||
Name: v.Name,
|
||||
Value: v.Value,
|
||||
})
|
||||
|
||||
// If there is an env_file, use ConfigMaps and ignore the environment variables
|
||||
// already specified
|
||||
if len(service.EnvFile) > 0 {
|
||||
|
||||
// Load each env_file
|
||||
|
||||
for _, file := range service.EnvFile {
|
||||
|
||||
envName := FormatEnvName(file)
|
||||
|
||||
// Load environment variables from file
|
||||
envLoad, err := GetEnvsFromFile(file, opt)
|
||||
if err != nil {
|
||||
return envs, errors.Wrap(err, "Unable to read env_file")
|
||||
}
|
||||
|
||||
// Add configMapKeyRef to each environment variable
|
||||
for k, _ := range envLoad {
|
||||
envs = append(envs, api.EnvVar{
|
||||
Name: k,
|
||||
ValueFrom: &api.EnvVarSource{
|
||||
ConfigMapKeyRef: &api.ConfigMapKeySelector{
|
||||
LocalObjectReference: api.LocalObjectReference{
|
||||
Name: envName,
|
||||
},
|
||||
Key: k,
|
||||
}},
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
// Load up the environment variables
|
||||
for _, v := range service.Environment {
|
||||
envs = append(envs, api.EnvVar{
|
||||
Name: v.Name,
|
||||
Value: v.Value,
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Stable sorts data while keeping the original order of equal elements
|
||||
// we need this because envs are not populated in any random order
|
||||
// this sorting ensures they are populated in a particular order
|
||||
sort.Stable(envs)
|
||||
return envs
|
||||
return envs, nil
|
||||
}
|
||||
|
||||
// CreateKubernetesObjects generates a Kubernetes artifact for each input type service
|
||||
@@ -517,6 +584,13 @@ func (k *Kubernetes) CreateKubernetesObjects(name string, service kobject.Servic
|
||||
objects = append(objects, k.InitRC(name, service, replica))
|
||||
}
|
||||
|
||||
if len(service.EnvFile) > 0 {
|
||||
for _, envFile := range service.EnvFile {
|
||||
configMap := k.InitConfigMap(name, service, opt, envFile)
|
||||
objects = append(objects, configMap)
|
||||
}
|
||||
}
|
||||
|
||||
return objects
|
||||
}
|
||||
|
||||
@@ -610,7 +684,10 @@ func (k *Kubernetes) Transform(komposeObject kobject.KomposeObject, opt kobject.
|
||||
}
|
||||
}
|
||||
|
||||
k.UpdateKubernetesObjects(name, service, &objects)
|
||||
err := k.UpdateKubernetesObjects(name, service, opt, &objects)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "Error transforming Kubernetes objects")
|
||||
}
|
||||
|
||||
allobjects = append(allobjects, objects...)
|
||||
}
|
||||
@@ -744,6 +821,12 @@ func (k *Kubernetes) Deploy(komposeObject kobject.KomposeObject, opt kobject.Con
|
||||
return err
|
||||
}
|
||||
log.Infof("Successfully created Pod: %s", t.Name)
|
||||
case *api.ConfigMap:
|
||||
_, err := client.ConfigMaps(namespace).Create(t)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
log.Infof("Successfully created Config Map: %s", t.Name)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -398,8 +398,11 @@ func (o *OpenShift) Transform(komposeObject kobject.KomposeObject, opt kobject.C
|
||||
}
|
||||
}
|
||||
|
||||
// Update and then append the objects (we're done generating)
|
||||
o.UpdateKubernetesObjects(name, service, &objects)
|
||||
err := o.UpdateKubernetesObjects(name, service, opt, &objects)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "Error transforming Kubernetes objects")
|
||||
}
|
||||
|
||||
allobjects = append(allobjects, objects...)
|
||||
}
|
||||
|
||||
|
||||
@@ -62,9 +62,10 @@ func TestOpenShiftUpdateKubernetesObjects(t *testing.T) {
|
||||
var object []runtime.Object
|
||||
o := OpenShift{}
|
||||
serviceConfig := newServiceConfig()
|
||||
opt := kobject.ConvertOptions{}
|
||||
|
||||
object = append(object, o.initDeploymentConfig("foobar", serviceConfig, 3))
|
||||
o.UpdateKubernetesObjects("foobar", serviceConfig, &object)
|
||||
o.UpdateKubernetesObjects("foobar", serviceConfig, opt, &object)
|
||||
|
||||
for _, obj := range object {
|
||||
switch tobj := obj.(type) {
|
||||
|
||||
Reference in New Issue
Block a user