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

Configure services with envs #641

Merged
merged 14 commits into from
Dec 20, 2018
15 changes: 9 additions & 6 deletions api/deploy.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,25 +25,27 @@ func DeployServiceStatusOption(statuses chan DeployStatus) DeployServiceOption {
}

// DeployService deploys a service from a gzipped tarball.
func (a *API) DeployService(r io.Reader, options ...DeployServiceOption) (*service.Service,
func (a *API) DeployService(r io.Reader, env map[string]string, options ...DeployServiceOption) (*service.Service,
NicolasMahe marked this conversation as resolved.
Show resolved Hide resolved
*importer.ValidationError, error) {
return newServiceDeployer(a, options...).FromGzippedTar(r)
return newServiceDeployer(a, env, options...).FromGzippedTar(r)
}

// DeployServiceFromURL deploys a service living at a Git host.
// Supported URL types:
// - https://github.com/mesg-foundation/service-ethereum
// - https://github.com/mesg-foundation/service-ethereum#branchName
func (a *API) DeployServiceFromURL(url string, options ...DeployServiceOption) (*service.Service,
func (a *API) DeployServiceFromURL(url string, env map[string]string, options ...DeployServiceOption) (*service.Service,
*importer.ValidationError, error) {
return newServiceDeployer(a, options...).FromGitURL(url)
return newServiceDeployer(a, env, options...).FromGitURL(url)
}

// serviceDeployer provides functionalities to deploy a MESG service.
type serviceDeployer struct {
// statuses receives status messages produced during deployment.
statuses chan DeployStatus

env map[string]string

api *API
}

Expand All @@ -70,9 +72,10 @@ type DeployStatus struct {
}

// newServiceDeployer creates a new serviceDeployer with given api and options.
func newServiceDeployer(api *API, options ...DeployServiceOption) *serviceDeployer {
func newServiceDeployer(api *API, env map[string]string, options ...DeployServiceOption) *serviceDeployer {
d := &serviceDeployer{
api: api,
env: env,
}
for _, option := range options {
option(d)
Expand Down Expand Up @@ -126,7 +129,7 @@ func (d *serviceDeployer) deploy(r io.Reader) (*service.Service, *importer.Valid
d.forwardDeployStatuses(statuses)
}()

s, err := service.New(r,
s, err := service.New(r, d.env,
NicolasMahe marked this conversation as resolved.
Show resolved Hide resolved
service.ContainerOption(d.api.container),
service.DeployStatusOption(statuses),
)
Expand Down
10 changes: 5 additions & 5 deletions api/deploy_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ func TestDeployService(t *testing.T) {
archive, err := xarchive.GzippedTar(path)
require.NoError(t, err)

service, validationError, err := a.DeployService(archive, DeployServiceStatusOption(statuses))
service, validationError, err := a.DeployService(archive, nil, DeployServiceStatusOption(statuses))
require.Nil(t, validationError)
require.NoError(t, err)
require.Len(t, service.Hash, 40)
Expand Down Expand Up @@ -76,7 +76,7 @@ func TestDeployInvalidService(t *testing.T) {
archive, err := xarchive.GzippedTar(path)
require.NoError(t, err)

service, validationError, err := a.DeployService(archive, DeployServiceStatusOption(statuses))
service, validationError, err := a.DeployService(archive, nil, DeployServiceStatusOption(statuses))
require.Nil(t, service)
require.NoError(t, err)
require.Equal(t, (&importer.ValidationError{}).Error(), validationError.Error())
Expand Down Expand Up @@ -114,7 +114,7 @@ func TestDeployServiceFromURL(t *testing.T) {
wg.Add(1)
go func() {
defer wg.Done()
service, validationError, err := a.DeployServiceFromURL(url, DeployServiceStatusOption(statuses))
service, validationError, err := a.DeployServiceFromURL(url, nil, DeployServiceStatusOption(statuses))
require.Nil(t, validationError)
require.NoError(t, err)
require.Len(t, service.Hash, 40)
Expand Down Expand Up @@ -156,7 +156,7 @@ func TestDeployServiceFromURL(t *testing.T) {
func TestCreateTempFolder(t *testing.T) {
a, _, closer := newAPIAndDockerTest(t)
defer closer()
deployer := newServiceDeployer(a)
deployer := newServiceDeployer(a, nil)

path, err := deployer.createTempDir()
defer os.RemoveAll(path)
Expand All @@ -167,7 +167,7 @@ func TestCreateTempFolder(t *testing.T) {
func TestRemoveTempFolder(t *testing.T) {
a, _, closer := newAPIAndDockerTest(t)
defer closer()
deployer := newServiceDeployer(a)
deployer := newServiceDeployer(a, nil)

path, _ := deployer.createTempDir()
err := os.RemoveAll(path)
Expand Down
2 changes: 1 addition & 1 deletion commands/commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ type ServiceExecutor interface {
ServiceByID(id string) (*coreapi.Service, error)
ServiceDeleteAll(deleteData bool) error
ServiceDelete(deleteData bool, ids ...string) error
ServiceDeploy(path string, statuses chan provider.DeployStatus) (id string, validationError, err error)
ServiceDeploy(path string, env map[string]string, statuses chan provider.DeployStatus) (id string, validationError, err error)
ServiceListenEvents(id, eventFilter string) (chan *coreapi.EventData, chan error, error)
ServiceListenResults(id, taskFilter, outputFilter string, tagFilters []string) (chan *coreapi.ResultData, chan error, error)
ServiceLogs(id string, dependencies ...string) (logs []*provider.Log, closer func(), err error)
Expand Down
18 changes: 9 additions & 9 deletions commands/mocks/Executor.go

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

13 changes: 10 additions & 3 deletions commands/provider/service_deployer.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ type deploymentResult struct {
}

// ServiceDeploy deploys service from given path.
func (p *ServiceProvider) ServiceDeploy(path string, statuses chan DeployStatus) (id string,
func (p *ServiceProvider) ServiceDeploy(path string, env map[string]string, statuses chan DeployStatus) (id string,
validationError, err error) {
stream, err := p.client.DeployService(context.Background())
if err != nil {
Expand All @@ -53,11 +53,12 @@ func (p *ServiceProvider) ServiceDeploy(path string, statuses chan DeployStatus)
if govalidator.IsURL(path) {
if err := stream.Send(&coreapi.DeployServiceRequest{
Value: &coreapi.DeployServiceRequest_Url{Url: path},
Env: env,
krhubert marked this conversation as resolved.
Show resolved Hide resolved
}); err != nil {
return "", nil, err
}
} else {
if err := deployServiceSendServiceContext(path, stream); err != nil {
if err := deployServiceSendServiceContext(path, env, stream); err != nil {
return "", nil, err
}
}
Expand All @@ -71,14 +72,20 @@ func (p *ServiceProvider) ServiceDeploy(path string, statuses chan DeployStatus)
return result.serviceID, result.validationError, result.err
}

func deployServiceSendServiceContext(path string, stream coreapi.Core_DeployServiceClient) error {
func deployServiceSendServiceContext(path string, env map[string]string, stream coreapi.Core_DeployServiceClient) error {
archive, err := archive.TarWithOptions(path, &archive.TarOptions{
Compression: archive.Gzip,
})
if err != nil {
return err
}

if len(env) > 0 {
if err := stream.Send(&coreapi.DeployServiceRequest{Env: env}); err != nil {
NicolasMahe marked this conversation as resolved.
Show resolved Hide resolved
return err
}
}

buf := make([]byte, 1024)
for {
n, err := archive.Read(buf)
Expand Down
7 changes: 5 additions & 2 deletions commands/service_deploy.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,15 @@ import (
"github.com/mesg-foundation/core/commands/provider"
"github.com/mesg-foundation/core/utils/pretty"
"github.com/mesg-foundation/core/x/xerrors"
"github.com/mesg-foundation/core/x/xpflag"
"github.com/spf13/cobra"
)

type serviceDeployCmd struct {
baseCmd

path string
env map[string]string

e ServiceExecutor
}
Expand All @@ -27,11 +29,12 @@ func newServiceDeployCmd(e ServiceExecutor) *serviceDeployCmd {
Long: `Deploy a service.
To get more information, see the [deploy page from the documentation](https://docs.mesg.com/guide/service/deploy-a-service.html)`,
Example: `mesg-core service deploy PATH_TO_SERVICE`,
Example: `mesg-core service deploy [PATH_TO_SERVICE|URL_TO_SERVICE]`,
PreRunE: c.preRunE,
RunE: c.runE,
Args: cobra.MaximumNArgs(1),
})
c.cmd.Flags().Var(xpflag.NewStringToStringValue(&c.env, nil), "env", "set env defined in mesg.yml (configuration.env)")
return c
}

Expand All @@ -52,7 +55,7 @@ func (c *serviceDeployCmd) runE(cmd *cobra.Command, args []string) error {
printDeployStatuses(statuses)
}()

id, validationError, err := c.e.ServiceDeploy(c.path, statuses)
id, validationError, err := c.e.ServiceDeploy(c.path, c.env, statuses)
wg.Wait()

pretty.DestroySpinner()
Expand Down
15 changes: 15 additions & 0 deletions commands/service_deploy_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package commands
NicolasMahe marked this conversation as resolved.
Show resolved Hide resolved

import (
"testing"

"github.com/stretchr/testify/require"
)

func TestServiceDeployCmdFlags(t *testing.T) {
c := newServiceDeployCmd(nil)

flags := c.cmd.Flags()
flags.Set("env", "a=1,b=2")
require.Equal(t, map[string]string{"a": "1", "b": "2"}, c.env)
}
5 changes: 4 additions & 1 deletion commands/service_dev.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"github.com/mesg-foundation/core/commands/provider"
"github.com/mesg-foundation/core/utils/pretty"
"github.com/mesg-foundation/core/x/xerrors"
"github.com/mesg-foundation/core/x/xpflag"
"github.com/mesg-foundation/core/x/xsignal"
"github.com/spf13/cobra"
)
Expand All @@ -21,6 +22,7 @@ type serviceDevCmd struct {
taskFilter string
outputFilter string
path string
env map[string]string

e ServiceExecutor
}
Expand All @@ -42,6 +44,7 @@ func newServiceDevCmd(e ServiceExecutor) *serviceDevCmd {
c.cmd.Flags().StringVarP(&c.eventFilter, "event-filter", "e", c.eventFilter, "Only log the data of the given event")
c.cmd.Flags().StringVarP(&c.taskFilter, "task-filter", "t", "", "Only log the result of the given task")
c.cmd.Flags().StringVarP(&c.outputFilter, "output-filter", "o", "", "Only log the data of the given output of a task result. If set, you also need to set the task in --task-filter")
c.cmd.Flags().Var(xpflag.NewStringToStringValue(&c.env, nil), "env", "set env defined in mesg.yml (configuration.env)")
return c
}

Expand All @@ -62,7 +65,7 @@ func (c *serviceDevCmd) runE(cmd *cobra.Command, args []string) error {
printDeployStatuses(statuses)
}()

id, validationError, err := c.e.ServiceDeploy(c.path, statuses)
id, validationError, err := c.e.ServiceDeploy(c.path, c.env, statuses)
wg.Wait()

pretty.DestroySpinner()
Expand Down
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
}
18 changes: 0 additions & 18 deletions container/service_options_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -123,21 +123,3 @@ func TestServiceOptionNetworks(t *testing.T) {
require.Equal(t, 1, len(networks[1].Aliases))
require.Equal(t, "test", networks[1].Aliases[0])
}

func contains(list []string, item string) bool {
for _, itemInList := range list {
if itemInList == item {
return true
}
}
return false
}

func TestMapToEnv(t *testing.T) {
env := MapToEnv(map[string]string{
"first": "first_value",
"second": "second_value",
})
require.True(t, contains(env, "first=first_value"))
require.True(t, contains(env, "second=second_value"))
}
3 changes: 2 additions & 1 deletion daemon/daemon.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"github.com/mesg-foundation/core/config"
"github.com/mesg-foundation/core/container"
"github.com/mesg-foundation/core/x/xnet"
"github.com/mesg-foundation/core/x/xos"
)

// Daemon is an interface that start, stop etc core as daemon.
Expand Down Expand Up @@ -61,7 +62,7 @@ func (d *ContainerDaemon) buildServiceOptions(sharedNetworkID string) container.
return container.ServiceOptions{
Namespace: []string{},
Image: d.cfg.Core.Image,
Env: container.MapToEnv(d.cfg.DaemonEnv()),
Env: xos.EnvMapToSlice(d.cfg.DaemonEnv()),
Mounts: []container.Mount{
{
Source: d.cfg.Docker.Socket,
Expand Down
Loading