init repository
This commit is contained in:
@@ -0,0 +1,211 @@
|
||||
package deployer
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/container"
|
||||
"github.com/docker/docker/api/types/filters"
|
||||
"github.com/docker/docker/api/types/swarm"
|
||||
"github.com/docker/docker/client"
|
||||
"github.com/docker/go-connections/nat"
|
||||
"github.com/rs/zerolog/log"
|
||||
|
||||
localcli "localenv/client"
|
||||
"localenv/services"
|
||||
)
|
||||
|
||||
const (
|
||||
SwarmImageName string = "localenv-swarm:latest"
|
||||
SwarmContainerName string = "localenv-swarm"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrSwarmNotFound = errors.New("unable to find the swarm")
|
||||
ErrSwarmClientInit = errors.New("swarm client is not initialized")
|
||||
|
||||
ImagesDeps = []string{
|
||||
services.PostgresImageName,
|
||||
services.RabbitMQImageName,
|
||||
services.NginxImageName,
|
||||
services.MailhogImageName,
|
||||
}
|
||||
)
|
||||
|
||||
type Deployer struct {
|
||||
swarm Swarm
|
||||
cli *client.Client
|
||||
}
|
||||
|
||||
func NewDeployer(ctx context.Context, cli *client.Client) (Deployer, error) {
|
||||
var deployer Deployer
|
||||
deployer.cli = cli
|
||||
|
||||
if err := deployer.init(ctx); err != nil {
|
||||
return deployer, err
|
||||
}
|
||||
|
||||
return deployer, nil
|
||||
}
|
||||
|
||||
func (d Deployer) getSwarm(ctx context.Context) (string, error) {
|
||||
filterArgs := filters.NewArgs()
|
||||
filterArgs.Add("name", SwarmContainerName)
|
||||
filterArgs.Add("ancestor", SwarmImageName)
|
||||
|
||||
options := types.ContainerListOptions{
|
||||
Filters: filterArgs,
|
||||
All: true,
|
||||
}
|
||||
|
||||
containers, err := d.cli.ContainerList(ctx, options)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if len(containers) == 0 {
|
||||
return "", ErrSwarmNotFound
|
||||
}
|
||||
|
||||
return containers[0].ID, nil
|
||||
}
|
||||
|
||||
func (d Deployer) createSwarm(ctx context.Context) (string, error) {
|
||||
containerConfig := container.Config{
|
||||
Image: SwarmImageName,
|
||||
ExposedPorts: nat.PortSet{
|
||||
"4523/tcp": struct{}{},
|
||||
"4443/tcp": struct{}{},
|
||||
"15672/tcp": struct{}{},
|
||||
},
|
||||
}
|
||||
|
||||
hostConfig := container.HostConfig{
|
||||
Runtime: "sysbox-runc",
|
||||
PortBindings: nat.PortMap{
|
||||
// swarm dockerd
|
||||
"4523/tcp": []nat.PortBinding{
|
||||
{
|
||||
HostIP: "0.0.0.0",
|
||||
HostPort: "4523",
|
||||
},
|
||||
},
|
||||
// nginx ssl
|
||||
"4443/tcp": []nat.PortBinding{
|
||||
{
|
||||
HostIP: "0.0.0.0",
|
||||
HostPort: "4443",
|
||||
},
|
||||
},
|
||||
// rabbitmq admin interface
|
||||
"15672/tcp": []nat.PortBinding{
|
||||
{
|
||||
HostIP: "0.0.0.0",
|
||||
HostPort: "15672",
|
||||
},
|
||||
},
|
||||
},
|
||||
NetworkMode: "bridge",
|
||||
}
|
||||
|
||||
resp, err := d.cli.ContainerCreate(ctx, &containerConfig, &hostConfig, nil, nil, SwarmContainerName)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
log.Info().Msg("swarm created successfully")
|
||||
return resp.ID, nil
|
||||
}
|
||||
|
||||
func (d Deployer) initSwarm(ctx context.Context) error {
|
||||
req := swarm.InitRequest{
|
||||
ListenAddr: "0.0.0.0:2377",
|
||||
AdvertiseAddr: "127.0.0.1",
|
||||
}
|
||||
|
||||
if _, err := d.swarm.cli.SwarmInit(ctx, req); err != nil {
|
||||
if strings.Contains(err.Error(), "part of a swarm") {
|
||||
log.Info().Msg("swarm already initialized")
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d Deployer) StopSwarm(ctx context.Context) error {
|
||||
if d.swarm.ID == "" {
|
||||
log.Warn().Msg("no swarm registered, can't stop")
|
||||
return nil
|
||||
}
|
||||
|
||||
options := container.StopOptions{}
|
||||
|
||||
if err := d.cli.ContainerStop(ctx, d.swarm.ID, options); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
log.Info().Msg("swarm stopped successfully")
|
||||
return nil
|
||||
}
|
||||
|
||||
// TODO(rmanach): get a child context instead
|
||||
func (d *Deployer) init(ctx context.Context) error {
|
||||
swarmID, err := d.getSwarm(ctx)
|
||||
if err != nil {
|
||||
if !errors.Is(err, ErrSwarmNotFound) {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
s := Swarm{swarmID, nil}
|
||||
|
||||
if swarmID == "" {
|
||||
id, err := d.createSwarm(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
s.ID = id
|
||||
}
|
||||
|
||||
if err := d.cli.ContainerStart(ctx, s.ID, types.ContainerStartOptions{}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cli, errInit := localcli.GetSwarmClient()
|
||||
if errInit != nil {
|
||||
if err := d.StopSwarm(ctx); err != nil {
|
||||
log.Err(err).Msg("unable to stop the swarm")
|
||||
}
|
||||
return errInit
|
||||
}
|
||||
|
||||
s.cli = cli
|
||||
d.swarm = s
|
||||
|
||||
if err := d.initSwarm(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
log.Info().Msg("deployer successfully initialized")
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *Deployer) Deploy(ctx context.Context) error {
|
||||
if err := d.swarm.deployServices(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *Deployer) GetSwarmCLI() (*client.Client, error) {
|
||||
if d.swarm.cli == nil {
|
||||
return nil, ErrSwarmClientInit
|
||||
}
|
||||
|
||||
return d.swarm.cli, nil
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
package deployer
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"localenv/services"
|
||||
|
||||
"localenv/utils"
|
||||
|
||||
"github.com/docker/docker/client"
|
||||
"github.com/docker/docker/errdefs"
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
type Swarm struct {
|
||||
ID string
|
||||
cli *client.Client
|
||||
}
|
||||
|
||||
func (s Swarm) deployServices(ctx context.Context) error {
|
||||
if err := s.createNetworks(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := s.deployRabbitMQ(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := s.deployMailhog(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := s.deployNginx(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s Swarm) createNetworks(ctx context.Context) error {
|
||||
log.Info().Str("network", services.NetworkName).Msg("creating network...")
|
||||
if err := utils.CreateNetwork(ctx, s.cli, services.NetworkName); err != nil {
|
||||
if !errdefs.IsConflict(err) {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s Swarm) deployRabbitMQ(ctx context.Context) error {
|
||||
rabbitmq := services.NewRabbitMQ()
|
||||
return rabbitmq.Deploy(ctx, s.cli)
|
||||
}
|
||||
|
||||
func (s Swarm) deployNginx(ctx context.Context) error {
|
||||
nginx := services.NewNginx()
|
||||
return nginx.Deploy(ctx, s.cli)
|
||||
}
|
||||
|
||||
func (s Swarm) deployMailhog(ctx context.Context) error {
|
||||
mailhog := services.NewMailhog()
|
||||
return mailhog.Deploy(ctx, s.cli)
|
||||
}
|
||||
Reference in New Issue
Block a user