Skip to content

Commit

Permalink
Merge pull request #181 from mesg-foundation/blocking-start-stop
Browse files Browse the repository at this point in the history
Make start and stop functions blocking
  • Loading branch information
NicolasMahe authored Jun 5, 2018
2 parents 0005c7c + 10be2d1 commit 20fbb11
Show file tree
Hide file tree
Showing 19 changed files with 172 additions and 95 deletions.
3 changes: 2 additions & 1 deletion .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ jobs:
- setup_remote_docker
- run: go get -t ./...
- run: docker swarm init
- run: env DAEMON.IMAGE=mesg/daemon:$CIRCLE_SHA1 go test -timeout 60s -p 1 -coverprofile=coverage.txt ./...
- run: docker pull nginx
- run: env DAEMON.IMAGE=mesg/daemon:$CIRCLE_SHA1 go test -timeout 180s -p 1 -coverprofile=coverage.txt ./...
- run: bash <(curl -s https://codecov.io/bash)

"publish_docker_version":
Expand Down
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
- (#174) Update CI to build version based on tags
- (#173) Use official Docker client
- (#175) Changed the struct to use to start docker service
- (#181) Daemon and Service start and stop functions wait for the docker container to actually run or stop.

#### Added
- (#174) Add CHANGELOG.md file
Expand Down
7 changes: 5 additions & 2 deletions cmd/daemon/start.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"fmt"

"github.com/logrusorgru/aurora"
"github.com/mesg-foundation/core/cmd/utils"
"github.com/mesg-foundation/core/daemon"
"github.com/spf13/cobra"
)
Expand All @@ -26,10 +27,12 @@ func startHandler(cmd *cobra.Command, args []string) {
fmt.Println(aurora.Green("Daemon is running"))
return
}
_, err = daemon.Start()
cmdUtils.ShowSpinnerForFunc(cmdUtils.SpinnerOptions{Text: "Starting daemon..."}, func() {
_, err = daemon.Start()
})
if err != nil {
fmt.Println(aurora.Red(err))
return
}
fmt.Println(aurora.Green("Daemon is starting"))
fmt.Println(aurora.Green("Daemon is running"))
}
8 changes: 6 additions & 2 deletions cmd/daemon/stop.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"fmt"

"github.com/logrusorgru/aurora"
"github.com/mesg-foundation/core/cmd/utils"
"github.com/mesg-foundation/core/daemon"
"github.com/spf13/cobra"
)
Expand All @@ -17,10 +18,13 @@ var Stop = &cobra.Command{
}

func stopHandler(cmd *cobra.Command, args []string) {
err := daemon.Stop()
var err error
cmdUtils.ShowSpinnerForFunc(cmdUtils.SpinnerOptions{Text: "Stopping daemon..."}, func() {
err = daemon.Stop()
})
if err != nil {
fmt.Println(aurora.Red(err))
return
}
fmt.Println(aurora.Green("Daemon is stopping"))
fmt.Println(aurora.Green("Daemon stopped"))
}
2 changes: 1 addition & 1 deletion cmd/service/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ To have more details, see the [detail command](mesg-core_service_detail.md).`,
}

func listHandler(cmd *cobra.Command, args []string) {
services, err := services.All()
services, err := services.All() // TODO: this should use the API
handleError(err)
for _, service := range services {
hash, _ := service.Hash()
Expand Down
10 changes: 7 additions & 3 deletions cmd/service/start.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"github.com/mesg-foundation/core/api/core"

"github.com/logrusorgru/aurora"
"github.com/mesg-foundation/core/cmd/utils"
"github.com/spf13/cobra"
)

Expand All @@ -25,9 +26,12 @@ var Start = &cobra.Command{
}

func startHandler(cmd *cobra.Command, args []string) {
_, err := cli.StartService(context.Background(), &core.StartServiceRequest{
ServiceID: args[0],
var err error
cmdUtils.ShowSpinnerForFunc(cmdUtils.SpinnerOptions{Text: "Starting service..."}, func() {
_, err = cli.StartService(context.Background(), &core.StartServiceRequest{
ServiceID: args[0],
})
})
handleError(err)
fmt.Println(aurora.Green("Service started"))
fmt.Println(aurora.Green("Service is running"))
}
8 changes: 6 additions & 2 deletions cmd/service/stop.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (

"github.com/logrusorgru/aurora"
"github.com/mesg-foundation/core/api/core"
"github.com/mesg-foundation/core/cmd/utils"
"github.com/spf13/cobra"
)

Expand All @@ -24,8 +25,11 @@ To have more explanation, see the page [stake explanation from the documentation
}

func stopHandler(cmd *cobra.Command, args []string) {
_, err := cli.StopService(context.Background(), &core.StopServiceRequest{
ServiceID: args[0],
var err error
cmdUtils.ShowSpinnerForFunc(cmdUtils.SpinnerOptions{Text: "Stopping service..."}, func() {
_, err = cli.StopService(context.Background(), &core.StopServiceRequest{
ServiceID: args[0],
})
})
handleError(err)
fmt.Println(aurora.Green("Service stopped"))
Expand Down
21 changes: 12 additions & 9 deletions cmd/service/test.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,25 +90,28 @@ func testHandler(cmd *cobra.Command, args []string) {
})
handleError(err)

_, err = cli.StartService(context.Background(), &core.StartServiceRequest{
ServiceID: deployment.ServiceID,
cmdUtils.ShowSpinnerForFunc(cmdUtils.SpinnerOptions{Text: "Starting service..."}, func() {
_, err = cli.StartService(context.Background(), &core.StartServiceRequest{
ServiceID: deployment.ServiceID,
})
})
handleError(err)
fmt.Println(aurora.Green("Service started"))

go listenEvents(deployment.ServiceID, cmd.Flag("event").Value.String())

go listenResults(deployment.ServiceID)

time.Sleep(10 * time.Second)

time.Sleep(time.Second)
executeTask(deployment.ServiceID, cmd.Flag("task").Value.String(), cmd.Flag("data").Value.String())

<-cmdUtils.WaitForCancel()

_, err = cli.StopService(context.Background(), &core.StopServiceRequest{
ServiceID: deployment.ServiceID,
cmdUtils.ShowSpinnerForFunc(cmdUtils.SpinnerOptions{Text: "Stopping service..."}, func() {
_, err = cli.StopService(context.Background(), &core.StopServiceRequest{
ServiceID: deployment.ServiceID,
})
})
fmt.Println(err)
handleError(err)
fmt.Println(aurora.Green("Service stopped"))
}

func init() {
Expand Down
8 changes: 8 additions & 0 deletions cmd/utils/spinner.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,11 @@ func StartSpinner(opts SpinnerOptions) (spinner *spinnerPkg.Spinner) {
}
return
}

// ShowSpinnerForFunc shows a spinner during the execution of the function
func ShowSpinnerForFunc(opts SpinnerOptions, function func()) {
s := StartSpinner(opts)
defer s.Stop()
function()
return
}
17 changes: 17 additions & 0 deletions container/container.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package container

import (
"context"
"time"

"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/filters"
Expand Down Expand Up @@ -48,3 +49,19 @@ func Status(namespace []string) (status StatusType, err error) {
}
return
}

// WaitForContainerStatus wait for the container to have the provided status until it reach the timeout
func WaitForContainerStatus(namespace []string, status StatusType) (err error) {
for {
var currentStatus StatusType
currentStatus, err = Status(namespace)
if err != nil {
break
}
if currentStatus == status {
break
}
time.Sleep(500 * time.Millisecond)
}
return
}
53 changes: 7 additions & 46 deletions container/container_test.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
package container

import (
"errors"
"fmt"
"testing"
"time"

"github.com/stvp/assert"
)
Expand All @@ -18,7 +15,7 @@ func TestFindContainer(t *testing.T) {
namespace := []string{"TestFindContainer"}
startTestService(namespace)
defer StopService(namespace)
<-WaitContainerStatus(namespace, RUNNING, time.Minute)
WaitForContainerStatus(namespace, RUNNING)
container, err := FindContainer(namespace)
assert.Nil(t, err)
assert.NotEqual(t, "", container.ID)
Expand All @@ -43,7 +40,7 @@ func TestContainerStatusRunning(t *testing.T) {
namespace := []string{"TestContainerStatusRunning"}
startTestService(namespace)
defer StopService(namespace)
<-WaitContainerStatus(namespace, RUNNING, time.Minute)
WaitForContainerStatus(namespace, RUNNING)
status, err := Status(namespace)
assert.Nil(t, err)
assert.Equal(t, status, RUNNING)
Expand All @@ -52,11 +49,9 @@ func TestContainerStatusRunning(t *testing.T) {
func TestContainerStatusStopped(t *testing.T) {
namespace := []string{"TestContainerStatusStopped"}
startTestService(namespace)
<-WaitContainerStatus(namespace, RUNNING, time.Minute)
fmt.Println("wait for running")
WaitForContainerStatus(namespace, RUNNING)
StopService(namespace)
<-WaitContainerStatus(namespace, STOPPED, time.Minute)
fmt.Println("wait for stop")
WaitForContainerStatus(namespace, STOPPED)
status, err := Status(namespace)
assert.Nil(t, err)
assert.Equal(t, status, STOPPED)
Expand All @@ -66,50 +61,16 @@ func TestWaitForContainerRunning(t *testing.T) {
namespace := []string{"TestWaitForContainerRunning"}
startTestService(namespace)
defer StopService(namespace)
err := <-WaitContainerStatus(namespace, RUNNING, time.Minute)
err := WaitForContainerStatus(namespace, RUNNING)
assert.Nil(t, err)
}

func TestWaitForContainerTimeout(t *testing.T) {
namespace := []string{"TestWaitForContainerTimeout"}
startTestService(namespace)
defer StopService(namespace)
err := <-WaitContainerStatus(namespace, RUNNING, time.Nanosecond)
assert.NotNil(t, err)
}

func TestWaitForContainerStopped(t *testing.T) {
namespace := []string{"TestWaitForContainerStopped"}
startTestService(namespace)
<-WaitContainerStatus(namespace, RUNNING, time.Minute)
WaitForContainerStatus(namespace, RUNNING)

StopService(namespace)
err := <-WaitContainerStatus(namespace, STOPPED, time.Minute)
err := WaitForContainerStatus(namespace, STOPPED)
assert.Nil(t, err)
}

// WaitContainerStatus wait for the container to have the provided status until it reach the timeout
func WaitContainerStatus(namespace []string, status StatusType, timeout time.Duration) (wait chan error) {
start := time.Now()
wait = make(chan error, 1)
go func() {
for {
currentStatus, err := Status(namespace)
if err != nil {
wait <- err
return
}
if currentStatus == status {
close(wait)
return
}
diff := time.Now().Sub(start)
if diff.Nanoseconds() >= int64(timeout) {
wait <- errors.New("Wait too long for the container, timeout reached")
return
}
time.Sleep(500 * time.Millisecond)
}
}()
return
}
12 changes: 10 additions & 2 deletions container/service_options.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package container

import (
"os"
"strconv"

"github.com/docker/docker/api/types/mount"
"github.com/docker/docker/api/types/swarm"
)
Expand Down Expand Up @@ -47,7 +50,7 @@ func (options *ServiceOptions) toSwarmServiceSpec() (service swarm.ServiceSpec)
},
Env: options.Env,
Args: options.Args,
Mounts: options.swarmMounts(),
Mounts: options.swarmMounts(false),
},
Networks: options.swarmNetworks(),
},
Expand All @@ -71,7 +74,12 @@ func (options *ServiceOptions) swarmPorts() (ports []swarm.PortConfig) {
return
}

func (options *ServiceOptions) swarmMounts() (mounts []mount.Mount) {
func (options *ServiceOptions) swarmMounts(force bool) (mounts []mount.Mount) {
// TOFIX: hack to prevent mount when in CircleCI (Mount in CircleCI doesn't work). Should use CircleCi with machine to fix this.
circleCI, errCircle := strconv.ParseBool(os.Getenv("CIRCLECI"))
if force == false && errCircle == nil && circleCI {
return
}
mounts = make([]mount.Mount, len(options.Mounts))
for i, m := range options.Mounts {
mounts[i] = mount.Mount{
Expand Down
2 changes: 1 addition & 1 deletion container/service_options_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ func TestServiceOptionMounts(t *testing.T) {
},
},
}
mounts := options.swarmMounts()
mounts := options.swarmMounts(true)
assert.Equal(t, 1, len(mounts))
assert.Equal(t, "source/file", mounts[0].Source)
assert.Equal(t, "target/file", mounts[0].Target)
Expand Down
23 changes: 15 additions & 8 deletions daemon/start.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,22 +11,28 @@ import (
// Start the docker daemon
func Start() (serviceID string, err error) {
running, err := IsRunning()
if err != nil {
if err != nil || running == true {
return
}
if running == true {
spec, err := serviceSpec()
if err != nil {
return
}
sharedNetworkID, err := container.SharedNetworkID()
serviceID, err = container.StartService(spec)
if err != nil {
return
}
return container.StartService(serviceSpec(sharedNetworkID))
err = container.WaitForContainerStatus(Namespace(), container.RUNNING)
return
}

func serviceSpec(networkID string) container.ServiceOptions {
return container.ServiceOptions{
Namespace: []string{name},
func serviceSpec() (spec container.ServiceOptions, err error) {
sharedNetworkID, err := container.SharedNetworkID()
if err != nil {
return
}
spec = container.ServiceOptions{
Namespace: Namespace(),
Image: viper.GetString(config.DaemonImage),
Env: []string{
"MESG.PATH=/mesg",
Expand All @@ -49,6 +55,7 @@ func serviceSpec(networkID string) container.ServiceOptions {
Published: 50052,
},
},
NetworksID: []string{networkID},
NetworksID: []string{sharedNetworkID},
}
return
}
Loading

0 comments on commit 20fbb11

Please sign in to comment.