Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

support using json for registry config #1680

Merged
merged 3 commits into from
Jul 4, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
139 changes: 133 additions & 6 deletions pkg/app/bootstrap.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
package app

import (
"encoding/json"
"fmt"
"os"
"path/filepath"
Expand Down Expand Up @@ -76,11 +77,27 @@ var CommandBootstrap = &cli.Command{
Usage: "Specify the registry to pull the image from",
Aliases: []string{"r"},
},
&cli.StringFlag{
Name: "registry-config",
Usage: "Path to a JSON file containing registry configuration. Cannot be used with 'registry' or 'registry-ca-keypair'",
},
},

Action: bootstrap,
}

type Registry struct {
Name string `json:"name"`
Ca string `json:"ca"`
Cert string `json:"cert"`
Key string `json:"key"`
UseHttp bool `json:"use_http"`
kemingy marked this conversation as resolved.
Show resolved Hide resolved
}

type RegistriesData struct {
Registries []Registry `json:"registries"`
}

func bootstrap(clicontext *cli.Context) error {
stages := []struct {
Name string
Expand All @@ -91,6 +108,9 @@ func bootstrap(clicontext *cli.Context) error {
}, {
"registry CA keypair",
registryCA,
}, {
"registry json config",
registryJSONConfig,
}, {
"autocomplete",
autocomplete,
Expand All @@ -112,7 +132,17 @@ func bootstrap(clicontext *cli.Context) error {
}

func registryCA(clicontext *cli.Context) error {
configFile := clicontext.String("registry-config")
ca := clicontext.String("registry-ca-keypair")
registry := clicontext.String("registry")

// We only need this check in registryCA because it is called before registryJSONConfig
if len(configFile) > 0 && len(ca) > 0 {
return errors.New("only one of `registry-config` and `registry-ca-keypair` can be used")
}
if len(configFile) > 0 && len(registry) > 0 {
return errors.New("only one of `registry-config` and `registry` can be used")
}
if len(ca) == 0 {
return nil
}
Expand Down Expand Up @@ -146,7 +176,12 @@ func registryCA(clicontext *cli.Context) error {
if !exist {
return errors.Newf("file %s doesn't exist", kv[1])
}
path, err := fileutil.ConfigFile(fmt.Sprintf("registry_%s.pem", kv[0]))

if len(registry) == 0 {
registry = "docker.io"
}

path, err := fileutil.ConfigFile(fmt.Sprintf("%s_%s.pem", registry, kv[0]))
kemingy marked this conversation as resolved.
Show resolved Hide resolved
if err != nil {
return errors.Wrap(err, "failed to get the envd config file path")
}
Expand All @@ -166,6 +201,69 @@ func registryCA(clicontext *cli.Context) error {
return nil
}

func registryJSONConfig(clicontext *cli.Context) error {
configFile := clicontext.String("registry-config")
if len(configFile) == 0 {
return nil
}

// Check if file exists
exist, err := fileutil.FileExists(configFile)
if err != nil {
return errors.Wrap(err, fmt.Sprintf("failed to parse file path %s", configFile))
}
if !exist {
return errors.Newf("file %s doesn't exist", configFile)
}

var data RegistriesData
configJson, err := os.ReadFile(configFile)
if err != nil {
return errors.Wrap(err, "Failed to read registry config file")
}
if err := json.Unmarshal(configJson, &data); err != nil {
return errors.Wrap(err, "Failed to parse registry config file")
}

// Check for required keys in each registry
for i, registry := range data.Registries {
if registry.Name == "" {
return errors.Newf("`name` key is required in the config for registry at index %d", i)
}

// Check for optional keys and if they exist, ensure they point to existing files
optionalKeys := map[string]string{"ca": registry.Ca, "cert": registry.Cert, "key": registry.Key}
for key, value := range optionalKeys {
if value != "" {
exist, err := fileutil.FileExists(value)
if err != nil {
return errors.Wrap(err, fmt.Sprintf("failed to parse file path %s", value))
}
if !exist {
return errors.Newf("file %s doesn't exist", value)
}

// Read the file
content, err := os.ReadFile(value)
if err != nil {
return errors.Wrap(err, fmt.Sprintf("failed to read the %s file for registry %s", key, registry.Name))
}

// Write the content to the envd config directory
envdConfigPath, err := fileutil.ConfigFile(fmt.Sprintf("%s_%s.pem", registry.Name, key))
if err != nil {
return errors.Wrap(err, fmt.Sprintf("failed to get the envd config file path for %s of registry %s", key, registry.Name))
}

if err = os.WriteFile(envdConfigPath, content, 0644); err != nil {
return errors.Wrap(err, fmt.Sprintf("failed to store the %s file for registry %s", key, registry.Name))
}
}
}
}
return nil
}

func sshKey(clicontext *cli.Context) error {
sshKeyPair := clicontext.StringSlice("ssh-keypair")

Expand Down Expand Up @@ -240,7 +338,7 @@ func sshKey(clicontext *cli.Context) error {
return nil

default:
return errors.Errorf("Invalid ssh-keypair flag")
return errors.Newf("Invalid ssh-keypair flag")
}
}

Expand Down Expand Up @@ -290,11 +388,40 @@ func buildkit(clicontext *cli.Context) error {

logrus.Debug("bootstrap the buildkitd container")
var bkClient buildkitd.Client
var data RegistriesData

// Populate the BuildkitConfig struct
config := buildkitutil.BuildkitConfig{
Registry: clicontext.String("registry"),
Mirror: clicontext.String("dockerhub-mirror"),
UseHTTP: clicontext.Bool("use-http"),
SetCA: clicontext.IsSet("registry-ca-keypair"),
Mirror: clicontext.String("dockerhub-mirror"),
}

configFile := clicontext.String("registry-config")
if len(configFile) != 0 {
configJson, err := os.ReadFile(configFile)
if err != nil {
return errors.Wrap(err, "Failed to read registry config file")
}
if err := json.Unmarshal(configJson, &data); err != nil {
return errors.Wrap(err, "Failed to parse registry config file")
}
for _, registry := range data.Registries {
config.RegistryName = append(config.RegistryName, registry.Name)
config.CaPath = append(config.CaPath, registry.Ca)
config.CertPath = append(config.CertPath, registry.Cert)
config.KeyPath = append(config.KeyPath, registry.Key)
config.UseHTTP = append(config.UseHTTP, registry.UseHttp)
}
} else if len(clicontext.String("registry-ca-keypair")) != 0 {
if len(clicontext.String("registry")) == 0 {
config.RegistryName = append(config.RegistryName, "docker.io")
} else {
config.RegistryName = append(config.RegistryName, clicontext.String("registry"))
}
// the path values aren't actually necessary since we already hardcoded the paths to /etc/registry. we just need something arbitrary in the struct so the template parses properly, so we'll just use /etc/registry
config.CaPath = append(config.CaPath, "/etc/registry")
config.CertPath = append(config.CertPath, "/etc/registry")
config.KeyPath = append(config.KeyPath, "/etc/registry")
config.UseHTTP = append(config.UseHTTP, clicontext.Bool("use-http"))
}

if c.Builder == types.BuilderTypeMoby {
Expand Down
2 changes: 1 addition & 1 deletion pkg/driver/docker/docker.go
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@ func (c dockerClient) StartBuildkitd(ctx context.Context, tag, name string, bc *
AutoRemove: true,
}

if bc.SetCA {
if len(bc.RegistryName) > 0 {
hostConfig.Mounts = append(hostConfig.Mounts, mount.Mount{
Type: mount.TypeBind,
Source: fileutil.DefaultConfigDir,
Expand Down
2 changes: 1 addition & 1 deletion pkg/driver/nerdctl/nerdctl.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ func (nc *nerdctlClient) StartBuildkitd(ctx context.Context, tag, name string, b
if !existed {
buildkitdCmd := "buildkitd"
// TODO: support mirror CA keypair
if bc.Registry != "" || bc.Mirror != "" || bc.UseHTTP {
if len(bc.RegistryName) > 0 || bc.Mirror != "" || len(bc.UseHTTP) > 0 {
cfg, err := bc.String()
if err != nil {
return "", errors.Wrap(err, "failed to generate buildkit config")
Expand Down
36 changes: 24 additions & 12 deletions pkg/util/buildkitutil/buildkit.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,21 +20,33 @@ import (
)

const buildkitConfigTemplate = `
[registry."{{ if .Registry }}{{ .Registry }}{{ else }}docker.io{{ end }}"]{{ if .Mirror }}
mirrors = ["{{ .Mirror }}"]{{ end }}
http = {{ .UseHTTP }}
{{ if .SetCA}}ca=["/etc/registry/ca.pem"]
[[registry."{{ if .Registry }}{{ .Registry }}{{ else }}docker.io{{ end }}".keypair]]
key="/etc/registry/key.pem"
cert="/etc/registry/cert.pem"
{{ end }}
[registry]
{{- range $index, $value := .RegistryName }}
[registry."{{ if $value }}{{ $value }}{{ else }}docker.io{{ end }}"]
{{- if index $.UseHTTP $index }}
http = true
{{- end }}
{{- if $.Mirror }}
mirrors = ["{{ $.Mirror }}"]
{{- end }}
{{- if index $.CaPath $index }}
ca=["/etc/registry/{{ $value }}_ca.pem"]
{{- end }}
{{- if and (index $.CertPath $index) (index $.KeyPath $index) }}
[[registry."{{ if $value }}{{ $value }}{{ else }}docker.io{{ end }}".keypair]]
key="/etc/registry/{{ $value }}_key.pem"
cert="/etc/registry/{{ $value }}_cert.pem"
{{- end }}
{{- end }}
`

type BuildkitConfig struct {
Registry string
Mirror string
UseHTTP bool
SetCA bool
RegistryName []string
CaPath []string
CertPath []string
KeyPath []string
UseHTTP []bool
Mirror string
}
kemingy marked this conversation as resolved.
Show resolved Hide resolved

func (c *BuildkitConfig) String() (string, error) {
Expand Down
79 changes: 61 additions & 18 deletions pkg/util/buildkitutil/buildkit_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,36 +28,79 @@ func TestBuildkitWithRegistry(t *testing.T) {
}{
{
BuildkitConfig{
Registry: "registry.example.com",
Mirror: "https://mirror.example.com",
UseHTTP: true,
RegistryName: []string{"registry.example.com"},
CaPath: []string{"/etc/registry/ca.pem"},
CertPath: []string{"/etc/registry/cert.pem"},
KeyPath: []string{"/etc/registry/key.pem"},
UseHTTP: []bool{false},
Mirror: "https://mirror.example.com",
},
`
[registry."registry.example.com"]
mirrors = ["https://mirror.example.com"]
http = true
[registry]
[registry."registry.example.com"]
mirrors = ["https://mirror.example.com"]
ca=["/etc/registry/registry.example.com_ca.pem"]
[[registry."registry.example.com".keypair]]
key="/etc/registry/registry.example.com_key.pem"
cert="/etc/registry/registry.example.com_cert.pem"
`,
},
{
BuildkitConfig{
Registry: "registry.example.com",
SetCA: true,
RegistryName: []string{"registry.example.com", "docker.io"},
CaPath: []string{"", ""},
CertPath: []string{"", ""},
KeyPath: []string{"", ""},
UseHTTP: []bool{true, false},
Mirror: "https://mirror.example.com",
},
`
[registry."registry.example.com"]
http = false
ca=["/etc/registry/ca.pem"]
[[registry."registry.example.com".keypair]]
key="/etc/registry/key.pem"
cert="/etc/registry/cert.pem"
[registry]
[registry."registry.example.com"]
http = true
mirrors = ["https://mirror.example.com"]
[registry."docker.io"]
mirrors = ["https://mirror.example.com"]
`,
},
{
BuildkitConfig{},
BuildkitConfig{
RegistryName: []string{},
CaPath: []string{},
CertPath: []string{},
KeyPath: []string{},
UseHTTP: []bool{},
Mirror: "",
},
`
[registry."docker.io"]
http = false
`,
[registry]
`,
},
{
BuildkitConfig{
RegistryName: []string{"registry1.example.com", "registry2.example.com"},
CaPath: []string{"/etc/registry/ca1.pem", "/etc/registry/ca2.pem"},
CertPath: []string{"/etc/registry/cert1.pem", "/etc/registry/cert2.pem"},
KeyPath: []string{"/etc/registry/key1.pem", "/etc/registry/key2.pem"},
UseHTTP: []bool{true, false},
Mirror: "https://mirror.example.com",
},
`
[registry]
[registry."registry1.example.com"]
http = true
mirrors = ["https://mirror.example.com"]
ca=["/etc/registry/registry1.example.com_ca.pem"]
[[registry."registry1.example.com".keypair]]
key="/etc/registry/registry1.example.com_key.pem"
cert="/etc/registry/registry1.example.com_cert.pem"
[registry."registry2.example.com"]
mirrors = ["https://mirror.example.com"]
ca=["/etc/registry/registry2.example.com_ca.pem"]
[[registry."registry2.example.com".keypair]]
key="/etc/registry/registry2.example.com_key.pem"
cert="/etc/registry/registry2.example.com_cert.pem"
`,
},
}

Expand Down
Loading