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

feat:Including import credentials for project via secretRef #138

Draft
wants to merge 2 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
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
17 changes: 16 additions & 1 deletion apis/projects/v1alpha1/project_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,16 @@
NameRegex *string `url:"name_regex,omitempty" json:"name_regex,omitempty"`
}

// Struct representing the secret name and the secret namespace to use when importing a project with secret

Check failure on line 151 in apis/projects/v1alpha1/project_types.go

View workflow job for this annotation

GitHub Actions / lint

comment on exported type ImportUrlSecretRef should be of the form "ImportUrlSecretRef ..." (with optional leading article) (golint)
type ImportUrlSecretRef struct {

Check failure on line 152 in apis/projects/v1alpha1/project_types.go

View workflow job for this annotation

GitHub Actions / lint

type `ImportUrlSecretRef` should be `ImportURLSecretRef` (golint)
Name string `json:"secretName"`
Namespace string `json:"secretNamespace"`
// +kubebuilder:default:=username
UsernameKey string `json:"username"`
// +kubebuilder:default:=password
PasswordKey string `json:"password"`
}

// ProjectParameters define the desired state of a Gitlab Project
type ProjectParameters struct {
// Set whether or not merge requests can be merged with skipped jobs.
Expand Down Expand Up @@ -244,10 +254,15 @@
// +immutable
GroupWithProjectTemplatesID *int `json:"groupWithProjectTemplatesId,omitempty"`

// URL to import repository from.
// URL to import repository from. Provided credentials in the URL will be overwritten in case a valid secretRef is present in ImportUrlSecretRef.
// +optional
// +kubebuilder:validation:MinLength=9
ImportURL *string `json:"importUrl,omitempty"`

// Secret to use when importing project with secret. Provided credentials in ImportUrl will be overwitten with the credentials found in ImportUrlSecretRel.
// +optional
ImportUrlSecretRef *ImportUrlSecretRef `json:"importUrlSecretRef,omitempty"`

Check failure on line 264 in apis/projects/v1alpha1/project_types.go

View workflow job for this annotation

GitHub Actions / lint

struct field `ImportUrlSecretRef` should be `ImportURLSecretRef` (golint)

// false by default.
// +optional
// +immutable
Expand Down
20 changes: 20 additions & 0 deletions apis/projects/v1alpha1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

28 changes: 26 additions & 2 deletions package/crds/projects.gitlab.crossplane.io_projects.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -162,8 +162,32 @@ spec:
to be true.
type: integer
importUrl:
description: URL to import repository from.
type: string
description: URL to import repository from. Provided credentials
in the URL will be overwritten in case a valid secretRef is
present in ImportUrlSecretRef.
minLength: 9
type: string
importUrlSecretRef:
description: Secret to use when importing project with secret.
Provided credentials in ImportUrl will be overwitten with the
credentials found in ImportUrlSecretRel.
properties:
password:
default: password
type: string
secretName:
type: string
secretNamespace:
type: string
username:
default: username
type: string
required:
- password
- secretName
- secretNamespace
- username
Comment on lines +186 to +189
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are username and password required values or should the provider support imports from public repos?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

username and password are required only if importUrlSecretRef is not nil. And yes the provider should also support imports from public repos. @abacus3

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, thank. I think the name importUrlSecretRef´ is a bit misleading. Can we change it to something more explicit like importCredentialsSecretRef`?

type: object
initializeWithReadme:
description: false by default.
type: boolean
Expand Down
72 changes: 72 additions & 0 deletions pkg/controller/projects/projects/project.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
"strconv"

"github.com/xanzy/go-gitlab"
"k8s.io/apimachinery/pkg/types"
"k8s.io/utils/ptr"

"github.com/google/go-cmp/cmp"
"github.com/google/go-cmp/cmp/cmpopts"
Expand All @@ -41,6 +43,10 @@
"github.com/crossplane-contrib/provider-gitlab/pkg/clients"
"github.com/crossplane-contrib/provider-gitlab/pkg/clients/projects"
"github.com/crossplane-contrib/provider-gitlab/pkg/features"

"net/url"

corev1 "k8s.io/api/core/v1"
)

const (
Expand All @@ -50,6 +56,10 @@
errUpdateFailed = "cannot update Gitlab project"
errDeleteFailed = "cannot delete Gitlab project"
errGetFailed = "cannot retrieve Gitlab project with"
errNoImportSecret = "cannot retrieve secret for import"
errUsernameNotFound = "No username in secret for import project"
errPasswordNotFound = "No password in secret for import project"
errParseUrlFailed = "Could not parse the provided importUrl"

Check failure on line 62 in pkg/controller/projects/projects/project.go

View workflow job for this annotation

GitHub Actions / lint

const `errParseUrlFailed` should be `errParseURLFailed` (golint)
)

// SetupProject adds a controller that reconciles Projects.
Expand Down Expand Up @@ -144,12 +154,74 @@
}, nil
}

func buildImportUrl(ctx context.Context, cr *v1alpha1.Project, e *external) error {

Check failure on line 157 in pkg/controller/projects/projects/project.go

View workflow job for this annotation

GitHub Actions / lint

cyclomatic complexity 12 of func `buildImportUrl` is high (> 10) (gocyclo)

keySecretRef := cr.Spec.ForProvider.ImportUrlSecretRef
importUrl := cr.Spec.ForProvider.ImportURL

Check failure on line 160 in pkg/controller/projects/projects/project.go

View workflow job for this annotation

GitHub Actions / lint

var `importUrl` should be `importURL` (golint)

// User has provided secret for the import
secretRefIsNotEmpty := keySecretRef != nil && keySecretRef.Namespace != "" && keySecretRef.Name != ""
keysAreNotEmpty := keySecretRef != nil && keySecretRef.PasswordKey != "" && keySecretRef.UsernameKey != ""
importUrlIsNotEmpty := ptr.Deref(importUrl, "") != ""

Check failure on line 165 in pkg/controller/projects/projects/project.go

View workflow job for this annotation

GitHub Actions / lint

var `importUrlIsNotEmpty` should be `importURLIsNotEmpty` (golint)

if secretRefIsNotEmpty && keysAreNotEmpty && importUrlIsNotEmpty {
// Retrieve secret from k8s
namespacedName := types.NamespacedName{
Namespace: keySecretRef.Namespace,
Name: keySecretRef.Name,
}

secret := &corev1.Secret{}

err := e.kube.Get(ctx, namespacedName, secret)

if err != nil {
return errors.Wrap(err, errNoImportSecret)
}

// Obtain the password from the secret.
password := string(secret.Data[keySecretRef.PasswordKey])
if password == "" {
return errors.Wrap(err, errPasswordNotFound)
}

// Obtain the username from the secret.
username := string(secret.Data[keySecretRef.UsernameKey])
if username == "" {
return errors.Wrap(err, errUsernameNotFound)
}

// manipulate url to add the secret. If secret is already in the url, it should be overridden
// https://username:[email protected]
parsedUrl, err := url.Parse(*importUrl)

Check failure on line 196 in pkg/controller/projects/projects/project.go

View workflow job for this annotation

GitHub Actions / lint

var `parsedUrl` should be `parsedURL` (golint)

if err != nil {
return errors.Wrap(err, errParseUrlFailed)
}

userInfo := url.UserPassword(username, password)

parsedUrl.User = userInfo

// Override importUrl with the manipulated URL containing the credentials found in ImportSecretRef.
*importUrl = parsedUrl.String()
}

return nil
}

func (e *external) Create(ctx context.Context, mg resource.Managed) (managed.ExternalCreation, error) {
cr, ok := mg.(*v1alpha1.Project)
if !ok {
return managed.ExternalCreation{}, errors.New(errNotProject)
}

err := buildImportUrl(ctx, cr, e)

if err != nil {
return managed.ExternalCreation{}, errors.WithStack(err)
}

prj, _, err := e.client.CreateProject(
projects.GenerateCreateProjectOptions(cr.Name, &cr.Spec.ForProvider),
gitlab.WithContext(ctx),
Expand Down
Loading