| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148 |
- package docker
- import (
- "bytes"
- "context"
- "encoding/base64"
- "encoding/json"
- "fmt"
- "io"
- "sync"
- "time"
- fw "git.buran.team/main/fairwind"
- archive "github.com/moby/go-archive"
- mobyregistry "github.com/moby/moby/api/types/registry"
- moby "github.com/moby/moby/client"
- )
- type Image struct {
- ctx context.Context
- log *fw.Log
- client *Docker
- registry *Registry
- tag string
- version string
- build bool
- push bool
- }
- func NewImage(ctx context.Context, log *fw.Log, client *Docker, registry *Registry, tag string, version string, build bool, push bool) *Image {
- return &Image{
- ctx: ctx,
- log: log,
- client: client,
- registry: registry,
- tag: tag,
- version: version,
- build: build,
- push: push,
- }
- }
- func (this *Image) Name() string {
- return fmt.Sprintf("%s/%s:%s", this.registry.address, this.tag, this.version)
- }
- func (this *Image) Build(timeout int, path string) ([]byte, error) {
- if (!this.build) {
- return []byte{}, nil
- }
- ctx, cancel := context.WithTimeout(this.ctx, time.Duration(timeout)*time.Millisecond)
- defer cancel()
- stream, err := archive.TarWithOptions(path, &archive.TarOptions{})
- if err != nil {
- return nil, fmt.Errorf("can't build image: %w", err)
- }
- defer stream.Close()
- response, err := this.client.Docker.ImageBuild(
- ctx,
- stream,
- moby.ImageBuildOptions{
- Dockerfile: "Dockerfile",
- Tags: []string{
- this.Name(),
- },
- },
- )
- if err != nil {
- return nil, fmt.Errorf("can't build image: %w", err)
- }
- defer response.Body.Close()
- var stdout bytes.Buffer
- _, err = io.Copy(&stdout, response.Body)
- if err != nil {
- return nil, fmt.Errorf("can't build image: %w", err)
- }
- return stdout.Bytes(), nil
- }
- func (this *Image) Push(timeout int) ([]byte, error) {
- if (!this.push) {
- return []byte{}, nil
- }
- ctx, cancel := context.WithTimeout(this.ctx, time.Duration(timeout)*time.Millisecond)
- defer cancel()
- credentials, err := credentialsToString(
- this.registry.login,
- this.registry.password,
- )
- if err != nil {
- return nil, fmt.Errorf("can't push image: %w", err)
- }
- response, err := this.client.Docker.ImagePush(
- ctx,
- this.Name(),
- moby.ImagePushOptions{
- RegistryAuth: credentials,
- },
- )
- if err != nil {
- return nil, fmt.Errorf("can't push image: %w", err)
- }
- var stdout bytes.Buffer
- var waitGroup sync.WaitGroup
- waitGroup.Add(1)
- go func() {
- defer waitGroup.Done()
- _, err := io.Copy(&stdout, response)
- if err != nil {
- // ...
- }
- }()
- err = response.Wait(ctx)
- if err != nil {
- return nil, fmt.Errorf("can't push image: %w", err)
- }
- waitGroup.Wait()
- return stdout.Bytes(), nil
- }
- func credentialsToString(login string, password string) (string, error) {
- encodedJSON, err := json.Marshal(
- &mobyregistry.AuthConfig{
- Username: login,
- Password: password,
- },
- )
- if err != nil {
- return "", fmt.Errorf("can't serialize credentials: %w", err)
- }
- authStr := base64.URLEncoding.EncodeToString(encodedJSON)
- return authStr, nil
- }
|