2017-09-26 12:50:09 +00:00
|
|
|
package biz
|
|
|
|
|
|
|
|
import (
|
2021-12-06 12:24:22 +00:00
|
|
|
"context"
|
2018-04-16 09:21:20 +00:00
|
|
|
"strings"
|
|
|
|
|
2021-12-06 12:24:22 +00:00
|
|
|
"github.com/cuigh/auxo/errors"
|
2017-09-26 12:50:09 +00:00
|
|
|
"github.com/cuigh/auxo/net/web"
|
|
|
|
"github.com/cuigh/swirl/dao"
|
2021-12-06 12:24:22 +00:00
|
|
|
"github.com/cuigh/swirl/docker"
|
|
|
|
"github.com/cuigh/swirl/docker/compose"
|
|
|
|
"github.com/cuigh/swirl/misc"
|
2017-09-26 12:50:09 +00:00
|
|
|
)
|
|
|
|
|
2021-12-06 12:24:22 +00:00
|
|
|
type StackBiz interface {
|
2022-01-06 08:54:14 +00:00
|
|
|
Search(ctx context.Context, name, filter string) (stacks []*dao.Stack, err error)
|
|
|
|
Find(ctx context.Context, name string) (stack *dao.Stack, err error)
|
|
|
|
Delete(ctx context.Context, name string, user web.User) (err error)
|
|
|
|
Shutdown(ctx context.Context, name string, user web.User) (err error)
|
|
|
|
Deploy(ctx context.Context, name string, user web.User) (err error)
|
|
|
|
Create(ctx context.Context, s *dao.Stack, user web.User) (err error)
|
|
|
|
Update(ctx context.Context, s *dao.Stack, user web.User) (err error)
|
2021-12-06 12:24:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func NewStack(d *docker.Docker, s dao.Interface, eb EventBiz) StackBiz {
|
|
|
|
return &stackBiz{d: d, s: s, eb: eb}
|
|
|
|
}
|
2017-09-26 12:50:09 +00:00
|
|
|
|
2018-04-16 09:21:20 +00:00
|
|
|
type stackBiz struct {
|
2021-12-06 12:24:22 +00:00
|
|
|
d *docker.Docker
|
|
|
|
s dao.Interface
|
|
|
|
eb EventBiz
|
2017-09-26 12:50:09 +00:00
|
|
|
}
|
|
|
|
|
2022-01-06 08:54:14 +00:00
|
|
|
func (b *stackBiz) Search(ctx context.Context, name, filter string) (stacks []*dao.Stack, err error) {
|
2018-04-16 09:21:20 +00:00
|
|
|
var (
|
2021-12-06 12:24:22 +00:00
|
|
|
activeStacks map[string][]string
|
2021-12-23 11:28:31 +00:00
|
|
|
internalStacks []*dao.Stack
|
2018-04-16 09:21:20 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
// load real stacks
|
2022-01-06 08:54:14 +00:00
|
|
|
activeStacks, err = b.d.StackList(ctx)
|
2018-04-16 09:21:20 +00:00
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// load stack definitions
|
2022-01-06 08:54:14 +00:00
|
|
|
internalStacks, err = b.s.StackGetAll(ctx)
|
2018-04-16 09:21:20 +00:00
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// merge stacks and definitions
|
2021-12-16 12:23:08 +00:00
|
|
|
for i := range internalStacks {
|
|
|
|
stack := internalStacks[i]
|
2021-12-06 12:24:22 +00:00
|
|
|
if services, ok := activeStacks[stack.Name]; ok {
|
|
|
|
stack.Services = services
|
|
|
|
delete(activeStacks, stack.Name)
|
2018-04-16 09:21:20 +00:00
|
|
|
}
|
2021-12-06 12:24:22 +00:00
|
|
|
if !b.filter(stack, name, filter) {
|
2018-04-16 09:21:20 +00:00
|
|
|
stacks = append(stacks, stack)
|
|
|
|
}
|
|
|
|
}
|
2021-12-06 12:24:22 +00:00
|
|
|
for n, services := range activeStacks {
|
2021-12-23 11:28:31 +00:00
|
|
|
stack := &dao.Stack{Name: n, Services: services}
|
2021-12-06 12:24:22 +00:00
|
|
|
if !b.filter(stack, name, filter) {
|
2018-04-16 09:21:20 +00:00
|
|
|
stacks = append(stacks, stack)
|
|
|
|
}
|
|
|
|
}
|
2017-09-26 12:50:09 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2022-01-06 08:54:14 +00:00
|
|
|
func (b *stackBiz) Find(ctx context.Context, name string) (s *dao.Stack, err error) {
|
|
|
|
s, err = b.s.StackGet(ctx, name)
|
2021-12-06 12:24:22 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
} else if s == nil {
|
2021-12-23 11:28:31 +00:00
|
|
|
s = &dao.Stack{Name: name}
|
2021-12-06 12:24:22 +00:00
|
|
|
}
|
2021-12-16 12:23:08 +00:00
|
|
|
return
|
2021-12-06 12:24:22 +00:00
|
|
|
}
|
|
|
|
|
2021-12-23 11:28:31 +00:00
|
|
|
func (b *stackBiz) filter(stack *dao.Stack, name, filter string) bool {
|
2021-12-06 12:24:22 +00:00
|
|
|
if name != "" {
|
|
|
|
if !strings.Contains(strings.ToLower(stack.Name), strings.ToLower(name)) {
|
2018-04-16 09:21:20 +00:00
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-12-06 12:24:22 +00:00
|
|
|
switch filter {
|
2018-04-16 09:21:20 +00:00
|
|
|
case "up":
|
|
|
|
if len(stack.Services) == 0 {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
case "internal":
|
|
|
|
if !stack.Internal {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
case "external":
|
|
|
|
if stack.Internal {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
2022-01-06 08:54:14 +00:00
|
|
|
func (b *stackBiz) Create(ctx context.Context, s *dao.Stack, user web.User) (err error) {
|
2021-12-23 11:28:31 +00:00
|
|
|
stack := &dao.Stack{
|
2021-12-06 12:24:22 +00:00
|
|
|
Name: s.Name,
|
|
|
|
Content: s.Content,
|
2021-12-16 12:23:08 +00:00
|
|
|
CreatedAt: now(),
|
|
|
|
CreatedBy: newOperator(user),
|
2021-12-16 08:11:16 +00:00
|
|
|
}
|
|
|
|
stack.UpdatedAt = stack.CreatedAt
|
|
|
|
stack.UpdatedBy = stack.CreatedBy
|
2022-01-06 08:54:14 +00:00
|
|
|
err = b.s.StackCreate(ctx, stack)
|
2021-12-06 12:24:22 +00:00
|
|
|
if err == nil {
|
|
|
|
b.eb.CreateStack(EventActionCreate, stack.Name, user)
|
|
|
|
}
|
2017-09-26 12:50:09 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2022-01-06 08:54:14 +00:00
|
|
|
func (b *stackBiz) Update(ctx context.Context, s *dao.Stack, user web.User) (err error) {
|
2021-12-23 11:28:31 +00:00
|
|
|
stack := &dao.Stack{
|
2021-12-06 12:24:22 +00:00
|
|
|
Name: s.Name,
|
|
|
|
Content: s.Content,
|
2021-12-16 12:23:08 +00:00
|
|
|
UpdatedAt: now(),
|
|
|
|
UpdatedBy: newOperator(user),
|
2021-12-06 12:24:22 +00:00
|
|
|
}
|
2022-01-06 08:54:14 +00:00
|
|
|
err = b.s.StackUpdate(ctx, stack)
|
2021-12-06 12:24:22 +00:00
|
|
|
if err == nil {
|
|
|
|
b.eb.CreateStack(EventActionUpdate, stack.Name, user)
|
|
|
|
}
|
2017-09-26 12:50:09 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2022-01-06 08:54:14 +00:00
|
|
|
func (b *stackBiz) Delete(ctx context.Context, name string, user web.User) (err error) {
|
|
|
|
err = b.d.StackRemove(ctx, name)
|
2021-12-06 12:24:22 +00:00
|
|
|
if err == nil {
|
2022-01-06 08:54:14 +00:00
|
|
|
err = b.s.StackDelete(ctx, name)
|
2021-12-06 12:24:22 +00:00
|
|
|
}
|
|
|
|
if err == nil {
|
|
|
|
b.eb.CreateStack(EventActionDelete, name, user)
|
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2022-01-06 08:54:14 +00:00
|
|
|
func (b *stackBiz) Shutdown(ctx context.Context, name string, user web.User) (err error) {
|
|
|
|
err = b.d.StackRemove(ctx, name)
|
2021-12-06 12:24:22 +00:00
|
|
|
if err == nil {
|
|
|
|
b.eb.CreateStack(EventActionShutdown, name, user)
|
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2022-01-06 08:54:14 +00:00
|
|
|
func (b *stackBiz) Deploy(ctx context.Context, name string, user web.User) (err error) {
|
|
|
|
stack, err := b.s.StackGet(ctx, name)
|
2021-12-06 12:24:22 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
} else if stack == nil {
|
|
|
|
return errors.Coded(misc.ErrExternalStack, "can not deploy external stack")
|
|
|
|
}
|
|
|
|
|
|
|
|
cfg, err := compose.Parse(stack.Name, stack.Content)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2022-01-06 08:54:14 +00:00
|
|
|
registries, err := b.s.RegistryGetAll(ctx)
|
2021-12-06 12:24:22 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
// Find auth info from registry
|
|
|
|
authes := map[string]string{}
|
|
|
|
for _, sc := range cfg.Services {
|
|
|
|
if _, ok := authes[sc.Image]; !ok {
|
|
|
|
for _, r := range registries {
|
|
|
|
if r.Match(sc.Image) {
|
|
|
|
authes[sc.Image] = r.GetEncodedAuth()
|
|
|
|
}
|
|
|
|
}
|
2018-04-16 09:21:20 +00:00
|
|
|
}
|
2021-12-06 12:24:22 +00:00
|
|
|
}
|
|
|
|
|
2022-01-06 08:54:14 +00:00
|
|
|
err = b.d.StackDeploy(ctx, cfg, authes)
|
2021-12-06 12:24:22 +00:00
|
|
|
if err == nil {
|
|
|
|
b.eb.CreateStack(EventActionDeploy, name, user)
|
|
|
|
}
|
2017-09-26 12:50:09 +00:00
|
|
|
return
|
|
|
|
}
|