Skip to content
Open
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
6 changes: 4 additions & 2 deletions api/v1alpha1/user_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ limitations under the License.
package v1alpha1

// UserResourceSpec contains the desired state of the resource.
// +kubebuilder:validation:XValidation:rule="!has(oldSelf.passwordRef) || has(self.passwordRef)",message="passwordRef may not be removed once set"
type UserResourceSpec struct {
// name will be the name of the created resource. If not specified, the
// name of the ORC object will be used.
Expand Down Expand Up @@ -45,8 +46,9 @@ type UserResourceSpec struct {

// passwordRef is a reference to a Secret containing the password
// for this user. The Secret must contain a key named "password".
// +required
PasswordRef KubernetesNameRef `json:"passwordRef,omitempty"`
// If not specified, the user is created without a password.
// +optional
PasswordRef *KubernetesNameRef `json:"passwordRef,omitempty"`
}

// UserFilter defines an existing resource by its properties
Expand Down
5 changes: 5 additions & 0 deletions api/v1alpha1/zz_generated.deepcopy.go

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

3 changes: 1 addition & 2 deletions cmd/models-schema/zz_generated.openapi.go

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

6 changes: 4 additions & 2 deletions config/crd/bases/openstack.k-orc.cloud_users.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -190,12 +190,14 @@ spec:
description: |-
passwordRef is a reference to a Secret containing the password
for this user. The Secret must contain a key named "password".
If not specified, the user is created without a password.
maxLength: 253
minLength: 1
type: string
required:
- passwordRef
type: object
x-kubernetes-validations:
- message: passwordRef may not be removed once set
rule: '!has(oldSelf.passwordRef) || has(self.passwordRef)'
required:
- cloudCredentialsRef
type: object
Expand Down
10 changes: 5 additions & 5 deletions internal/controllers/user/actuator.go
Original file line number Diff line number Diff line change
Expand Up @@ -140,10 +140,10 @@ func (actuator userActuator) CreateResource(ctx context.Context, obj orcObjectPT
}

var password string
{
if resource.PasswordRef != nil {
secret, secretReconcileStatus := dependency.FetchDependency(
ctx, actuator.k8sClient, obj.Namespace,
&resource.PasswordRef, "Secret",
resource.PasswordRef, "Secret",
func(*corev1.Secret) bool { return true },
)
reconcileStatus = reconcileStatus.WithReconcileStatus(secretReconcileStatus)
Expand Down Expand Up @@ -189,11 +189,11 @@ func (actuator userActuator) DeleteResource(ctx context.Context, _ orcObjectPT,
func (actuator userActuator) reconcilePassword(ctx context.Context, obj orcObjectPT, osResource *osResourceT) progress.ReconcileStatus {
log := ctrl.LoggerFrom(ctx)
resource := obj.Spec.Resource
if resource == nil {
if resource == nil || resource.PasswordRef == nil {
return nil
}

currentRef := string(resource.PasswordRef)
currentRef := string(*resource.PasswordRef)
var lastAppliedRef string
if obj.Status.Resource != nil {
lastAppliedRef = obj.Status.Resource.AppliedPasswordRef
Expand All @@ -206,7 +206,7 @@ func (actuator userActuator) reconcilePassword(ctx context.Context, obj orcObjec
// Read the password from the referenced Secret
secret, secretRS := dependency.FetchDependency(
ctx, actuator.k8sClient, obj.Namespace,
&resource.PasswordRef, "Secret",
resource.PasswordRef, "Secret",
func(*corev1.Secret) bool { return true },
)
if secretRS != nil {
Expand Down
4 changes: 2 additions & 2 deletions internal/controllers/user/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,10 +91,10 @@ var passwordDependency = dependency.NewDependency[*orcv1alpha1.UserList, *corev1
"spec.resource.passwordRef",
func(user *orcv1alpha1.User) []string {
resource := user.Spec.Resource
if resource == nil {
if resource == nil || resource.PasswordRef == nil {
return nil
}
return []string{string(resource.PasswordRef)}
return []string{string(*resource.PasswordRef)}
},
)

Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,4 @@
---
apiVersion: v1
kind: Secret
metadata:
name: user-create-minimal
type: Opaque
stringData:
password: "TestPassword"
---
apiVersion: openstack.k-orc.cloud/v1alpha1
kind: User
metadata:
Expand All @@ -16,5 +8,4 @@ spec:
cloudName: openstack-admin
secretName: openstack-clouds
managementPolicy: managed
resource:
passwordRef: user-create-minimal
resource: {}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

## Step 00

Create a minimal User, that sets only the required fields, and verify that the observed state corresponds to the spec.
Create a minimal User without a password, and verify that the observed state corresponds to the spec.

Also validate that the OpenStack resource uses the name of the ORC object when no name is explicitly specified.

Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,4 @@
---
apiVersion: v1
kind: Secret
metadata:
name: user-import-dependency-password
type: Opaque
stringData:
password: "TestPassword"
---
apiVersion: openstack.k-orc.cloud/v1alpha1
kind: Domain
metadata:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,4 @@ spec:
secretName: openstack-clouds
managementPolicy: managed
resource:
domainRef: user-import-dependency-not-this-one
passwordRef: user-import-dependency-password
domainRef: user-import-dependency-not-this-one
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,4 @@ spec:
secretName: openstack-clouds
managementPolicy: managed
resource:
domainRef: user-import-dependency-external
passwordRef: user-import-dependency-password
domainRef: user-import-dependency-external
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,6 @@ spec:
managementPolicy: managed
resource: {}
---
apiVersion: v1
kind: Secret
metadata:
name: user-import-error-password
type: Opaque
stringData:
password: "TestPassword"
---
apiVersion: openstack.k-orc.cloud/v1alpha1
kind: User
metadata:
Expand All @@ -30,7 +22,6 @@ spec:
resource:
description: User from "import error" test
domainRef: user-import-error-domain
passwordRef: user-import-error-password
---
apiVersion: openstack.k-orc.cloud/v1alpha1
kind: User
Expand All @@ -43,5 +34,4 @@ spec:
managementPolicy: managed
resource:
description: User from "import error" test
domainRef: user-import-error-domain
passwordRef: user-import-error-password
domainRef: user-import-error-domain
Original file line number Diff line number Diff line change
@@ -1,12 +1,4 @@
---
apiVersion: v1
kind: Secret
metadata:
name: user-import-password
type: Opaque
stringData:
password: "TestPassword"
---
apiVersion: openstack.k-orc.cloud/v1alpha1
kind: Domain
metadata:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,4 @@ spec:
managementPolicy: managed
resource:
description: User user-import-external from "user-import" test
domainRef: user-import-external
passwordRef: user-import-password
domainRef: user-import-external
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,4 @@ spec:
managementPolicy: managed
resource:
description: User user-import-external from "user-import" test
domainRef: user-import-external
passwordRef: user-import-password
domainRef: user-import-external
26 changes: 20 additions & 6 deletions test/apivalidations/user_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,7 @@ func userStub(namespace *corev1.Namespace) *orcv1alpha1.User {
}

func testUserResource() *applyconfigv1alpha1.UserResourceSpecApplyConfiguration {
return applyconfigv1alpha1.UserResourceSpec().
WithPasswordRef("user-password")
return applyconfigv1alpha1.UserResourceSpec()
}

func baseUserPatch(user client.Object) *applyconfigv1alpha1.UserApplyConfiguration {
Expand Down Expand Up @@ -96,12 +95,10 @@ var _ = Describe("ORC User API validations", func() {
user := userStub(namespace)
patch := baseUserPatch(user)
patch.Spec.WithResource(applyconfigv1alpha1.UserResourceSpec().
WithPasswordRef("user-password").
WithDomainRef("domain-a"))
Expect(applyObj(ctx, user, patch)).To(Succeed())

patch.Spec.WithResource(applyconfigv1alpha1.UserResourceSpec().
WithPasswordRef("user-password").
WithDomainRef("domain-b"))
Expect(applyObj(ctx, user, patch)).To(MatchError(ContainSubstring("domainRef is immutable")))
})
Expand All @@ -110,16 +107,21 @@ var _ = Describe("ORC User API validations", func() {
user := userStub(namespace)
patch := baseUserPatch(user)
patch.Spec.WithResource(applyconfigv1alpha1.UserResourceSpec().
WithPasswordRef("user-password").
WithDefaultProjectRef("project-a"))
Expect(applyObj(ctx, user, patch)).To(Succeed())

patch.Spec.WithResource(applyconfigv1alpha1.UserResourceSpec().
WithPasswordRef("user-password").
WithDefaultProjectRef("project-b"))
Expect(applyObj(ctx, user, patch)).To(MatchError(ContainSubstring("defaultProjectRef is immutable")))
})

It("should allow omitting passwordRef", func(ctx context.Context) {
user := userStub(namespace)
patch := baseUserPatch(user)
patch.Spec.WithResource(applyconfigv1alpha1.UserResourceSpec())
Expect(applyObj(ctx, user, patch)).To(Succeed())
})

It("should have mutable passwordRef", func(ctx context.Context) {
user := userStub(namespace)
patch := baseUserPatch(user)
Expand All @@ -131,4 +133,16 @@ var _ = Describe("ORC User API validations", func() {
WithPasswordRef("password-b"))
Expect(applyObj(ctx, user, patch)).To(Succeed())
})

It("should not allow removing passwordRef once set", func(ctx context.Context) {
user := userStub(namespace)
patch := baseUserPatch(user)
patch.Spec.WithResource(applyconfigv1alpha1.UserResourceSpec().
WithPasswordRef("password-a"))
Expect(applyObj(ctx, user, patch)).To(Succeed())

patch.Spec.WithResource(applyconfigv1alpha1.UserResourceSpec().
WithDescription("updated"))
Expect(applyObj(ctx, user, patch)).To(MatchError(ContainSubstring("passwordRef may not be removed once set")))
})
})
2 changes: 1 addition & 1 deletion website/docs/crd-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -4436,7 +4436,7 @@ _Appears in:_
| `domainRef` _[KubernetesNameRef](#kubernetesnameref)_ | domainRef is a reference to the ORC Domain which this resource is associated with. | | MaxLength: 253 <br />MinLength: 1 <br />Optional: \{\} <br /> |
| `defaultProjectRef` _[KubernetesNameRef](#kubernetesnameref)_ | defaultProjectRef is a reference to the Default Project which this resource is associated with. | | MaxLength: 253 <br />MinLength: 1 <br />Optional: \{\} <br /> |
| `enabled` _boolean_ | enabled defines whether a user is enabled or disabled | | Optional: \{\} <br /> |
| `passwordRef` _[KubernetesNameRef](#kubernetesnameref)_ | passwordRef is a reference to a Secret containing the password<br />for this user. The Secret must contain a key named "password". | | MaxLength: 253 <br />MinLength: 1 <br />Required: \{\} <br /> |
| `passwordRef` _[KubernetesNameRef](#kubernetesnameref)_ | passwordRef is a reference to a Secret containing the password<br />for this user. The Secret must contain a key named "password".<br />If not specified, the user is created without a password. | | MaxLength: 253 <br />MinLength: 1 <br />Optional: \{\} <br /> |


#### UserResourceStatus
Expand Down
Loading