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

Addition of generic registry #612

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Changes from all commits
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
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -4,6 +4,7 @@
*.dll
*.so
*.dylib
*.iml

# Test binary, built with `go test -c`
*.test
@@ -14,6 +15,9 @@
# Dependency directories (remove the comment below to include it)
# vendor/

# Mac
.DS_Store

.idea/
coverage.txt
k8s-image-swapper
18 changes: 13 additions & 5 deletions .k8s-image-swapper.yml
Original file line number Diff line number Diff line change
@@ -33,9 +33,11 @@ source:
#- jmespath: "ends_with(obj.metadata.namespace,'-dev')"

# registries:
# dockerio:
# username:
# password:
# - type: "generic"
# generic:
# repository: "repo1.azurecr.io"
# username: "user"
# password: "pass"

target:
type: aws
@@ -98,5 +100,11 @@ target:
}
]
}
# dockerio:
# quayio:

#target:
# type: generic
# generic:
# repository: "repo1.azurecr.io"
# username: "user"
# password: "pass"
# ignoreCert: false
6 changes: 6 additions & 0 deletions cmd/root.go
Original file line number Diff line number Diff line change
@@ -66,20 +66,25 @@ A mutating webhook for Kubernetes, pointing the images to a new location.`,
// Create registry clients for source registries
sourceRegistryClients := []registry.Client{}
for _, reg := range cfg.Source.Registries {
log.Trace().Msgf("Connecting to Source Registry")
sourceRegistryClient, err := registry.NewClient(reg)
if err != nil {
log.Err(err).Msgf("error connecting to source registry at %s", reg.Domain())
os.Exit(1)
}
log.Trace().Msgf("Added Source Registry: %s", sourceRegistryClient.Endpoint())
sourceRegistryClients = append(sourceRegistryClients, sourceRegistryClient)
}

// Create a registry client for private target registry

log.Trace().Msgf("Connecting to Target Registry")
targetRegistryClient, err := registry.NewClient(cfg.Target)
if err != nil {
log.Err(err).Msgf("error connecting to target registry at %s", cfg.Target.Domain())
os.Exit(1)
}
log.Trace().Msgf("Added Target Registry: %s", targetRegistryClient.Endpoint())

imageSwapPolicy, err := types.ParseImageSwapPolicy(cfg.ImageSwapPolicy)
if err != nil {
@@ -102,6 +107,7 @@ A mutating webhook for Kubernetes, pointing the images to a new location.`,
imagePullSecretProvider.SetAuthenticatedRegistries(sourceRegistryClients)

wh, err := webhook.NewImageSwapperWebhookWithOpts(
sourceRegistryClients,
targetRegistryClient,
webhook.Filters(cfg.Source.Filters),
webhook.ImagePullSecretsProvider(imagePullSecretProvider),
39 changes: 39 additions & 0 deletions docs/configuration.md
Original file line number Diff line number Diff line change
@@ -77,6 +77,30 @@ Registries are described with an AWS account ID and region, mostly to construct
accountId: 234567890
region: us-east-1
```
#### GENERIC

By providing configuration on GENERIC registries you can ask `k8s-image-swapper` to handle the authentication using
username and password.

Registries are described with a repository URL, username and password.

!!! example
```yaml
source:
registries:
- type: "generic"
generic:
repository: "repo1.azurecr.io"
username: "username1"
password: "pass1"
- type: "generic"
generic:
repository: "repo2.azurecr.io"
username: "username2"
password: "pass2"
```


### Filters

Filters provide control over what pods will be processed.
@@ -172,6 +196,7 @@ The AWS Account ID and Region is primarily used to construct the ECR domain `[AC
region: ap-southeast-2
```


#### ECR Options

##### Tags
@@ -204,3 +229,17 @@ The GCP location, projectId, and repositoryId are used to constrct the GCP Artif
projectId: gcp-project-123
repositoryId: main
```

### GENERIC

The option `target.generic` holds details about the target registry storing the images.

!!! example
```yaml
target:
type: generic
generic:
repository: "repo2.azurecr.io"
username: "username2"
password: "pass2"
```
70 changes: 48 additions & 22 deletions pkg/config/config.go
Original file line number Diff line number Diff line change
@@ -57,9 +57,10 @@ type Source struct {
}

type Registry struct {
Type string `yaml:"type"`
AWS AWS `yaml:"aws"`
GCP GCP `yaml:"gcp"`
Type string `yaml:"type"`
GENERIC GENERIC `yaml:"generic"`
AWS AWS `yaml:"aws"`
GCP GCP `yaml:"gcp"`
}

type AWS struct {
@@ -75,6 +76,13 @@ type GCP struct {
RepositoryID string `yaml:"repositoryId"`
}

type GENERIC struct {
Repository string `yaml:"repository"`
Username string `yaml:"username"`
Password string `yaml:"password"`
IgnoreCert bool `yaml:"ignoreCert"`
}

type ECROptions struct {
AccessPolicy string `yaml:"accessPolicy"`
LifecyclePolicy string `yaml:"lifecyclePolicy"`
@@ -124,30 +132,48 @@ func CheckRegistryConfiguration(r Registry) error {
return fmt.Errorf("a registry requires a type")
}

errorWithType := func(info string) error {
return fmt.Errorf(`registry of type "%s" %s`, r.Type, info)
}

registry, _ := types.ParseRegistry(r.Type)
switch registry {
case types.RegistryAWS:
if r.AWS.Region == "" {
return errorWithType(`requires a field "region"`)
}
if r.AWS.AccountID == "" {
return errorWithType(`requires a field "accountdId"`)
}
return validateAWSRegistry(r)
case types.RegistryGCP:
if r.GCP.Location == "" {
return errorWithType(`requires a field "location"`)
}
if r.GCP.ProjectID == "" {
return errorWithType(`requires a field "projectId"`)
}
if r.GCP.RepositoryID == "" {
return errorWithType(`requires a field "repositoryId"`)
}
return validateGCPRegistry(r)
case types.RegistryGeneric:
return validateGenericRegistry(r)
}

return nil
}

func errorWithType(r Registry, info string) error {
return fmt.Errorf(`registry of type "%s" %s`, r.Type, info)
}
func validateAWSRegistry(r Registry) error {
if r.AWS.Region == "" {
return errorWithType(r, "requires a field region")
}
if r.AWS.AccountID == "" {
return errorWithType(r, `requires a field "accountdId"`)
}
return nil
}

func validateGCPRegistry(r Registry) error {
if r.GCP.Location == "" {
return errorWithType(r, `requires a field "location"`)
}
if r.GCP.ProjectID == "" {
return errorWithType(r, `requires a field "projectId"`)
}
if r.GCP.RepositoryID == "" {
return errorWithType(r, `requires a field "repositoryId"`)
}
return nil
}

func validateGenericRegistry(r Registry) error {
if r.GENERIC.Repository == "" {
return errorWithType(r, `requires a field "repository"`)
}
return nil
}
Loading