Rainbond/pkg/builder/sources/image.go

244 lines
7.2 KiB
Go
Raw Normal View History

// RAINBOND, Application Management Platform
// Copyright (C) 2014-2017 Goodrain Co., Ltd.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version. For any non-GPL usage of Rainbond,
// one or multiple Commercial Licenses authorized by Goodrain Co., Ltd.
// must be obtained first.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package sources
import (
"bufio"
2018-03-01 18:30:24 +08:00
"bytes"
2018-03-01 13:34:54 +08:00
"encoding/base64"
"encoding/json"
"fmt"
2018-03-01 13:34:54 +08:00
"io"
"strings"
"time"
2018-02-28 15:14:27 +08:00
"github.com/Sirupsen/logrus"
"github.com/docker/distribution/reference"
2018-02-28 15:14:27 +08:00
"golang.org/x/net/context"
//"github.com/docker/docker/api/types"
"github.com/docker/engine-api/types"
//"github.com/docker/docker/client"
2018-03-01 18:30:24 +08:00
"github.com/docker/docker/pkg/archive"
"github.com/docker/docker/pkg/progress"
"github.com/docker/docker/pkg/streamformatter"
"github.com/docker/engine-api/client"
"github.com/goodrain/rainbond/pkg/builder/model"
2018-02-28 15:14:27 +08:00
"github.com/goodrain/rainbond/pkg/event"
)
//ImagePull 拉取镜像
//timeout 分钟为单位
func ImagePull(dockerCli *client.Client, image string, opts types.ImagePullOptions, logger event.Logger, timeout int) (*types.ImageInspect, error) {
if logger != nil {
//进度信息
logger.Info(fmt.Sprintf("开始获取镜像:%s", image), map[string]string{"step": "pullimage"})
}
2018-02-07 14:50:15 +08:00
rf, err := reference.ParseAnyReference(image)
if err != nil {
2018-02-07 14:50:15 +08:00
logrus.Errorf("reference image error: %s", err.Error())
return nil, err
}
//最少一分钟
if timeout < 1 {
timeout = 1
}
ctx, cancel := context.WithTimeout(context.Background(), time.Minute*time.Duration(timeout))
defer cancel()
2018-02-07 14:50:15 +08:00
//TODO: 使用1.12版本api的bug “repository name must be canonical”使用rf.String()完整的镜像地址
readcloser, err := dockerCli.ImagePull(ctx, rf.String(), opts)
if err != nil {
2018-02-07 14:50:15 +08:00
logrus.Debugf("image name: %s readcloser error: %v", image, err.Error())
if strings.HasSuffix(err.Error(), "does not exist or no pull access") {
return nil, fmt.Errorf("Image(%s) does not exist or no pull access", image)
}
return nil, err
}
defer readcloser.Close()
r := bufio.NewReader(readcloser)
for {
if line, _, err := r.ReadLine(); err == nil {
if logger != nil {
//进度信息
logger.Debug(string(line), map[string]string{"step": "progress"})
}
} else {
break
}
}
ins, _, err := dockerCli.ImageInspectWithRaw(ctx, image, false)
if err != nil {
return nil, err
}
return &ins, nil
}
2018-01-17 22:06:58 +08:00
//ImageTag 修改镜像tag
func ImageTag(dockerCli *client.Client, source, target string, logger event.Logger, timeout int) error {
if logger != nil {
//进度信息
logger.Info(fmt.Sprintf("开始修改镜像tag%s -> %s", source, target), map[string]string{"step": "changetag"})
}
ctx, cancel := context.WithTimeout(context.Background(), time.Minute*time.Duration(timeout))
defer cancel()
err := dockerCli.ImageTag(ctx, source, target)
if err != nil {
logrus.Debugf("image tag err: %s", err.Error())
return err
}
2018-02-28 15:14:27 +08:00
logger.Info("镜像tag修改完成", map[string]string{"step": "changetag"})
return nil
}
//ImageNameHandle 解析imagename
func ImageNameHandle(imageName string) *model.ImageName {
var i model.ImageName
2018-02-28 15:14:27 +08:00
if strings.Contains(imageName, "/") {
mm := strings.Split(imageName, "/")
i.Host = mm[0]
names := strings.Join(mm[1:], "/")
2018-02-28 15:14:27 +08:00
if strings.Contains(names, ":") {
nn := strings.Split(names, ":")
i.Name = nn[0]
i.Tag = nn[1]
2018-02-28 15:14:27 +08:00
} else {
i.Name = names
i.Tag = "latest"
}
2018-02-28 15:14:27 +08:00
} else {
if strings.Contains(imageName, ":") {
nn := strings.Split(imageName, ":")
i.Name = nn[0]
i.Tag = nn[1]
2018-02-28 15:14:27 +08:00
} else {
i.Name = imageName
i.Tag = "latest"
2018-02-28 15:14:27 +08:00
}
}
return &i
}
2018-01-17 22:06:58 +08:00
//ImagePush 推送镜像
//timeout 分钟为单位
func ImagePush(dockerCli *client.Client, image string, opts types.ImagePushOptions, logger event.Logger, timeout int) error {
if logger != nil {
//进度信息
logger.Info(fmt.Sprintf("开始推送镜像:%s", image), map[string]string{"step": "pushimage"})
}
//最少一分钟
if timeout < 1 {
timeout = 1
}
ctx, cancel := context.WithTimeout(context.Background(), time.Minute*time.Duration(timeout))
defer cancel()
readcloser, err := dockerCli.ImagePush(ctx, image, opts)
if err != nil {
if strings.HasSuffix(err.Error(), "does not exist") {
2018-03-01 13:34:54 +08:00
if logger != nil {
logger.Error(fmt.Sprintf("镜像:%s不存在不能推送", image), map[string]string{"step": "pushimage"})
}
return fmt.Errorf("Image(%s) does not exist", image)
}
return err
2018-02-28 15:14:27 +08:00
}
2018-03-01 13:34:54 +08:00
if readcloser != nil {
defer readcloser.Close()
r := bufio.NewReader(readcloser)
for {
if line, _, err := r.ReadLine(); err == nil {
if logger != nil {
//进度信息
logger.Debug(string(line), map[string]string{"step": "progress"})
}
} else {
break
}
}
2018-02-28 15:14:27 +08:00
}
2018-01-17 22:06:58 +08:00
return nil
}
2018-03-01 13:34:54 +08:00
// EncodeAuthToBase64 serializes the auth configuration as JSON base64 payload
func EncodeAuthToBase64(authConfig types.AuthConfig) (string, error) {
buf, err := json.Marshal(authConfig)
if err != nil {
return "", err
}
return base64.URLEncoding.EncodeToString(buf), nil
}
// ImagePushPrivileged push the image
func imagePushPrivileged(ctx context.Context, dockerCli *client.Client, authConfig types.AuthConfig, ref string, requestPrivilege types.RequestPrivilegeFunc) (io.ReadCloser, error) {
encodedAuth, err := EncodeAuthToBase64(authConfig)
if err != nil {
return nil, err
}
options := types.ImagePushOptions{
RegistryAuth: encodedAuth,
PrivilegeFunc: requestPrivilege,
}
return dockerCli.ImagePush(ctx, ref, options)
}
//ImageBuild ImageBuild
2018-03-01 18:30:24 +08:00
func ImageBuild(dockerCli *client.Client, contextDir string, options types.ImageBuildOptions, logger event.Logger, timeout int) error {
ctx, cancel := context.WithTimeout(context.Background(), time.Minute*time.Duration(timeout))
defer cancel()
2018-03-01 18:30:24 +08:00
buildCtx, err := archive.TarWithOptions(contextDir, &archive.TarOptions{
Compression: archive.Uncompressed,
ExcludePatterns: []string{""},
IncludeFiles: []string{"."},
})
if err != nil {
return err
}
progBuff := bytes.NewBuffer(nil)
go func() {
r := bufio.NewReader(progBuff)
for {
if line, _, err := r.ReadLine(); err == nil {
if logger != nil {
logger.Debug(string(line), map[string]string{"step": "dockerbuild"})
}
} else {
break
}
}
}()
// Setup an upload progress bar
progressOutput := streamformatter.NewStreamFormatter().NewProgressOutput(progBuff, true)
var body io.Reader = progress.NewProgressReader(buildCtx, progressOutput, 0, "", "Sending build context to Docker daemon")
rc, err := dockerCli.ImageBuild(ctx, body, options)
if err != nil {
return err
}
r := bufio.NewReader(rc.Body)
for {
if line, _, err := r.ReadLine(); err == nil {
if logger != nil {
2018-03-01 11:30:54 +08:00
logger.Debug(string(line), map[string]string{"step": "dockerbuild"})
}
} else {
break
}
2018-02-28 15:14:27 +08:00
}
return nil
2018-02-28 15:14:27 +08:00
}