* Copyright (c) 2025 Bocloud Technologies Co., Ltd.
* installer is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain n copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
******************************************************************/
package build
import (
"fmt"
"os"
"runtime"
"strings"
"gopkg.in/yaml.v3"
"gopkg.openfuyao.cn/bkeadm/pkg/global"
"gopkg.openfuyao.cn/bkeadm/pkg/infrastructure"
"gopkg.openfuyao.cn/bkeadm/utils"
"gopkg.openfuyao.cn/bkeadm/utils/log"
)
func (o *Options) BuildOnlineImage() {
var err error
if !infrastructure.IsDocker() {
log.Error("This build instruction only supports running in docker environment.")
return
}
log.SteppedInfo("step.1", "Configuration file check")
cfg := &BuildConfig{}
yamlFile, err := os.ReadFile(o.File)
if err != nil {
log.Errorf("Failed to read the file, %v", err)
return
}
if err = yaml.Unmarshal(yamlFile, cfg); err != nil {
log.Errorf("Unable to serialize file, %v", err)
return
}
log.SteppedInfo("step.2", "Creates a workspace in the current directory")
if err = prepare(); err != nil {
return
}
stopChan := make(chan struct{})
log.SteppedInfo("step.3", "Collect host dependency packages and package files")
if err = buildRpms(cfg, stopChan); err != nil {
log.Errorf("Build failures %v", err)
closeChanStruct(stopChan)
return
}
log.SteppedInfof("step.4", "Build the image %s ...", o.Target)
err = buildImage(o.Target, o.Arch)
if err != nil {
log.Errorf("Build image failures %v", err)
return
}
if err := os.RemoveAll(packages); err != nil {
log.Warnf("Failed to remove packages directory: %v", err)
}
log.SteppedInfo("step.5", "Push the image to the registry completed")
}
func buildImage(imageName string, arch string) error {
err := os.Mkdir(pwd+"/bkesource", utils.DefaultDirPermission)
if err != nil {
return err
}
defer os.RemoveAll(pwd + "/bkesource")
dockerfile := `
FROM scratch
COPY source.tar.gz /bkesource/source.tar.gz
`
err = os.WriteFile(pwd+"/bkesource/Dockerfile", []byte(dockerfile), utils.DefaultFilePermission)
if err != nil {
return err
}
err = os.Rename(fmt.Sprintf("%s/%s", bke, utils.SourceDataFile), pwd+"/bkesource/source.tar.gz")
if err != nil {
return err
}
if strings.Contains(arch, runtime.GOARCH) && !strings.Contains(arch, ",") {
log.Infof("docker build -t %s .", imageName)
output, err := global.Command.ExecuteCommandWithOutput("sh", "-c",
fmt.Sprintf("cd %s/bkesource && docker build -t %s .", pwd, imageName))
if err != nil {
return fmt.Errorf("docker build failed, output: %s, error: %v", output, err)
}
log.Infof("docker push %s", imageName)
output, err = global.Command.ExecuteCommandWithOutput("sh", "-c",
fmt.Sprintf("docker push %s", imageName))
if err != nil {
return fmt.Errorf("docker push failed, output: %s, error: %v", output, err)
}
} else {
platform := ""
for _, ar := range strings.Split(arch, ",") {
if strings.HasPrefix("linux", ar) {
platform += ar + ","
} else {
platform += "linux/" + ar + ","
}
}
platform = strings.TrimSuffix(platform, ",")
log.Infof("docker buildx build --platform=%s -t %s . --push", platform, imageName)
output, err := global.Command.ExecuteCommandWithOutput("sh", "-c",
fmt.Sprintf("cd %s/bkesource && docker buildx build --platform=%s -t %s . --push", pwd, platform, imageName))
if err != nil {
return fmt.Errorf("docker buildx build failed, output: %s, error: %v", output, err)
}
}
return nil
}