github.com/oam-dev/kubevela@v1.9.11/pkg/builtin/build/build.go (about) 1 /* 2 Copyright 2021 The KubeVela Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package build 18 19 import ( 20 "encoding/json" 21 "io" 22 "os/exec" 23 "strings" 24 25 "github.com/pkg/errors" 26 27 "github.com/oam-dev/kubevela/pkg/builtin/kind" 28 "github.com/oam-dev/kubevela/pkg/builtin/registry" 29 cmdutil "github.com/oam-dev/kubevela/pkg/utils/util" 30 ) 31 32 func init() { 33 registry.RegisterTask("build", ImageBuildHandler) 34 } 35 36 func ImageBuildHandler(ctx registry.CallCtx, params interface{}) error { 37 pm, err := json.Marshal(params) 38 if err != nil { 39 return err 40 } 41 b := new(Build) 42 if err := json.Unmarshal(pm, b); err != nil { 43 return err 44 } 45 v, err := ctx.LookUp("image") 46 if err != nil { 47 return err 48 } 49 image, ok := v.(string) 50 if !ok { 51 return errors.New("image must be 'string'") 52 } 53 if err := b.buildImage(ctx.IO(), image); err != nil { 54 return err 55 } 56 if err := b.pushImage(ctx.IO(), image); err != nil { 57 return err 58 } 59 return nil 60 } 61 62 // Build defines the build section of AppFile 63 type Build struct { 64 Push Push `json:"push,omitempty"` 65 Docker Docker `json:"docker,omitempty"` 66 } 67 68 // Docker defines the docker build section 69 type Docker struct { 70 File string `json:"file"` 71 Context string `json:"context"` 72 } 73 74 // Push defines where to push your image 75 type Push struct { 76 Local string `json:"local,omitempty"` 77 Registry string `json:"registry,omitempty"` 78 } 79 80 func asyncLog(reader io.Reader, stream cmdutil.IOStreams) { 81 cache := "" 82 buf := make([]byte, 1024) 83 for { 84 num, err := reader.Read(buf) 85 if err != nil && errors.Is(err, io.EOF) { 86 return 87 } 88 if num > 0 { 89 b := buf[:num] 90 s := strings.Split(string(b), "\n") 91 line := strings.Join(s[:len(s)-1], "\n") 92 stream.Infof("%s%s\n", cache, line) 93 cache = s[len(s)-1] 94 } 95 if errors.Is(err, io.EOF) { 96 break 97 } 98 } 99 } 100 101 // buildImage will build a image with name and context. 102 func (b *Build) buildImage(io cmdutil.IOStreams, image string) error { 103 //nolint:gosec 104 // keep docker binary command due to the issue #416 https://github.com/oam-dev/kubevela/issues/416 105 cmd := exec.Command("docker", "build", "-t", image, "-f", b.Docker.File, b.Docker.Context) 106 stdout, err := cmd.StdoutPipe() 107 if err != nil { 108 io.Errorf("BuildImage exec command error, message:%s\n", err.Error()) 109 return err 110 } 111 stderr, err := cmd.StderrPipe() 112 if err != nil { 113 io.Errorf("BuildImage exec command error, message:%s\n", err.Error()) 114 return err 115 } 116 if err := cmd.Start(); err != nil { 117 io.Errorf("BuildImage exec command error, message:%s\n", err.Error()) 118 return err 119 } 120 go asyncLog(stdout, io) 121 go asyncLog(stderr, io) 122 if err := cmd.Wait(); err != nil { 123 io.Errorf("BuildImage wait for command execution error:%s", err.Error()) 124 return err 125 } 126 return nil 127 } 128 129 func (b *Build) pushImage(io cmdutil.IOStreams, image string) error { 130 io.Infof("pushing image (%s)...\n", image) 131 switch { 132 case b.Push.Local == "kind": 133 err := kind.LoadDockerImage(image) 134 if err != nil { 135 io.Errorf("pushImage(kind) load docker image error, message:%s", err) 136 return err 137 } 138 return nil 139 default: 140 } 141 //nolint:gosec 142 cmd := exec.Command("docker", "push", image) 143 stdout, err := cmd.StdoutPipe() 144 if err != nil { 145 io.Errorf("pushImage(docker push) exec command error, message:%s\n", err.Error()) 146 return err 147 } 148 stderr, err := cmd.StderrPipe() 149 if err != nil { 150 io.Errorf("pushImage(docker push) exec command error, message:%s\n", err.Error()) 151 return err 152 } 153 if err := cmd.Start(); err != nil { 154 io.Errorf("pushImage(docker push) exec command error, message:%s\n", err.Error()) 155 return err 156 } 157 go asyncLog(stdout, io) 158 go asyncLog(stderr, io) 159 if err := cmd.Wait(); err != nil { 160 io.Errorf("pushImage(docker push) wait for command execution error:%s", err.Error()) 161 return err 162 } 163 return nil 164 }