Skip to content

Commit

Permalink
Replace env.Parametr with key=value syntax
Browse files Browse the repository at this point in the history
  • Loading branch information
krhubert committed Dec 14, 2018
1 parent 434c1c1 commit 62934d5
Show file tree
Hide file tree
Showing 14 changed files with 119 additions and 73 deletions.
14 changes: 0 additions & 14 deletions container/service_options.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
package container

import (
"fmt"
"os"
"sort"
"strconv"
"strings"

Expand Down Expand Up @@ -137,15 +135,3 @@ func mergeLabels(l1 map[string]string, l2 map[string]string) map[string]string {
}
return l1
}

// MapToEnv transform a map of key value to a array of env string.
// env vars sorted by names to get an accurate order while testing, otherwise
// comparing a string slice with different orders will fail.
func MapToEnv(data map[string]string) []string {
env := make([]string, 0, len(data))
for key, value := range data {
env = append(env, fmt.Sprintf("%s=%s", key, value))
}
sort.Strings(env)
return env
}
2 changes: 1 addition & 1 deletion daemon/daemon.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ func (d *ContainerDaemon) buildServiceOptions(sharedNetworkID string) container.
return container.ServiceOptions{
Namespace: []string{},
Image: d.cfg.Core.Image,
Env: xos.MapToEnv(d.cfg.DaemonEnv()),
Env: xos.EnvMapToSlice(d.cfg.DaemonEnv()),
Mounts: []container.Mount{
{
Source: d.cfg.Docker.Socket,
Expand Down
12 changes: 9 additions & 3 deletions interface/grpc/core/deploy.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (
func (s *Server) DeployService(stream coreapi.Core_DeployServiceServer) error {
var (
statuses = make(chan api.DeployStatus)
option = api.DeployServiceStatusOption(statuses)
wg sync.WaitGroup

service *service.Service
Expand All @@ -34,18 +35,22 @@ func (s *Server) DeployService(stream coreapi.Core_DeployServiceServer) error {
return err
}

// env must go always with first package
// env must be set with first package (always)
env := in.GetEnv()

if url := in.GetUrl(); url != "" {
service, validationError, err = s.api.DeployServiceFromURL(url, env, api.DeployServiceStatusOption(statuses))
service, validationError, err = s.api.DeployServiceFromURL(url, env, option)
} else {
// create tarball reader with first chunk of bytes
tarball := &deployChunkReader{
stream: stream,
buf: in.GetChunk(),
}
service, validationError, err = s.api.DeployService(tarball, env, api.DeployServiceStatusOption(statuses))
service, validationError, err = s.api.DeployService(tarball, env, option)
}

// wait for statuses to be sent first, otherwise sending multiple messages at the
// same time may cause messages to be sent in different order.
wg.Wait()

if err != nil {
Expand Down Expand Up @@ -88,6 +93,7 @@ func sendDeployStatus(statuses chan api.DeployStatus, stream coreapi.Core_Deploy
}
}

// deployChunkReader implements io.Reader for stream chunks.
type deployChunkReader struct {
stream coreapi.Core_DeployServiceServer

Expand Down
7 changes: 2 additions & 5 deletions service/dependency.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,8 @@ type Dependency struct {
// Argument holds the args to pass to the Docker container
Args []string `hash:"name:7"`

// Env is map of all defiend environments variables.
Env []*Parameter `hash:"name:8"`

// EnvValue is map of all values for Env
EnvValue map[string]string `hash:"name:9"`
// Env is a slice of all key=value.
Env []string `hash:"name:8"`

// service is the dependency's service.
service *Service `hash:"-"`
Expand Down
4 changes: 2 additions & 2 deletions service/importer/assets/schema.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 5 additions & 1 deletion service/importer/assets/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,11 @@
]
},
"env": {
"type": "object"
"type": "array",
"uniqueItems": true,
"items": {
"type": "string"
}
}
}
}
Expand Down
4 changes: 2 additions & 2 deletions service/importer/definition.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,8 @@ type Dependency struct {
// Args hold the args to pass to the Docker container
Args []string `yaml:"args"`

// Env is map of all defiend environments variables.
Env map[string]*Parameter `yaml:"env"`
// Env is a slice of all defiend environments variables in format key=value.
Env []string `yaml:"env"`
}

// Task describes a service task.
Expand Down
10 changes: 2 additions & 8 deletions service/inject_definition.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import (
)

// injectDefinition applies service definition to Service type.
func (s *Service) injectDefinition(def *importer.ServiceDefinition, env map[string]string) {
func (s *Service) injectDefinition(def *importer.ServiceDefinition) {
s.Name = def.Name
s.SID = def.SID
s.Description = def.Description
Expand All @@ -17,20 +17,14 @@ func (s *Service) injectDefinition(def *importer.ServiceDefinition, env map[stri
s.Tasks = s.defTasksToService(def.Tasks)
s.Dependencies = s.defDependenciesToService(def.Dependencies)

// insert env into dependencies
for _, d := range s.Dependencies {
d.EnvValue = env
}

s.configuration = &Dependency{}
if def.Configuration != nil {
s.configuration.Command = def.Configuration.Command
s.configuration.Args = def.Configuration.Args
s.configuration.Ports = def.Configuration.Ports
s.configuration.Volumes = def.Configuration.Volumes
s.configuration.VolumesFrom = def.Configuration.VolumesFrom
s.configuration.Env = s.defParametersToService(def.Configuration.Env)
s.configuration.EnvValue = env
s.configuration.Env = def.Configuration.Env
}
}

Expand Down
31 changes: 23 additions & 8 deletions service/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,13 @@ import (
"io"
"io/ioutil"
"os"
"strings"
"time"

"github.com/docker/docker/pkg/archive"
"github.com/mesg-foundation/core/container"
"github.com/mesg-foundation/core/service/importer"
"github.com/mesg-foundation/core/x/xos"
"github.com/mesg-foundation/core/x/xstructhash"
uuid "github.com/satori/go.uuid"
)
Expand Down Expand Up @@ -107,12 +109,18 @@ func New(tarball io.Reader, env map[string]string, options ...Option) (*Service,
if err != nil {
return nil, err
}
s.injectDefinition(def, env)

if err := s.validateEnv(); err != nil {
s.injectDefinition(def)

if err := s.validateConfigurationEnv(env); err != nil {
return nil, err
}

// if the all keys exists append to configuration env.
// The order of variables allows to safely append new variables
// without removing previous one. The last variable in slice will take precedens.
s.configuration.Env = append(s.configuration.Env, xos.EnvMapToSlice(env)...)

if err := s.deploy(); err != nil {
return nil, err
}
Expand Down Expand Up @@ -244,13 +252,20 @@ func (s *Service) getDependency(dependencyKey string) (*Dependency, error) {
return nil, fmt.Errorf("dependency %s do not exist", dependencyKey)
}

func (s *Service) validateEnv() error {
for _, p := range s.configuration.Env {
if p.Optional {
continue
// validateConfigurationEnv checks if every variable from env map
// has been defiend in mesg.yml in env section.
func (s *Service) validateConfigurationEnv(env map[string]string) error {
for key := range env {
exist := false
// check if "key=" exists in configuration
for _, env := range s.configuration.Env {
if strings.HasPrefix(env, key+"=") {
exist = true
break
}
}
if s.configuration.EnvValue[p.Key] == "" {
return fmt.Errorf("service env %s is empty", p.Key)
if !exist {
return fmt.Errorf("service environment variable %q dosen't exist in mesg.yml (under configuration.env key)", key)
}
}
return nil
Expand Down
4 changes: 2 additions & 2 deletions service/service_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ func TestInjectDefinitionWithConfig(t *testing.T) {
Configuration: &importer.Dependency{
Command: command,
},
}, nil)
})
require.Equal(t, command, s.configuration.Command)
}

Expand All @@ -104,6 +104,6 @@ func TestInjectDefinitionWithDependency(t *testing.T) {
Image: image,
},
},
}, nil)
})
require.Equal(t, s.Dependencies[0].Image, image)
}
10 changes: 5 additions & 5 deletions service/start.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,11 +69,11 @@ func (d *Dependency) Start(networkID string) (containerServiceID string, err err
Image: d.Image,
Args: d.Args,
Command: d.Command,
Env: xos.MapToEnv(xos.MergeMapEnvs(map[string]string{
"MESG_TOKEN": d.service.Hash,
"MESG_ENDPOINT": endpoint,
"MESG_ENDPOINT_TCP": endpoint,
}, d.EnvValue)),
Env: xos.EnvMergeSlices(d.Env, []string{
"MESG_TOKEN=" + d.service.Hash,
"MESG_ENDPOINT=" + endpoint,
"MESG_ENDPOINT_TCP=" + endpoint,
}),
Mounts: append(volumes, volumesFrom...),
Ports: d.extractPorts(),
Networks: []container.Network{
Expand Down
11 changes: 5 additions & 6 deletions service/start_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import (
"github.com/mesg-foundation/core/container"
"github.com/mesg-foundation/core/container/mocks"
"github.com/mesg-foundation/core/x/xnet"
"github.com/mesg-foundation/core/x/xos"
"github.com/stretchr/testify/require"
)

Expand Down Expand Up @@ -319,11 +318,11 @@ func mockStartService(d *Dependency, mc *mocks.Container,
Image: d.Image,
Command: d.Command,
Args: d.Args,
Env: xos.MapToEnv(map[string]string{
"MESG_TOKEN": d.service.Hash,
"MESG_ENDPOINT": endpoint,
"MESG_ENDPOINT_TCP": endpoint,
}),
Env: []string{
"MESG_TOKEN=" + d.service.Hash,
"MESG_ENDPOINT=" + endpoint,
"MESG_ENDPOINT_TCP=" + endpoint,
},
Mounts: append(volumes, volumesFrom...),
Ports: d.extractPorts(),
Networks: []container.Network{
Expand Down
41 changes: 32 additions & 9 deletions x/xos/env.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
package xos

import (
"fmt"
"os"
"sort"
"strings"
)

// GetenvDefault retrieves the value of the environment variable named by the key.
Expand All @@ -15,25 +15,48 @@ func GetenvDefault(key, fallback string) string {
return fallback
}

// MapToEnv transform a map of key value to a slice of env in the form "key=value".
// EnvMapToSlice transform a map of key value to a slice of env in the form "key=value".
// Env vars are sorted by names to get an accurate order while testing.
func MapToEnv(data map[string]string) []string {
env := make([]string, 0, len(data))
for key, value := range data {
env = append(env, fmt.Sprintf("%s=%s", key, value))
func EnvMapToSlice(values map[string]string) []string {
env := make([]string, 0, len(values))
for k, v := range values {
env = append(env, k+"="+v)
}
sort.Strings(env)
return env
}

// MergeMapEnvs merges multiple maps storing environment varialbes into single one.
// EnvSliceToMap transform a slice of key=value to a map.
func EnvSliceToMap(values []string) map[string]string {
env := make(map[string]string, len(values))
for _, v := range values {
if e := strings.SplitN(v, "=", 2); len(e) == 1 {
env[e[0]] = ""
} else {
env[e[0]] = e[1]
}
}
return env
}

// EnvMergeMaps merges multiple maps into single one.
// If the same key exist multiple time, it will be overwritten by the latest occurrence.
func MergeMapEnvs(envs ...map[string]string) map[string]string {
func EnvMergeMaps(values ...map[string]string) map[string]string {
env := make(map[string]string)
for _, e := range envs {
for _, e := range values {
for k, v := range e {
env[k] = v
}
}
return env
}

// EnvMergeSlices merges multiple slices into single one.
// If the same key exist multiple time, it will be added in occurrence order.
func EnvMergeSlices(values ...[]string) []string {
env := make([]string, 0, 16)
for _, v := range values {
env = append(env, v...)
}
return env
}
Loading

0 comments on commit 62934d5

Please sign in to comment.