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

System service instance #1087

Merged
merged 14 commits into from
Jul 2, 2019
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 7 additions & 10 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ const (
)

var (
instance *Config
once sync.Once
_instance *Config
once sync.Once
)

// Config contains all the configuration needed.
Expand All @@ -45,8 +45,6 @@ type Config struct {
InstanceRelativePath string
ExecutionRelativePath string
}

Service ServiceConfigGroup
}

// New creates a new config with default values.
Expand All @@ -66,32 +64,31 @@ func New() (*Config, error) {
c.Database.ServiceRelativePath = filepath.Join("database", "services", serviceDBVersion)
c.Database.InstanceRelativePath = filepath.Join("database", "instance", instanceDBVersion)
c.Database.ExecutionRelativePath = filepath.Join("database", "executions", executionDBVersion)
c.Service = c.getServiceConfigGroup()
return &c, nil
}

// Global returns a singleton of a Config after loaded ENV and validate the values.
func Global() (*Config, error) {
var err error
once.Do(func() {
instance, err = New()
_instance, err = New()
if err != nil {
return
}
if err = instance.Load(); err != nil {
if err = _instance.Load(); err != nil {
return
}
if err = instance.Prepare(); err != nil {
if err = _instance.Prepare(); err != nil {
return
}
})
if err != nil {
return nil, err
}
if err := instance.Validate(); err != nil {
if err := _instance.Validate(); err != nil {
return nil, err
}
return instance, nil
return _instance, nil
}

// Load reads config from environmental variables.
Expand Down
72 changes: 37 additions & 35 deletions config/services.go
Original file line number Diff line number Diff line change
@@ -1,17 +1,22 @@
package config

import "github.com/mesg-foundation/core/hash"
import (
"encoding/json"

// Default endpoints to access services. These endpoints are overritten by the build
// Use the following format for the variable name: "[Service]URL" (where Service is the name of the service capitalized)
// The service name should be the name of the directory inside `systemservices` but capitalized
"github.com/mesg-foundation/core/instance"
"github.com/mesg-foundation/core/service"
)

// Default compiled version of the service. These compiled versions are overritten by the build
// Use the following format for the variable name: "[service]Compiled" (where service is the name of the service)
// The service name should be the name of the directory inside `systemservices`
// example:
// var (
// BarURL string
// barCompiled string
// )
var (
EthwalletURL string
MarketplaceURL string
ethwalletCompiled string
antho1404 marked this conversation as resolved.
Show resolved Hide resolved
marketplaceCompiled string
)

// Env to override on the system services
Expand All @@ -23,41 +28,38 @@ var (

// ServiceConfig contains information related to services that the config knows about
type ServiceConfig struct {
URL string
Env map[string]string
Sid string
Hash hash.Hash
}

// ServiceConfigWithKey contains information related to services that the config knows about and their key
type ServiceConfigWithKey struct {
*ServiceConfig
Key string
}

// ServiceConfigGroup is the struct that contains all the `ServiceConfig` related to the config
type ServiceConfigGroup struct {
Ethwallet ServiceConfig
Marketplace ServiceConfig
Key string
Env map[string]string
Definition *service.Service
Instance *instance.Instance
}

// getServiceConfigGroup return the config for all services.
// DO NOT USE STRING HERE but variable defined on top of this file `XxxURL` for config injection
func (c *Config) getServiceConfigGroup() ServiceConfigGroup {
return ServiceConfigGroup{
Ethwallet: ServiceConfig{URL: EthwalletURL},
Marketplace: ServiceConfig{URL: MarketplaceURL, Env: map[string]string{
// Services return the config for all services.
func (c *Config) Services() ([]ServiceConfig, error) {
serviceConfigs := make([]ServiceConfig, 0)
if marketplaceCompiled != "" {
marketplace, err := c.createServiceConfig("Marketplace", marketplaceCompiled, map[string]string{
"MARKETPLACE_ADDRESS": EnvMarketplaceAddress,
"TOKEN_ADDRESS": EnvMarketplaceToken,
"PROVIDER_ENDPOINT": EnvMarketplaceEndpoint,
}},
})
if err != nil {
return nil, err
}
serviceConfigs = append(serviceConfigs, marketplace)
}
return serviceConfigs, nil
}

// Services returns all services that the configuration package is aware of
func (c *Config) Services() []*ServiceConfigWithKey {
return []*ServiceConfigWithKey{
{&c.Service.Ethwallet, "ethwallet"},
{&c.Service.Marketplace, "marketplace"},
func (c *Config) createServiceConfig(key string, compilatedJSON string, env map[string]string) (ServiceConfig, error) {
var srv service.Service
if err := json.Unmarshal([]byte(compilatedJSON), &srv); err != nil {
return ServiceConfig{}, err
}
srv.Configuration.Key = service.MainServiceKey
return ServiceConfig{
Key: key,
Definition: &srv,
Env: env,
}, nil
}
132 changes: 78 additions & 54 deletions core/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,20 @@ package main

import (
"path/filepath"
"sync"

"github.com/mesg-foundation/core/config"
"github.com/mesg-foundation/core/container"
"github.com/mesg-foundation/core/database"
"github.com/mesg-foundation/core/hash"
"github.com/mesg-foundation/core/logger"
"github.com/mesg-foundation/core/sdk"
instancesdk "github.com/mesg-foundation/core/sdk/instance"
servicesdk "github.com/mesg-foundation/core/sdk/service"
"github.com/mesg-foundation/core/server/grpc"
"github.com/mesg-foundation/core/version"
"github.com/mesg-foundation/core/x/xerrors"
"github.com/mesg-foundation/core/x/xos"
"github.com/mesg-foundation/core/x/xsignal"
"github.com/sirupsen/logrus"
)
Expand Down Expand Up @@ -65,54 +71,72 @@ func initDependencies() (*dependencies, error) {
}, nil
}

// func deployCoreServices(config *config.Config, sdk *sdk.SDK) error {
// for _, service := range config.Services() {
// logrus.Infof("Deploying service %q from %q", service.Key, service.URL)
// s, valid, err := sdk.DeployServiceFromURL(service.URL, service.Env)
// if valid != nil {
// return valid
// }
// if err != nil {
// return err
// }
// service.Sid = s.Sid
// service.Hash = s.Hash
// logrus.Infof("Service %q deployed with hash %q", service.Key, service.Hash)
// if err := sdk.StartService(s.Hash); err != nil {
// return err
// }
// }
// return nil
// }

// func stopRunningServices(sdk *sdk.SDK) error {
// services, err := sdk.ListServices()
// if err != nil {
// return err
// }
// var (
// serviceLen = len(services)
// errC = make(chan error, serviceLen)
// wg sync.WaitGroup
// )
// wg.Add(serviceLen)
// for _, service := range services {
// go func(hash hash.Hash) {
// defer wg.Done()
// err := sdk.StopService(hash)
// if err != nil {
// errC <- err
// }
// }(service.Hash)
// }
// wg.Wait()
// close(errC)
// var errs xerrors.Errors
// for err := range errC {
// errs = append(errs, err)
// }
// return errs.ErrorOrNil()
// }
func deployCoreServices(config *config.Config, sdk *sdk.SDK) error {
services, err := config.Services()
if err != nil {
return err
}
for _, serviceConfig := range services {
logrus.Infof("Deploying service %q", serviceConfig.Definition.Sid)
srv, err := sdk.Service.Create(serviceConfig.Definition)
if err != nil {
existsError, ok := err.(*servicesdk.AlreadyExistsError)
if ok {
srv, err = sdk.Service.Get(existsError.Hash)
if err != nil {
return err
}
} else {
return err
}
}
logrus.Infof("Service %q deployed with hash %q", srv.Sid, srv.Hash)
instance, err := sdk.Instance.Create(srv.Hash, xos.EnvMapToSlice(serviceConfig.Env))
if err != nil {
existsError, ok := err.(*instancesdk.AlreadyExistsError)
if ok {
instance, err = sdk.Instance.Get(existsError.Hash)
if err != nil {
return err
}
} else {
return err
}
}
serviceConfig.Instance = instance
logrus.Infof("Instance started with hash %q", instance.Hash)
}
return nil
}

func stopRunningServices(sdk *sdk.SDK) error {
instances, err := sdk.Instance.List(&instancesdk.Filter{})
if err != nil {
return err
}
var (
instancesLen = len(instances)
errC = make(chan error, instancesLen)
wg sync.WaitGroup
)
wg.Add(instancesLen)
for _, instance := range instances {
go func(hash hash.Hash) {
defer wg.Done()
err := sdk.Instance.Delete(hash, false)
if err != nil {
errC <- err
}
}(instance.Hash)
}
wg.Wait()
close(errC)
var errs xerrors.Errors
for err := range errC {
errs = append(errs, err)
}
return errs.ErrorOrNil()
}

func main() {
dep, err := initDependencies()
Expand All @@ -124,9 +148,9 @@ func main() {
logger.Init(dep.config.Log.Format, dep.config.Log.Level, dep.config.Log.ForceColors)

// init system services.
// if err := deployCoreServices(dep.config, dep.sdk); err != nil {
// logrus.Fatalln(err)
// }
if err := deployCoreServices(dep.config, dep.sdk); err != nil {
logrus.Fatalln(err)
}

// init gRPC server.
server := grpc.New(dep.sdk)
Expand All @@ -140,8 +164,8 @@ func main() {
}()

<-xsignal.WaitForInterrupt()
// if err := stopRunningServices(dep.sdk); err != nil {
// logrus.Fatalln(err)
// }
if err := stopRunningServices(dep.sdk); err != nil {
logrus.Fatalln(err)
}
server.Close()
}
49 changes: 10 additions & 39 deletions dev
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ MESG_PATH=${MESG_PATH:-$HOME/.mesg}
MESG_LOG_FORMAT=${MESG_LOG_FORMAT:-text}
MESG_LOG_FORCECOLORS=${MESG_LOG_FORCECOLORS:-false}
MESG_LOG_LEVEL=${MESG_LOG_LEVEL:-debug}
MESG_SERVICE_SERVER=ipfs.app.mesg.com
NicolasMahe marked this conversation as resolved.
Show resolved Hide resolved

VERSION=local
LDFLAGS="-X 'github.com/mesg-foundation/core/version.Version=$VERSION'"
Expand All @@ -19,51 +20,22 @@ LDFLAGS+=" -X 'github.com/mesg-foundation/core/config.EnvMarketplaceToken=0x5861

MESG_SERVER_PORT=${MESG_SERVER_PORT:-50052}

# if set to true the docker with system services will be started.
MESG_SERVICE_SERVER_ON=${MESG_SERVICE_SERVER_ON:-true}
MESG_SERVICE_SERVER="engine-service-server"


networkExists=$(docker network list -f name=engine -f driver=overlay -q)
if [ "$networkExists" == "" ]; then
docker network create --driver overlay engine --label com.docker.stack.namespace=engine
fi

function deleteServiceServer {
rm -rf tmp-systemservices
if [ "$MESG_SERVICE_SERVER_ON" = true ]; then
if docker service list | grep -q engine-service-server; then
docker service rm $MESG_SERVICE_SERVER
fi
fi
}

deleteServiceServer
mkdir -p tmp-systemservices
for i in systemservices/* ; do
if [ -d "$i" ]; then
echo "Creating archive for $i..."
cd $i
file=$(basename "$i")
tar -czf ../../tmp-systemservices/$file.tar.gz --exclude-from=.dockerignore .
varname="$(tr '[:lower:]' '[:upper:]' <<< ${file:0:1})${file:1}"
LDFLAGS+=" -X 'github.com/mesg-foundation/core/config.${varname}URL=http://$MESG_SERVICE_SERVER/$file.tar.gz'"
cd ../..
# from scripts/build-core.sh
NicolasMahe marked this conversation as resolved.
Show resolved Hide resolved
# upload system services
for s in systemservices/* ; do
if [ -d "$s" ]; then
pushd $s > /dev/null
name=$(basename "$s")
varname="${name}"
LDFLAGS+=" -X 'github.com/mesg-foundation/core/config.${varname}Compiled=$(cat compiled.json)'"
Copy link
Member

@NicolasMahe NicolasMahe Jul 2, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

also, why not compiling the service also in this script? like scripts/build-engine.sh is doing? because of optimization?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes because of optimization but not only, we should only have the compiled version of the service and if we have the compiled version there is no need of having the sources of the system service in the engine and in that case, the compiled version is a snapshot of the exact version we want from this system service that we can manually update with something like

mesg-cli service:compile https://github.com/mesg-foundation/service-marketplace > systemservices/marketplace.json

popd > /dev/null
fi
done
echo "FROM nginx:alpine" >> tmp-systemservices/Dockerfile
echo "COPY . /usr/share/nginx/html" >> tmp-systemservices/Dockerfile

if [ "$MESG_SERVICE_SERVER_ON" = true ]; then
echo "set up system services server"
docker build tmp-systemservices -t $MESG_SERVICE_SERVER

docker service create -d \
-p 8080:8080 \
--name $MESG_SERVICE_SERVER \
--network engine \
$MESG_SERVICE_SERVER
fi

echo "compile engine"
GOOS=linux GOARCH=amd64 go build -o ./bin/engine -ldflags="$LDFLAGS" core/main.go
Expand Down Expand Up @@ -105,7 +77,6 @@ fi
trap onexit EXIT INT

function onexit {
deleteServiceServer
docker service rm $MESG_NAME
}

Expand Down
Loading