Skip to content

Commit

Permalink
Merge pull request #953 from CircleCI-Public/put-back-build-agent-cus…
Browse files Browse the repository at this point in the history
…tomisation

fix: Put back build-agent customisation
  • Loading branch information
JulesFaucherre authored Jun 15, 2023
2 parents b675973 + b18c540 commit 8f735af
Show file tree
Hide file tree
Showing 2 changed files with 65 additions and 31 deletions.
1 change: 1 addition & 0 deletions cmd/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ func newLocalExecuteCommand(config *settings.Config) *cobra.Command {
}

local.AddFlagsForDocumentation(buildCommand.Flags())
buildCommand.Flags().String("build-agent-version", "", `The version of the build agent image you want to use. This can be configured by writing in $HOME/.circleci/build_agent_settings.json: '{"LatestSha256":"<version-of-build-agent>"}'`)
buildCommand.Flags().StringP("org-slug", "o", "", "organization slug (for example: github/example-org), used when a config depends on private orbs belonging to that org")
buildCommand.Flags().String("org-id", "", "organization id, used when a config depends on private orbs belonging to that org")

Expand Down
95 changes: 64 additions & 31 deletions local/local.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
package local

import (
"encoding/json"
"fmt"
"io"
"os"
"os/exec"
"regexp"
"path"
"strings"
"syscall"

Expand Down Expand Up @@ -71,7 +72,8 @@ func Execute(flags *pflag.FlagSet, cfg *settings.Config, args []string) error {
return err
}

image, err := picardImage(os.Stdout)
picardVersion, _ := flags.GetString("build-agent-version")
image, err := picardImage(os.Stdout, picardVersion)
if err != nil {
return errors.Wrap(err, "Could not find picard image")
}
Expand Down Expand Up @@ -130,7 +132,7 @@ func buildAgentArguments(flags *pflag.FlagSet) ([]string, string) {

// build a list of all supplied flags, that we will pass on to build-agent
flags.Visit(func(flag *pflag.Flag) {
if flag.Name != "org-slug" && flag.Name != "config" && flag.Name != "debug" && flag.Name != "org-id" && flag.Name != "docker-socket-path" {
if flag.Name != "build-agent-version" && flag.Name != "org-slug" && flag.Name != "config" && flag.Name != "debug" && flag.Name != "org-id" && flag.Name != "docker-socket-path" {
result = append(result, unparseFlag(flags, flag)...)
}
})
Expand All @@ -141,10 +143,10 @@ func buildAgentArguments(flags *pflag.FlagSet) ([]string, string) {
return result, configPath
}

func picardImage(output io.Writer) (string, error) {
func picardImage(output io.Writer, picardVersion string) (string, error) {
fmt.Fprintf(output, "Fetching latest build environment...\n")

sha, err := findLatestPicardSha()
sha, err := getPicardSha(output, picardVersion)
if err != nil {
return "", err
}
Expand All @@ -153,47 +155,44 @@ func picardImage(output io.Writer) (string, error) {
return fmt.Sprintf("%s@%s", picardRepo, sha), nil
}

func ensureDockerIsAvailable() (string, error) {

dockerPath, err := exec.LookPath("docker")

if err != nil {
return "", errors.New("could not find `docker` on the PATH; please ensure that docker is installed")
func getPicardSha(output io.Writer, picardVersion string) (string, error) {
// If the version was passed as argument, we take it
if picardVersion != "" {
return picardVersion, nil
}

dockerRunning := exec.Command(dockerPath, "version").Run() == nil // #nosec
var sha string
var err error

if !dockerRunning {
return "", errors.New("failed to connect to docker; please ensure that docker is running, and that `docker version` succeeds")
sha, err = loadBuildAgentShaFromConfig()
if sha != "" && err == nil {
return sha, nil
}
if err != nil && !os.IsNotExist(err) {
fmt.Fprintf(output, "Unable to parse JSON file %s because: %s\n", buildAgentSettingsPath(), err)
fmt.Fprintf(output, "Falling back to latest build-agent version\n")
}

return dockerPath, nil
// We are freezing build-agent cli as we would like to deprecate this path
fixedSha := "sha256:008ba7f4223f1e26c11df9575283491b620074fa96da6961e0dcde47fb757014"
return fixedSha, nil
}

// Still depends on a function in cmd/build.go
func findLatestPicardSha() (string, error) {
if _, err := ensureDockerIsAvailable(); err != nil {
return "", err
}
func ensureDockerIsAvailable() (string, error) {

// We are freezing build-agent cli as we would like to deprecate this path
// this is frozen to build-agent branch https://github.com/circleci/build-agent/tree/frozen-circleci-cli
imageName := fmt.Sprintf("%s:1.0.183556-5a2aabb6", picardRepo)
outputBytes, err := exec.Command("docker", "pull", imageName).CombinedOutput() // #nosec
dockerPath, err := exec.LookPath("docker")

if err != nil {
return "", errors.Wrap(err, "failed to pull latest docker image")
return "", errors.New("could not find `docker` on the PATH; please ensure that docker is installed")
}

output := string(outputBytes)
sha256 := regexp.MustCompile("(?m)sha256:[0-9a-f]+")
latest := sha256.FindString(output)
dockerRunning := exec.Command(dockerPath, "version").Run() == nil // #nosec

if latest == "" {
return "", fmt.Errorf("failed to parse sha256 from docker pull output")
if !dockerRunning {
return "", errors.New("failed to connect to docker; please ensure that docker is running, and that `docker version` succeeds")
}

return latest, nil
return dockerPath, nil
}

// Write data to a temp file, and return the path to that file.
Expand Down Expand Up @@ -247,3 +246,37 @@ func unparseFlag(flags *pflag.FlagSet, flag *pflag.Flag) []string {
}
return result
}

type buildAgentSettings struct {
LatestSha256 string
}

func loadBuildAgentShaFromConfig() (string, error) {
if _, err := os.Stat(buildAgentSettingsPath()); os.IsNotExist(err) {
// Settings file does not exist.
return "", nil
}

file, err := os.Open(buildAgentSettingsPath())
if err != nil {
return "", errors.Wrap(err, "Could not open build settings config")
}
defer file.Close()

var settings buildAgentSettings

buf, err := io.ReadAll(file)
if err != nil {
return "", errors.Wrap(err, "Couldn't read from build settings file")
}

if err = json.Unmarshal(buf, &settings); err != nil {
return "", errors.Wrap(err, "Could not parse build settings config")
}

return settings.LatestSha256, nil
}

func buildAgentSettingsPath() string {
return path.Join(settings.SettingsPath(), "build_agent_settings.json")
}

0 comments on commit 8f735af

Please sign in to comment.