Skip to content

Commit

Permalink
Merge pull request #580 from mesg-foundation/refactor/daemon-newable
Browse files Browse the repository at this point in the history
Make daemon newable
  • Loading branch information
ilgooz authored Nov 29, 2018
2 parents 0704b40 + cd2f840 commit cb387ac
Show file tree
Hide file tree
Showing 20 changed files with 224 additions and 336 deletions.
13 changes: 7 additions & 6 deletions commands/provider/core_provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,20 +14,21 @@ import (

// CoreProvider is a struct that provides all methods required by core command.
type CoreProvider struct {
d daemon.Daemon
client coreapi.CoreClient
}

// NewCoreProvider creates new CoreProvider.
func NewCoreProvider(client coreapi.CoreClient) *CoreProvider {
func NewCoreProvider(client coreapi.CoreClient, d daemon.Daemon) *CoreProvider {
return &CoreProvider{
client: client,
d: d,
}
}

// Start starts core daemon.
func (p *CoreProvider) Start() error {
_, err := daemon.Start()
return err
return p.d.Start()
}

// Stop stops core daemon and all running services.
Expand Down Expand Up @@ -64,7 +65,7 @@ func (p *CoreProvider) Stop() error {
errs = append(errs, err)
}

if err := daemon.Stop(); err != nil {
if err := p.d.Stop(); err != nil {
errs = append(errs, err)
}

Expand All @@ -73,10 +74,10 @@ func (p *CoreProvider) Stop() error {

// Status returns daemon status.
func (p *CoreProvider) Status() (container.StatusType, error) {
return daemon.Status()
return p.d.Status()
}

// Logs returns daemon logs reader.
func (p *CoreProvider) Logs() (io.ReadCloser, error) {
return daemon.Logs()
return p.d.Logs()
}
5 changes: 3 additions & 2 deletions commands/provider/provider.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package provider

import (
"github.com/mesg-foundation/core/daemon"
"github.com/mesg-foundation/core/protobuf/coreapi"
)

Expand All @@ -12,9 +13,9 @@ type Provider struct {
}

// New creates Provider based on given CoreClient.
func New(c coreapi.CoreClient) *Provider {
func New(c coreapi.CoreClient, d daemon.Daemon) *Provider {
return &Provider{
CoreProvider: NewCoreProvider(c),
CoreProvider: NewCoreProvider(c, d),
ServiceProvider: NewServiceProvider(c),
WorkflowProvider: NewWorkflowProvider(c),
}
Expand Down
19 changes: 18 additions & 1 deletion container/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,15 @@ func (c *DockerContainer) FindService(namespace []string) (swarm.Service, error)

// StartService starts a docker service.
func (c *DockerContainer) StartService(options ServiceOptions) (serviceID string, err error) {
status, err := c.Status(options.Namespace)
if err != nil {
return "", err
}
if status == RUNNING {
service, err := c.FindService(options.Namespace)
return service.ID, err
}

service := options.toSwarmServiceSpec(c)
ctx, cancel := context.WithTimeout(context.Background(), c.callTimeout)
defer cancel()
Expand All @@ -50,7 +59,15 @@ func (c *DockerContainer) StartService(options ServiceOptions) (serviceID string
}

// StopService stops a docker service.
func (c *DockerContainer) StopService(namespace []string) (err error) {
func (c *DockerContainer) StopService(namespace []string) error {
status, err := c.Status(namespace)
if err != nil {
return err
}
if status == STOPPED {
return nil
}

ctx, cancel := context.WithTimeout(context.Background(), c.callTimeout)
defer cancel()
container, err := c.FindContainer(namespace)
Expand Down
13 changes: 7 additions & 6 deletions container/service_integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,15 +29,16 @@ func TestIntegrationStartService(t *testing.T) {
require.NotEqual(t, "", serviceID)
}

func TestIntegrationStartService2Times(t *testing.T) {
func TestIntegrationStartServiceTwice(t *testing.T) {
c, err := New()
require.NoError(t, err)
namespace := []string{"TestStartService2Times"}
startTestService(namespace)
namespace := []string{"TestStartServiceTwice"}
id1, err := startTestService(namespace)
require.NoError(t, err)
defer c.StopService(namespace)
serviceID, err := startTestService(namespace)
require.Error(t, err)
require.Equal(t, "", serviceID)
id2, err := startTestService(namespace)
require.NoError(t, err)
require.Equal(t, id1, id2)
}

func TestIntegrationStopService(t *testing.T) {
Expand Down
3 changes: 3 additions & 0 deletions container/service_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
)

func TestStartService(t *testing.T) {
t.Skip("put back when dockertest will be replaced with testify.Mock")
namespace := []string{"namespace"}
containerID := "id"
options := ServiceOptions{
Expand All @@ -35,6 +36,8 @@ func TestStartService(t *testing.T) {
}

func TestStopService(t *testing.T) {
t.Skip("put back when dockertest will be replaced with testify.Mock")

namespace := []string{"namespace"}
dt := dockertest.New()
c, _ := New(ClientOption(dt.Client()))
Expand Down
92 changes: 92 additions & 0 deletions daemon/daemon.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
package daemon

import (
"io"
"path/filepath"

"github.com/mesg-foundation/core/config"
"github.com/mesg-foundation/core/container"
"github.com/mesg-foundation/core/x/xnet"
)

// Daemon is an interface that start, stop etc core as daemon.
type Daemon interface {
Start() error
Stop() error
Status() (container.StatusType, error)
Logs() (io.ReadCloser, error)
}

// ContainerDaemon run core as container.
type ContainerDaemon struct {
c container.Container
cfg *config.Config
}

// NewContainerDaemon creates new dameon that will be run in container.
func NewContainerDaemon(cfg *config.Config, c container.Container) *ContainerDaemon {
return &ContainerDaemon{
c: c,
cfg: cfg,
}
}

// Start starts the docker core.
func (d *ContainerDaemon) Start() error {
sharedNetworkID, err := d.c.SharedNetworkID()
if err != nil {
return err
}
_, err = d.c.StartService(d.buildServiceOptions(sharedNetworkID))
return err
}

// Stop stops the MESG Core docker container.
func (d *ContainerDaemon) Stop() error {
return d.c.StopService([]string{})
}

// Status returns the Status of the docker service of the daemon.
func (d *ContainerDaemon) Status() (container.StatusType, error) {
return d.c.Status([]string{})
}

// Logs returns the core's docker service logs.
func (d *ContainerDaemon) Logs() (io.ReadCloser, error) {
return d.c.ServiceLogs([]string{})
}

func (d *ContainerDaemon) buildServiceOptions(sharedNetworkID string) container.ServiceOptions {
_, port, _ := xnet.SplitHostPort(d.cfg.Server.Address)
return container.ServiceOptions{
Namespace: []string{},
Image: d.cfg.Core.Image,
Env: container.MapToEnv(d.cfg.DaemonEnv()),
Mounts: []container.Mount{
{
Source: d.cfg.Docker.Socket,
Target: d.cfg.Docker.Socket,
Bind: true,
},
{
Source: d.cfg.Core.Path,
Target: d.cfg.Docker.Core.Path,
Bind: true,
},
{
Source: filepath.Join(d.cfg.Core.Path, d.cfg.SystemServices.RelativePath),
Target: filepath.Join(d.cfg.Docker.Core.Path, d.cfg.SystemServices.RelativePath),
Bind: true,
},
},
Ports: []container.Port{
{
Target: uint32(port),
Published: uint32(port),
},
},
Networks: []container.Network{
{ID: sharedNetworkID},
},
}
}
80 changes: 80 additions & 0 deletions daemon/daemon_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
package daemon

import (
"testing"

"github.com/mesg-foundation/core/config"
"github.com/mesg-foundation/core/container"
"github.com/mesg-foundation/core/container/mocks"
"github.com/mesg-foundation/core/x/xnet"
"github.com/stretchr/testify/require"
)

func TestStart(t *testing.T) {
cfg, _ := config.Global()
c := &mocks.Container{}
d := NewContainerDaemon(cfg, c)

c.On("SharedNetworkID").Return("1", nil)
c.On("StartService", d.buildServiceOptions("1")).Return("1", nil)
require.NoError(t, d.Start())
c.AssertExpectations(t)
}

func TestStop(t *testing.T) {
cfg, _ := config.Global()
c := &mocks.Container{}
d := NewContainerDaemon(cfg, c)

c.On("StopService", []string{}).Return(nil)
require.NoError(t, d.Stop())
c.AssertExpectations(t)
}

func TestStatus(t *testing.T) {
cfg, _ := config.Global()
c := &mocks.Container{}
d := NewContainerDaemon(cfg, c)

c.On("Status", []string{}).Return(container.STOPPED, nil)
status, err := d.Status()
require.NoError(t, err)
require.Equal(t, container.STOPPED, status)
c.AssertExpectations(t)
}

func TestLogs(t *testing.T) {
cfg, _ := config.Global()
c := &mocks.Container{}
d := NewContainerDaemon(cfg, c)

c.On("ServiceLogs", []string{}).Return(nil, nil)
_, err := d.Logs()
require.NoError(t, err)
c.AssertExpectations(t)
}

func TestBuildServiceOptions(t *testing.T) {
cfg, _ := config.Global()
c := &mocks.Container{}
d := NewContainerDaemon(cfg, c)

spec := d.buildServiceOptions("")
require.Equal(t, []string{}, spec.Namespace)
// Make sure that the config directory is passed in parameter to write on the same folder
require.Contains(t, spec.Env, "MESG_LOG_LEVEL=info")
require.Contains(t, spec.Env, "MESG_LOG_FORMAT=text")
require.Contains(t, spec.Env, "MESG_CORE_PATH="+cfg.Docker.Core.Path)
// Ensure that the port is shared
_, port, _ := xnet.SplitHostPort(cfg.Server.Address)
require.Equal(t, spec.Ports[0].Published, uint32(port))
require.Equal(t, spec.Ports[0].Target, uint32(port))
// Ensure that the docker socket is shared in the core
require.Equal(t, spec.Mounts[0].Source, cfg.Docker.Socket)
require.Equal(t, spec.Mounts[0].Target, cfg.Docker.Socket)
require.True(t, spec.Mounts[0].Bind)
// Ensure that the host users folder is sync with the core
require.Equal(t, spec.Mounts[1].Source, cfg.Core.Path)
require.Equal(t, spec.Mounts[1].Target, cfg.Docker.Core.Path)
require.True(t, spec.Mounts[1].Bind)
}
18 changes: 0 additions & 18 deletions daemon/init.go

This file was deleted.

10 changes: 0 additions & 10 deletions daemon/logs.go

This file was deleted.

14 changes: 0 additions & 14 deletions daemon/logs_test.go

This file was deleted.

Loading

0 comments on commit cb387ac

Please sign in to comment.