swirl/biz/stack.go

228 lines
5.2 KiB
Go
Raw Normal View History

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-16 08:11:16 +00:00
"time"
2018-04-16 09:21:20 +00:00
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
"github.com/cuigh/swirl/model"
)
2021-12-06 12:24:22 +00:00
type StackBiz interface {
Search(name, filter string) (stacks []*Stack, err error)
Find(name string) (stack *Stack, err error)
Delete(name string, user web.User) (err error)
Shutdown(name string, user web.User) (err error)
Deploy(name string, user web.User) (err error)
Create(s *Stack, user web.User) (err error)
Update(s *Stack, user web.User) (err error)
}
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
}
2021-12-06 12:24:22 +00:00
func (b *stackBiz) Search(name, filter string) (stacks []*Stack, err error) {
2018-04-16 09:21:20 +00:00
var (
2021-12-06 12:24:22 +00:00
activeStacks map[string][]string
internalStacks []*model.Stack
2018-04-16 09:21:20 +00:00
)
// load real stacks
2021-12-06 12:24:22 +00:00
activeStacks, err = b.d.StackList(context.TODO())
2018-04-16 09:21:20 +00:00
if err != nil {
return
}
// load stack definitions
2021-12-16 08:11:16 +00:00
internalStacks, err = b.s.StackGetAll(context.TODO())
2018-04-16 09:21:20 +00:00
if err != nil {
return
}
// merge stacks and definitions
2021-12-06 12:24:22 +00:00
for _, s := range internalStacks {
stack := newStack(s)
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 {
stack := &Stack{Name: n, Services: services}
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
}
2021-12-06 12:24:22 +00:00
func (b *stackBiz) Find(name string) (stack *Stack, err error) {
s, err := b.s.StackGet(context.TODO(), name)
if err != nil {
return nil, err
} else if s == nil {
return &Stack{ID: name, Name: name}, nil
}
return newStack(s), nil
}
func (b *stackBiz) filter(stack *Stack, name, filter string) bool {
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
}
2021-12-06 12:24:22 +00:00
func (b *stackBiz) Create(s *Stack, user web.User) (err error) {
stack := &model.Stack{
Name: s.Name,
Content: s.Content,
2021-12-16 08:11:16 +00:00
CreatedAt: time.Now(),
CreatedBy: model.Operator{
ID: user.ID(),
Name: user.Name(),
},
}
stack.UpdatedAt = stack.CreatedAt
stack.UpdatedBy = stack.CreatedBy
2021-12-06 12:24:22 +00:00
err = b.s.StackCreate(context.TODO(), stack)
if err == nil {
b.eb.CreateStack(EventActionCreate, stack.Name, user)
}
2017-09-26 12:50:09 +00:00
return
}
2018-04-16 09:21:20 +00:00
func (b *stackBiz) Get(name string) (stack *model.Stack, err error) {
2021-12-06 12:24:22 +00:00
return b.s.StackGet(context.TODO(), name)
2018-04-16 09:21:20 +00:00
}
2017-09-26 12:50:09 +00:00
2021-12-06 12:24:22 +00:00
func (b *stackBiz) Update(s *Stack, user web.User) (err error) {
stack := &model.Stack{
Name: s.Name,
Content: s.Content,
2021-12-16 08:11:16 +00:00
UpdatedAt: time.Now(),
2021-12-06 12:24:22 +00:00
}
2021-12-16 08:11:16 +00:00
stack.UpdatedBy.ID = user.ID()
stack.UpdatedBy.Name = user.Name()
2021-12-06 12:24:22 +00:00
err = b.s.StackUpdate(context.TODO(), stack)
if err == nil {
b.eb.CreateStack(EventActionUpdate, stack.Name, user)
}
2017-09-26 12:50:09 +00:00
return
}
2018-04-16 09:21:20 +00:00
func (b *stackBiz) Delete(name string, user web.User) (err error) {
2021-12-06 12:24:22 +00:00
err = b.d.StackRemove(context.TODO(), name)
if err == nil {
err = b.s.StackDelete(context.TODO(), name)
}
if err == nil {
b.eb.CreateStack(EventActionDelete, name, user)
}
return
}
func (b *stackBiz) Shutdown(name string, user web.User) (err error) {
err = b.d.StackRemove(context.TODO(), name)
if err == nil {
b.eb.CreateStack(EventActionShutdown, name, user)
}
return
}
func (b *stackBiz) Deploy(name string, user web.User) (err error) {
stack, err := b.s.StackGet(context.TODO(), name)
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
}
2021-12-16 08:11:16 +00:00
registries, err := b.s.RegistryGetAll(context.TODO())
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
}
err = b.d.StackDeploy(context.TODO(), cfg, authes)
if err == nil {
b.eb.CreateStack(EventActionDeploy, name, user)
}
2017-09-26 12:50:09 +00:00
return
}
2021-12-06 12:24:22 +00:00
type Stack struct {
2021-12-16 08:11:16 +00:00
ID string `json:"id,omitempty"`
Name string `json:"name,omitempty"`
Content string `json:"content,omitempty"`
Services []string `json:"services,omitempty"`
Internal bool `json:"internal"`
CreatedAt string `json:"createdAt,omitempty"`
UpdatedAt string `json:"updatedAt,omitempty"`
CreatedBy model.Operator `json:"createdBy,omitempty"`
UpdatedBy model.Operator `json:"updatedBy,omitempty"`
2021-12-06 12:24:22 +00:00
}
func newStack(s *model.Stack) *Stack {
return &Stack{
ID: s.Name,
Name: s.Name,
Content: s.Content,
2021-12-16 08:11:16 +00:00
Internal: true,
2021-12-06 12:24:22 +00:00
CreatedAt: formatTime(s.CreatedAt),
UpdatedAt: formatTime(s.UpdatedAt),
2021-12-16 08:11:16 +00:00
CreatedBy: s.CreatedBy,
UpdatedBy: s.UpdatedBy,
2021-12-06 12:24:22 +00:00
}
2017-09-26 12:50:09 +00:00
}