init repository
This commit is contained in:
@@ -0,0 +1,189 @@
|
||||
package collector
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"io"
|
||||
"os"
|
||||
"path"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"localenv/utils"
|
||||
|
||||
"github.com/docker/docker/client"
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
const HostImagesStore string = "/tmp/localenv-swarm"
|
||||
|
||||
var ErrImageNotFound = errors.New("image not found")
|
||||
|
||||
func imageNameIntoFilename(name string) string {
|
||||
name = strings.Replace(name, "/", "-", -1)
|
||||
return strings.Replace(name, ":", "-", -1)
|
||||
}
|
||||
|
||||
type collectorErr struct {
|
||||
errs []error
|
||||
sync.Mutex
|
||||
}
|
||||
|
||||
func newCollectorError() collectorErr {
|
||||
return collectorErr{
|
||||
errs: []error{},
|
||||
}
|
||||
}
|
||||
|
||||
func (c *collectorErr) AddError(err error) {
|
||||
c.Lock()
|
||||
defer c.Unlock()
|
||||
|
||||
c.errs = append(c.errs, err)
|
||||
}
|
||||
|
||||
func (c *collectorErr) Err() error {
|
||||
if len(c.errs) != 0 {
|
||||
return errors.Join(c.errs...)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type Collector struct {
|
||||
hostCLI *client.Client
|
||||
swarmCLI *client.Client
|
||||
}
|
||||
|
||||
func NewCollector(hostCLI, swarmCLI *client.Client) Collector {
|
||||
return Collector{
|
||||
hostCLI: hostCLI,
|
||||
swarmCLI: swarmCLI,
|
||||
}
|
||||
}
|
||||
|
||||
func (c Collector) saveImage(ctx context.Context, name, filepath string) error {
|
||||
log.Info().Str("image", name).Str("path", filepath).Msg("saving image into store...")
|
||||
|
||||
imageSaveResponse, err := c.hostCLI.ImageSave(ctx, []string{name})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer imageSaveResponse.Close()
|
||||
|
||||
tarFile, err := os.Create(filepath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer tarFile.Close()
|
||||
|
||||
content, err := io.ReadAll(imageSaveResponse)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := tarFile.Write(content); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
log.Info().Str("image", name).Str("path", filepath).Msg("image saved successfully")
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c Collector) loadImage(ctx context.Context, filepath string) error {
|
||||
log.Info().Str("path", filepath).Msg("loading image...")
|
||||
|
||||
tarFile, err := os.Open(filepath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer tarFile.Close()
|
||||
|
||||
loadResponse, err := c.swarmCLI.ImageLoad(ctx, tarFile, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer loadResponse.Body.Close()
|
||||
|
||||
log.Info().Str("path", filepath).Msg("image loaded successfully")
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c Collector) retryCheckImage(ctx context.Context, name string) error {
|
||||
fnRetry := func(ctx context.Context) error {
|
||||
ok, err := c.checkImage(ctx, name)
|
||||
if err != nil {
|
||||
log.Warn().Str("image", name).Msg("error while searching image, retrying...")
|
||||
return err
|
||||
}
|
||||
|
||||
if !ok {
|
||||
log.Warn().Str("image", name).Msg("image not found, retrying...")
|
||||
return ErrImageNotFound
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
attempts := 30
|
||||
waitDuration := 2 * time.Second
|
||||
if err := utils.Retry(ctx, fnRetry, waitDuration, attempts); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c Collector) checkImage(ctx context.Context, name string) (bool, error) {
|
||||
images, err := utils.FilterImagesByName(ctx, c.swarmCLI, name)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
if len(images) != 1 {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func (c Collector) DeployImages(ctx context.Context, images []string) error {
|
||||
errs := newCollectorError()
|
||||
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(len(images))
|
||||
|
||||
for i := range images {
|
||||
go func(idx int) {
|
||||
defer wg.Done()
|
||||
|
||||
ok, err := c.checkImage(ctx, images[idx])
|
||||
if err != nil {
|
||||
errs.AddError(err)
|
||||
}
|
||||
|
||||
if ok {
|
||||
return
|
||||
}
|
||||
|
||||
filepath := path.Join(HostImagesStore, imageNameIntoFilename(images[idx])+".tar")
|
||||
|
||||
if err = c.saveImage(ctx, images[idx], filepath); err != nil {
|
||||
errs.AddError(err)
|
||||
}
|
||||
|
||||
if err = c.loadImage(ctx, filepath); err != nil {
|
||||
errs.AddError(err)
|
||||
}
|
||||
|
||||
if err := c.retryCheckImage(ctx, images[idx]); err != nil {
|
||||
errs.AddError(err)
|
||||
}
|
||||
}(i)
|
||||
}
|
||||
|
||||
wg.Wait()
|
||||
|
||||
return errs.Err()
|
||||
}
|
||||
Reference in New Issue
Block a user