Change FederationDomain.Status to use Phase and Conditions
This commit is contained in:
parent
022fdb9cfd
commit
0b408f4fc0
@ -8,14 +8,17 @@ import (
|
|||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
// +kubebuilder:validation:Enum=Success;Duplicate;Invalid;SameIssuerHostMustUseSameSecret
|
type FederationDomainPhase string
|
||||||
type FederationDomainStatusCondition string
|
|
||||||
|
|
||||||
const (
|
const (
|
||||||
SuccessFederationDomainStatusCondition = FederationDomainStatusCondition("Success")
|
// FederationDomainPhasePending is the default phase for newly-created FederationDomain resources.
|
||||||
DuplicateFederationDomainStatusCondition = FederationDomainStatusCondition("Duplicate")
|
FederationDomainPhasePending FederationDomainPhase = "Pending"
|
||||||
SameIssuerHostMustUseSameSecretFederationDomainStatusCondition = FederationDomainStatusCondition("SameIssuerHostMustUseSameSecret")
|
|
||||||
InvalidFederationDomainStatusCondition = FederationDomainStatusCondition("Invalid")
|
// FederationDomainPhaseReady is the phase for an FederationDomain resource in a healthy state.
|
||||||
|
FederationDomainPhaseReady FederationDomainPhase = "Ready"
|
||||||
|
|
||||||
|
// FederationDomainPhaseError is the phase for an FederationDomain in an unhealthy state.
|
||||||
|
FederationDomainPhaseError FederationDomainPhase = "Error"
|
||||||
)
|
)
|
||||||
|
|
||||||
// FederationDomainTLSSpec is a struct that describes the TLS configuration for an OIDC Provider.
|
// FederationDomainTLSSpec is a struct that describes the TLS configuration for an OIDC Provider.
|
||||||
@ -263,20 +266,17 @@ type FederationDomainSecrets struct {
|
|||||||
|
|
||||||
// FederationDomainStatus is a struct that describes the actual state of an OIDC Provider.
|
// FederationDomainStatus is a struct that describes the actual state of an OIDC Provider.
|
||||||
type FederationDomainStatus struct {
|
type FederationDomainStatus struct {
|
||||||
// Status holds an enum that describes the state of this OIDC Provider. Note that this Status can
|
// Phase summarizes the overall status of the FederationDomain.
|
||||||
// represent success or failure.
|
// +kubebuilder:default=Pending
|
||||||
// +optional
|
// +kubebuilder:validation:Enum=Pending;Ready;Error
|
||||||
Status FederationDomainStatusCondition `json:"status,omitempty"`
|
Phase FederationDomainPhase `json:"phase,omitempty"`
|
||||||
|
|
||||||
// Message provides human-readable details about the Status.
|
// Conditions represent the observations of an FederationDomain's current state.
|
||||||
// +optional
|
// +patchMergeKey=type
|
||||||
Message string `json:"message,omitempty"`
|
// +patchStrategy=merge
|
||||||
|
// +listType=map
|
||||||
// LastUpdateTime holds the time at which the Status was last updated. It is a pointer to get
|
// +listMapKey=type
|
||||||
// around some undesirable behavior with respect to the empty metav1.Time value (see
|
Conditions []Condition `json:"conditions,omitempty" patchStrategy:"merge" patchMergeKey:"type"`
|
||||||
// https://github.com/kubernetes/kubernetes/issues/86811).
|
|
||||||
// +optional
|
|
||||||
LastUpdateTime *metav1.Time `json:"lastUpdateTime,omitempty"`
|
|
||||||
|
|
||||||
// Secrets contains information about this OIDC Provider's secrets.
|
// Secrets contains information about this OIDC Provider's secrets.
|
||||||
// +optional
|
// +optional
|
||||||
@ -288,7 +288,7 @@ type FederationDomainStatus struct {
|
|||||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||||
// +kubebuilder:resource:categories=pinniped
|
// +kubebuilder:resource:categories=pinniped
|
||||||
// +kubebuilder:printcolumn:name="Issuer",type=string,JSONPath=`.spec.issuer`
|
// +kubebuilder:printcolumn:name="Issuer",type=string,JSONPath=`.spec.issuer`
|
||||||
// +kubebuilder:printcolumn:name="Status",type=string,JSONPath=`.status.status`
|
// +kubebuilder:printcolumn:name="Phase",type=string,JSONPath=`.status.phase`
|
||||||
// +kubebuilder:printcolumn:name="Age",type=date,JSONPath=`.metadata.creationTimestamp`
|
// +kubebuilder:printcolumn:name="Age",type=date,JSONPath=`.metadata.creationTimestamp`
|
||||||
// +kubebuilder:subresource:status
|
// +kubebuilder:subresource:status
|
||||||
type FederationDomain struct {
|
type FederationDomain struct {
|
||||||
|
@ -8,14 +8,14 @@ import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|||||||
type OIDCClientPhase string
|
type OIDCClientPhase string
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// PhasePending is the default phase for newly-created OIDCClient resources.
|
// OIDCClientPhasePending is the default phase for newly-created OIDCClient resources.
|
||||||
PhasePending OIDCClientPhase = "Pending"
|
OIDCClientPhasePending OIDCClientPhase = "Pending"
|
||||||
|
|
||||||
// PhaseReady is the phase for an OIDCClient resource in a healthy state.
|
// OIDCClientPhaseReady is the phase for an OIDCClient resource in a healthy state.
|
||||||
PhaseReady OIDCClientPhase = "Ready"
|
OIDCClientPhaseReady OIDCClientPhase = "Ready"
|
||||||
|
|
||||||
// PhaseError is the phase for an OIDCClient in an unhealthy state.
|
// OIDCClientPhaseError is the phase for an OIDCClient in an unhealthy state.
|
||||||
PhaseError OIDCClientPhase = "Error"
|
OIDCClientPhaseError OIDCClientPhase = "Error"
|
||||||
)
|
)
|
||||||
|
|
||||||
// +kubebuilder:validation:Pattern=`^https://.+|^http://(127\.0\.0\.1|\[::1\])(:\d+)?/`
|
// +kubebuilder:validation:Pattern=`^https://.+|^http://(127\.0\.0\.1|\[::1\])(:\d+)?/`
|
||||||
|
@ -21,8 +21,8 @@ spec:
|
|||||||
- jsonPath: .spec.issuer
|
- jsonPath: .spec.issuer
|
||||||
name: Issuer
|
name: Issuer
|
||||||
type: string
|
type: string
|
||||||
- jsonPath: .status.status
|
- jsonPath: .status.phase
|
||||||
name: Status
|
name: Phase
|
||||||
type: string
|
type: string
|
||||||
- jsonPath: .metadata.creationTimestamp
|
- jsonPath: .metadata.creationTimestamp
|
||||||
name: Age
|
name: Age
|
||||||
@ -348,14 +348,80 @@ spec:
|
|||||||
status:
|
status:
|
||||||
description: Status of the OIDC provider.
|
description: Status of the OIDC provider.
|
||||||
properties:
|
properties:
|
||||||
lastUpdateTime:
|
conditions:
|
||||||
description: LastUpdateTime holds the time at which the Status was
|
description: Conditions represent the observations of an FederationDomain's
|
||||||
last updated. It is a pointer to get around some undesirable behavior
|
current state.
|
||||||
with respect to the empty metav1.Time value (see https://github.com/kubernetes/kubernetes/issues/86811).
|
items:
|
||||||
|
description: Condition status of a resource (mirrored from the metav1.Condition
|
||||||
|
type added in Kubernetes 1.19). In a future API version we can
|
||||||
|
switch to using the upstream type. See https://github.com/kubernetes/apimachinery/blob/v0.19.0/pkg/apis/meta/v1/types.go#L1353-L1413.
|
||||||
|
properties:
|
||||||
|
lastTransitionTime:
|
||||||
|
description: lastTransitionTime is the last time the condition
|
||||||
|
transitioned from one status to another. This should be when
|
||||||
|
the underlying condition changed. If that is not known, then
|
||||||
|
using the time when the API field changed is acceptable.
|
||||||
format: date-time
|
format: date-time
|
||||||
type: string
|
type: string
|
||||||
message:
|
message:
|
||||||
description: Message provides human-readable details about the Status.
|
description: message is a human readable message indicating
|
||||||
|
details about the transition. This may be an empty string.
|
||||||
|
maxLength: 32768
|
||||||
|
type: string
|
||||||
|
observedGeneration:
|
||||||
|
description: observedGeneration represents the .metadata.generation
|
||||||
|
that the condition was set based upon. For instance, if .metadata.generation
|
||||||
|
is currently 12, but the .status.conditions[x].observedGeneration
|
||||||
|
is 9, the condition is out of date with respect to the current
|
||||||
|
state of the instance.
|
||||||
|
format: int64
|
||||||
|
minimum: 0
|
||||||
|
type: integer
|
||||||
|
reason:
|
||||||
|
description: reason contains a programmatic identifier indicating
|
||||||
|
the reason for the condition's last transition. Producers
|
||||||
|
of specific condition types may define expected values and
|
||||||
|
meanings for this field, and whether the values are considered
|
||||||
|
a guaranteed API. The value should be a CamelCase string.
|
||||||
|
This field may not be empty.
|
||||||
|
maxLength: 1024
|
||||||
|
minLength: 1
|
||||||
|
pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$
|
||||||
|
type: string
|
||||||
|
status:
|
||||||
|
description: status of the condition, one of True, False, Unknown.
|
||||||
|
enum:
|
||||||
|
- "True"
|
||||||
|
- "False"
|
||||||
|
- Unknown
|
||||||
|
type: string
|
||||||
|
type:
|
||||||
|
description: type of condition in CamelCase or in foo.example.com/CamelCase.
|
||||||
|
--- Many .condition.type values are consistent across resources
|
||||||
|
like Available, but because arbitrary conditions can be useful
|
||||||
|
(see .node.status.conditions), the ability to deconflict is
|
||||||
|
important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt)
|
||||||
|
maxLength: 316
|
||||||
|
pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$
|
||||||
|
type: string
|
||||||
|
required:
|
||||||
|
- lastTransitionTime
|
||||||
|
- message
|
||||||
|
- reason
|
||||||
|
- status
|
||||||
|
- type
|
||||||
|
type: object
|
||||||
|
type: array
|
||||||
|
x-kubernetes-list-map-keys:
|
||||||
|
- type
|
||||||
|
x-kubernetes-list-type: map
|
||||||
|
phase:
|
||||||
|
default: Pending
|
||||||
|
description: Phase summarizes the overall status of the FederationDomain.
|
||||||
|
enum:
|
||||||
|
- Pending
|
||||||
|
- Ready
|
||||||
|
- Error
|
||||||
type: string
|
type: string
|
||||||
secrets:
|
secrets:
|
||||||
description: Secrets contains information about this OIDC Provider's
|
description: Secrets contains information about this OIDC Provider's
|
||||||
@ -402,15 +468,6 @@ spec:
|
|||||||
type: string
|
type: string
|
||||||
type: object
|
type: object
|
||||||
type: object
|
type: object
|
||||||
status:
|
|
||||||
description: Status holds an enum that describes the state of this
|
|
||||||
OIDC Provider. Note that this Status can represent success or failure.
|
|
||||||
enum:
|
|
||||||
- Success
|
|
||||||
- Duplicate
|
|
||||||
- Invalid
|
|
||||||
- SameIssuerHostMustUseSameSecret
|
|
||||||
type: string
|
|
||||||
type: object
|
type: object
|
||||||
required:
|
required:
|
||||||
- spec
|
- spec
|
||||||
|
5
generated/1.21/README.adoc
generated
5
generated/1.21/README.adoc
generated
@ -728,9 +728,8 @@ FederationDomainStatus is a struct that describes the actual state of an OIDC Pr
|
|||||||
[cols="25a,75a", options="header"]
|
[cols="25a,75a", options="header"]
|
||||||
|===
|
|===
|
||||||
| Field | Description
|
| Field | Description
|
||||||
| *`status`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-21-apis-supervisor-config-v1alpha1-federationdomainstatuscondition[$$FederationDomainStatusCondition$$]__ | Status holds an enum that describes the state of this OIDC Provider. Note that this Status can represent success or failure.
|
| *`phase`* __FederationDomainPhase__ | Phase summarizes the overall status of the FederationDomain.
|
||||||
| *`message`* __string__ | Message provides human-readable details about the Status.
|
| *`conditions`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-21-apis-supervisor-config-v1alpha1-condition[$$Condition$$] array__ | Conditions represent the observations of an FederationDomain's current state.
|
||||||
| *`lastUpdateTime`* __link:https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.21/#time-v1-meta[$$Time$$]__ | LastUpdateTime holds the time at which the Status was last updated. It is a pointer to get around some undesirable behavior with respect to the empty metav1.Time value (see https://github.com/kubernetes/kubernetes/issues/86811).
|
|
||||||
| *`secrets`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-21-apis-supervisor-config-v1alpha1-federationdomainsecrets[$$FederationDomainSecrets$$]__ | Secrets contains information about this OIDC Provider's secrets.
|
| *`secrets`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-21-apis-supervisor-config-v1alpha1-federationdomainsecrets[$$FederationDomainSecrets$$]__ | Secrets contains information about this OIDC Provider's secrets.
|
||||||
|===
|
|===
|
||||||
|
|
||||||
|
@ -8,14 +8,17 @@ import (
|
|||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
// +kubebuilder:validation:Enum=Success;Duplicate;Invalid;SameIssuerHostMustUseSameSecret
|
type FederationDomainPhase string
|
||||||
type FederationDomainStatusCondition string
|
|
||||||
|
|
||||||
const (
|
const (
|
||||||
SuccessFederationDomainStatusCondition = FederationDomainStatusCondition("Success")
|
// FederationDomainPhasePending is the default phase for newly-created FederationDomain resources.
|
||||||
DuplicateFederationDomainStatusCondition = FederationDomainStatusCondition("Duplicate")
|
FederationDomainPhasePending FederationDomainPhase = "Pending"
|
||||||
SameIssuerHostMustUseSameSecretFederationDomainStatusCondition = FederationDomainStatusCondition("SameIssuerHostMustUseSameSecret")
|
|
||||||
InvalidFederationDomainStatusCondition = FederationDomainStatusCondition("Invalid")
|
// FederationDomainPhaseReady is the phase for an FederationDomain resource in a healthy state.
|
||||||
|
FederationDomainPhaseReady FederationDomainPhase = "Ready"
|
||||||
|
|
||||||
|
// FederationDomainPhaseError is the phase for an FederationDomain in an unhealthy state.
|
||||||
|
FederationDomainPhaseError FederationDomainPhase = "Error"
|
||||||
)
|
)
|
||||||
|
|
||||||
// FederationDomainTLSSpec is a struct that describes the TLS configuration for an OIDC Provider.
|
// FederationDomainTLSSpec is a struct that describes the TLS configuration for an OIDC Provider.
|
||||||
@ -263,20 +266,17 @@ type FederationDomainSecrets struct {
|
|||||||
|
|
||||||
// FederationDomainStatus is a struct that describes the actual state of an OIDC Provider.
|
// FederationDomainStatus is a struct that describes the actual state of an OIDC Provider.
|
||||||
type FederationDomainStatus struct {
|
type FederationDomainStatus struct {
|
||||||
// Status holds an enum that describes the state of this OIDC Provider. Note that this Status can
|
// Phase summarizes the overall status of the FederationDomain.
|
||||||
// represent success or failure.
|
// +kubebuilder:default=Pending
|
||||||
// +optional
|
// +kubebuilder:validation:Enum=Pending;Ready;Error
|
||||||
Status FederationDomainStatusCondition `json:"status,omitempty"`
|
Phase FederationDomainPhase `json:"phase,omitempty"`
|
||||||
|
|
||||||
// Message provides human-readable details about the Status.
|
// Conditions represent the observations of an FederationDomain's current state.
|
||||||
// +optional
|
// +patchMergeKey=type
|
||||||
Message string `json:"message,omitempty"`
|
// +patchStrategy=merge
|
||||||
|
// +listType=map
|
||||||
// LastUpdateTime holds the time at which the Status was last updated. It is a pointer to get
|
// +listMapKey=type
|
||||||
// around some undesirable behavior with respect to the empty metav1.Time value (see
|
Conditions []Condition `json:"conditions,omitempty" patchStrategy:"merge" patchMergeKey:"type"`
|
||||||
// https://github.com/kubernetes/kubernetes/issues/86811).
|
|
||||||
// +optional
|
|
||||||
LastUpdateTime *metav1.Time `json:"lastUpdateTime,omitempty"`
|
|
||||||
|
|
||||||
// Secrets contains information about this OIDC Provider's secrets.
|
// Secrets contains information about this OIDC Provider's secrets.
|
||||||
// +optional
|
// +optional
|
||||||
@ -288,7 +288,7 @@ type FederationDomainStatus struct {
|
|||||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||||
// +kubebuilder:resource:categories=pinniped
|
// +kubebuilder:resource:categories=pinniped
|
||||||
// +kubebuilder:printcolumn:name="Issuer",type=string,JSONPath=`.spec.issuer`
|
// +kubebuilder:printcolumn:name="Issuer",type=string,JSONPath=`.spec.issuer`
|
||||||
// +kubebuilder:printcolumn:name="Status",type=string,JSONPath=`.status.status`
|
// +kubebuilder:printcolumn:name="Phase",type=string,JSONPath=`.status.phase`
|
||||||
// +kubebuilder:printcolumn:name="Age",type=date,JSONPath=`.metadata.creationTimestamp`
|
// +kubebuilder:printcolumn:name="Age",type=date,JSONPath=`.metadata.creationTimestamp`
|
||||||
// +kubebuilder:subresource:status
|
// +kubebuilder:subresource:status
|
||||||
type FederationDomain struct {
|
type FederationDomain struct {
|
||||||
|
@ -8,14 +8,14 @@ import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|||||||
type OIDCClientPhase string
|
type OIDCClientPhase string
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// PhasePending is the default phase for newly-created OIDCClient resources.
|
// OIDCClientPhasePending is the default phase for newly-created OIDCClient resources.
|
||||||
PhasePending OIDCClientPhase = "Pending"
|
OIDCClientPhasePending OIDCClientPhase = "Pending"
|
||||||
|
|
||||||
// PhaseReady is the phase for an OIDCClient resource in a healthy state.
|
// OIDCClientPhaseReady is the phase for an OIDCClient resource in a healthy state.
|
||||||
PhaseReady OIDCClientPhase = "Ready"
|
OIDCClientPhaseReady OIDCClientPhase = "Ready"
|
||||||
|
|
||||||
// PhaseError is the phase for an OIDCClient in an unhealthy state.
|
// OIDCClientPhaseError is the phase for an OIDCClient in an unhealthy state.
|
||||||
PhaseError OIDCClientPhase = "Error"
|
OIDCClientPhaseError OIDCClientPhase = "Error"
|
||||||
)
|
)
|
||||||
|
|
||||||
// +kubebuilder:validation:Pattern=`^https://.+|^http://(127\.0\.0\.1|\[::1\])(:\d+)?/`
|
// +kubebuilder:validation:Pattern=`^https://.+|^http://(127\.0\.0\.1|\[::1\])(:\d+)?/`
|
||||||
|
@ -143,9 +143,12 @@ func (in *FederationDomainSpec) DeepCopy() *FederationDomainSpec {
|
|||||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
func (in *FederationDomainStatus) DeepCopyInto(out *FederationDomainStatus) {
|
func (in *FederationDomainStatus) DeepCopyInto(out *FederationDomainStatus) {
|
||||||
*out = *in
|
*out = *in
|
||||||
if in.LastUpdateTime != nil {
|
if in.Conditions != nil {
|
||||||
in, out := &in.LastUpdateTime, &out.LastUpdateTime
|
in, out := &in.Conditions, &out.Conditions
|
||||||
*out = (*in).DeepCopy()
|
*out = make([]Condition, len(*in))
|
||||||
|
for i := range *in {
|
||||||
|
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||||
|
}
|
||||||
}
|
}
|
||||||
out.Secrets = in.Secrets
|
out.Secrets = in.Secrets
|
||||||
return
|
return
|
||||||
|
@ -21,8 +21,8 @@ spec:
|
|||||||
- jsonPath: .spec.issuer
|
- jsonPath: .spec.issuer
|
||||||
name: Issuer
|
name: Issuer
|
||||||
type: string
|
type: string
|
||||||
- jsonPath: .status.status
|
- jsonPath: .status.phase
|
||||||
name: Status
|
name: Phase
|
||||||
type: string
|
type: string
|
||||||
- jsonPath: .metadata.creationTimestamp
|
- jsonPath: .metadata.creationTimestamp
|
||||||
name: Age
|
name: Age
|
||||||
@ -348,14 +348,80 @@ spec:
|
|||||||
status:
|
status:
|
||||||
description: Status of the OIDC provider.
|
description: Status of the OIDC provider.
|
||||||
properties:
|
properties:
|
||||||
lastUpdateTime:
|
conditions:
|
||||||
description: LastUpdateTime holds the time at which the Status was
|
description: Conditions represent the observations of an FederationDomain's
|
||||||
last updated. It is a pointer to get around some undesirable behavior
|
current state.
|
||||||
with respect to the empty metav1.Time value (see https://github.com/kubernetes/kubernetes/issues/86811).
|
items:
|
||||||
|
description: Condition status of a resource (mirrored from the metav1.Condition
|
||||||
|
type added in Kubernetes 1.19). In a future API version we can
|
||||||
|
switch to using the upstream type. See https://github.com/kubernetes/apimachinery/blob/v0.19.0/pkg/apis/meta/v1/types.go#L1353-L1413.
|
||||||
|
properties:
|
||||||
|
lastTransitionTime:
|
||||||
|
description: lastTransitionTime is the last time the condition
|
||||||
|
transitioned from one status to another. This should be when
|
||||||
|
the underlying condition changed. If that is not known, then
|
||||||
|
using the time when the API field changed is acceptable.
|
||||||
format: date-time
|
format: date-time
|
||||||
type: string
|
type: string
|
||||||
message:
|
message:
|
||||||
description: Message provides human-readable details about the Status.
|
description: message is a human readable message indicating
|
||||||
|
details about the transition. This may be an empty string.
|
||||||
|
maxLength: 32768
|
||||||
|
type: string
|
||||||
|
observedGeneration:
|
||||||
|
description: observedGeneration represents the .metadata.generation
|
||||||
|
that the condition was set based upon. For instance, if .metadata.generation
|
||||||
|
is currently 12, but the .status.conditions[x].observedGeneration
|
||||||
|
is 9, the condition is out of date with respect to the current
|
||||||
|
state of the instance.
|
||||||
|
format: int64
|
||||||
|
minimum: 0
|
||||||
|
type: integer
|
||||||
|
reason:
|
||||||
|
description: reason contains a programmatic identifier indicating
|
||||||
|
the reason for the condition's last transition. Producers
|
||||||
|
of specific condition types may define expected values and
|
||||||
|
meanings for this field, and whether the values are considered
|
||||||
|
a guaranteed API. The value should be a CamelCase string.
|
||||||
|
This field may not be empty.
|
||||||
|
maxLength: 1024
|
||||||
|
minLength: 1
|
||||||
|
pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$
|
||||||
|
type: string
|
||||||
|
status:
|
||||||
|
description: status of the condition, one of True, False, Unknown.
|
||||||
|
enum:
|
||||||
|
- "True"
|
||||||
|
- "False"
|
||||||
|
- Unknown
|
||||||
|
type: string
|
||||||
|
type:
|
||||||
|
description: type of condition in CamelCase or in foo.example.com/CamelCase.
|
||||||
|
--- Many .condition.type values are consistent across resources
|
||||||
|
like Available, but because arbitrary conditions can be useful
|
||||||
|
(see .node.status.conditions), the ability to deconflict is
|
||||||
|
important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt)
|
||||||
|
maxLength: 316
|
||||||
|
pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$
|
||||||
|
type: string
|
||||||
|
required:
|
||||||
|
- lastTransitionTime
|
||||||
|
- message
|
||||||
|
- reason
|
||||||
|
- status
|
||||||
|
- type
|
||||||
|
type: object
|
||||||
|
type: array
|
||||||
|
x-kubernetes-list-map-keys:
|
||||||
|
- type
|
||||||
|
x-kubernetes-list-type: map
|
||||||
|
phase:
|
||||||
|
default: Pending
|
||||||
|
description: Phase summarizes the overall status of the FederationDomain.
|
||||||
|
enum:
|
||||||
|
- Pending
|
||||||
|
- Ready
|
||||||
|
- Error
|
||||||
type: string
|
type: string
|
||||||
secrets:
|
secrets:
|
||||||
description: Secrets contains information about this OIDC Provider's
|
description: Secrets contains information about this OIDC Provider's
|
||||||
@ -402,15 +468,6 @@ spec:
|
|||||||
type: string
|
type: string
|
||||||
type: object
|
type: object
|
||||||
type: object
|
type: object
|
||||||
status:
|
|
||||||
description: Status holds an enum that describes the state of this
|
|
||||||
OIDC Provider. Note that this Status can represent success or failure.
|
|
||||||
enum:
|
|
||||||
- Success
|
|
||||||
- Duplicate
|
|
||||||
- Invalid
|
|
||||||
- SameIssuerHostMustUseSameSecret
|
|
||||||
type: string
|
|
||||||
type: object
|
type: object
|
||||||
required:
|
required:
|
||||||
- spec
|
- spec
|
||||||
|
5
generated/1.22/README.adoc
generated
5
generated/1.22/README.adoc
generated
@ -728,9 +728,8 @@ FederationDomainStatus is a struct that describes the actual state of an OIDC Pr
|
|||||||
[cols="25a,75a", options="header"]
|
[cols="25a,75a", options="header"]
|
||||||
|===
|
|===
|
||||||
| Field | Description
|
| Field | Description
|
||||||
| *`status`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-22-apis-supervisor-config-v1alpha1-federationdomainstatuscondition[$$FederationDomainStatusCondition$$]__ | Status holds an enum that describes the state of this OIDC Provider. Note that this Status can represent success or failure.
|
| *`phase`* __FederationDomainPhase__ | Phase summarizes the overall status of the FederationDomain.
|
||||||
| *`message`* __string__ | Message provides human-readable details about the Status.
|
| *`conditions`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-22-apis-supervisor-config-v1alpha1-condition[$$Condition$$] array__ | Conditions represent the observations of an FederationDomain's current state.
|
||||||
| *`lastUpdateTime`* __link:https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.22/#time-v1-meta[$$Time$$]__ | LastUpdateTime holds the time at which the Status was last updated. It is a pointer to get around some undesirable behavior with respect to the empty metav1.Time value (see https://github.com/kubernetes/kubernetes/issues/86811).
|
|
||||||
| *`secrets`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-22-apis-supervisor-config-v1alpha1-federationdomainsecrets[$$FederationDomainSecrets$$]__ | Secrets contains information about this OIDC Provider's secrets.
|
| *`secrets`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-22-apis-supervisor-config-v1alpha1-federationdomainsecrets[$$FederationDomainSecrets$$]__ | Secrets contains information about this OIDC Provider's secrets.
|
||||||
|===
|
|===
|
||||||
|
|
||||||
|
@ -8,14 +8,17 @@ import (
|
|||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
// +kubebuilder:validation:Enum=Success;Duplicate;Invalid;SameIssuerHostMustUseSameSecret
|
type FederationDomainPhase string
|
||||||
type FederationDomainStatusCondition string
|
|
||||||
|
|
||||||
const (
|
const (
|
||||||
SuccessFederationDomainStatusCondition = FederationDomainStatusCondition("Success")
|
// FederationDomainPhasePending is the default phase for newly-created FederationDomain resources.
|
||||||
DuplicateFederationDomainStatusCondition = FederationDomainStatusCondition("Duplicate")
|
FederationDomainPhasePending FederationDomainPhase = "Pending"
|
||||||
SameIssuerHostMustUseSameSecretFederationDomainStatusCondition = FederationDomainStatusCondition("SameIssuerHostMustUseSameSecret")
|
|
||||||
InvalidFederationDomainStatusCondition = FederationDomainStatusCondition("Invalid")
|
// FederationDomainPhaseReady is the phase for an FederationDomain resource in a healthy state.
|
||||||
|
FederationDomainPhaseReady FederationDomainPhase = "Ready"
|
||||||
|
|
||||||
|
// FederationDomainPhaseError is the phase for an FederationDomain in an unhealthy state.
|
||||||
|
FederationDomainPhaseError FederationDomainPhase = "Error"
|
||||||
)
|
)
|
||||||
|
|
||||||
// FederationDomainTLSSpec is a struct that describes the TLS configuration for an OIDC Provider.
|
// FederationDomainTLSSpec is a struct that describes the TLS configuration for an OIDC Provider.
|
||||||
@ -263,20 +266,17 @@ type FederationDomainSecrets struct {
|
|||||||
|
|
||||||
// FederationDomainStatus is a struct that describes the actual state of an OIDC Provider.
|
// FederationDomainStatus is a struct that describes the actual state of an OIDC Provider.
|
||||||
type FederationDomainStatus struct {
|
type FederationDomainStatus struct {
|
||||||
// Status holds an enum that describes the state of this OIDC Provider. Note that this Status can
|
// Phase summarizes the overall status of the FederationDomain.
|
||||||
// represent success or failure.
|
// +kubebuilder:default=Pending
|
||||||
// +optional
|
// +kubebuilder:validation:Enum=Pending;Ready;Error
|
||||||
Status FederationDomainStatusCondition `json:"status,omitempty"`
|
Phase FederationDomainPhase `json:"phase,omitempty"`
|
||||||
|
|
||||||
// Message provides human-readable details about the Status.
|
// Conditions represent the observations of an FederationDomain's current state.
|
||||||
// +optional
|
// +patchMergeKey=type
|
||||||
Message string `json:"message,omitempty"`
|
// +patchStrategy=merge
|
||||||
|
// +listType=map
|
||||||
// LastUpdateTime holds the time at which the Status was last updated. It is a pointer to get
|
// +listMapKey=type
|
||||||
// around some undesirable behavior with respect to the empty metav1.Time value (see
|
Conditions []Condition `json:"conditions,omitempty" patchStrategy:"merge" patchMergeKey:"type"`
|
||||||
// https://github.com/kubernetes/kubernetes/issues/86811).
|
|
||||||
// +optional
|
|
||||||
LastUpdateTime *metav1.Time `json:"lastUpdateTime,omitempty"`
|
|
||||||
|
|
||||||
// Secrets contains information about this OIDC Provider's secrets.
|
// Secrets contains information about this OIDC Provider's secrets.
|
||||||
// +optional
|
// +optional
|
||||||
@ -288,7 +288,7 @@ type FederationDomainStatus struct {
|
|||||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||||
// +kubebuilder:resource:categories=pinniped
|
// +kubebuilder:resource:categories=pinniped
|
||||||
// +kubebuilder:printcolumn:name="Issuer",type=string,JSONPath=`.spec.issuer`
|
// +kubebuilder:printcolumn:name="Issuer",type=string,JSONPath=`.spec.issuer`
|
||||||
// +kubebuilder:printcolumn:name="Status",type=string,JSONPath=`.status.status`
|
// +kubebuilder:printcolumn:name="Phase",type=string,JSONPath=`.status.phase`
|
||||||
// +kubebuilder:printcolumn:name="Age",type=date,JSONPath=`.metadata.creationTimestamp`
|
// +kubebuilder:printcolumn:name="Age",type=date,JSONPath=`.metadata.creationTimestamp`
|
||||||
// +kubebuilder:subresource:status
|
// +kubebuilder:subresource:status
|
||||||
type FederationDomain struct {
|
type FederationDomain struct {
|
||||||
|
@ -8,14 +8,14 @@ import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|||||||
type OIDCClientPhase string
|
type OIDCClientPhase string
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// PhasePending is the default phase for newly-created OIDCClient resources.
|
// OIDCClientPhasePending is the default phase for newly-created OIDCClient resources.
|
||||||
PhasePending OIDCClientPhase = "Pending"
|
OIDCClientPhasePending OIDCClientPhase = "Pending"
|
||||||
|
|
||||||
// PhaseReady is the phase for an OIDCClient resource in a healthy state.
|
// OIDCClientPhaseReady is the phase for an OIDCClient resource in a healthy state.
|
||||||
PhaseReady OIDCClientPhase = "Ready"
|
OIDCClientPhaseReady OIDCClientPhase = "Ready"
|
||||||
|
|
||||||
// PhaseError is the phase for an OIDCClient in an unhealthy state.
|
// OIDCClientPhaseError is the phase for an OIDCClient in an unhealthy state.
|
||||||
PhaseError OIDCClientPhase = "Error"
|
OIDCClientPhaseError OIDCClientPhase = "Error"
|
||||||
)
|
)
|
||||||
|
|
||||||
// +kubebuilder:validation:Pattern=`^https://.+|^http://(127\.0\.0\.1|\[::1\])(:\d+)?/`
|
// +kubebuilder:validation:Pattern=`^https://.+|^http://(127\.0\.0\.1|\[::1\])(:\d+)?/`
|
||||||
|
@ -143,9 +143,12 @@ func (in *FederationDomainSpec) DeepCopy() *FederationDomainSpec {
|
|||||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
func (in *FederationDomainStatus) DeepCopyInto(out *FederationDomainStatus) {
|
func (in *FederationDomainStatus) DeepCopyInto(out *FederationDomainStatus) {
|
||||||
*out = *in
|
*out = *in
|
||||||
if in.LastUpdateTime != nil {
|
if in.Conditions != nil {
|
||||||
in, out := &in.LastUpdateTime, &out.LastUpdateTime
|
in, out := &in.Conditions, &out.Conditions
|
||||||
*out = (*in).DeepCopy()
|
*out = make([]Condition, len(*in))
|
||||||
|
for i := range *in {
|
||||||
|
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||||
|
}
|
||||||
}
|
}
|
||||||
out.Secrets = in.Secrets
|
out.Secrets = in.Secrets
|
||||||
return
|
return
|
||||||
|
@ -21,8 +21,8 @@ spec:
|
|||||||
- jsonPath: .spec.issuer
|
- jsonPath: .spec.issuer
|
||||||
name: Issuer
|
name: Issuer
|
||||||
type: string
|
type: string
|
||||||
- jsonPath: .status.status
|
- jsonPath: .status.phase
|
||||||
name: Status
|
name: Phase
|
||||||
type: string
|
type: string
|
||||||
- jsonPath: .metadata.creationTimestamp
|
- jsonPath: .metadata.creationTimestamp
|
||||||
name: Age
|
name: Age
|
||||||
@ -348,14 +348,80 @@ spec:
|
|||||||
status:
|
status:
|
||||||
description: Status of the OIDC provider.
|
description: Status of the OIDC provider.
|
||||||
properties:
|
properties:
|
||||||
lastUpdateTime:
|
conditions:
|
||||||
description: LastUpdateTime holds the time at which the Status was
|
description: Conditions represent the observations of an FederationDomain's
|
||||||
last updated. It is a pointer to get around some undesirable behavior
|
current state.
|
||||||
with respect to the empty metav1.Time value (see https://github.com/kubernetes/kubernetes/issues/86811).
|
items:
|
||||||
|
description: Condition status of a resource (mirrored from the metav1.Condition
|
||||||
|
type added in Kubernetes 1.19). In a future API version we can
|
||||||
|
switch to using the upstream type. See https://github.com/kubernetes/apimachinery/blob/v0.19.0/pkg/apis/meta/v1/types.go#L1353-L1413.
|
||||||
|
properties:
|
||||||
|
lastTransitionTime:
|
||||||
|
description: lastTransitionTime is the last time the condition
|
||||||
|
transitioned from one status to another. This should be when
|
||||||
|
the underlying condition changed. If that is not known, then
|
||||||
|
using the time when the API field changed is acceptable.
|
||||||
format: date-time
|
format: date-time
|
||||||
type: string
|
type: string
|
||||||
message:
|
message:
|
||||||
description: Message provides human-readable details about the Status.
|
description: message is a human readable message indicating
|
||||||
|
details about the transition. This may be an empty string.
|
||||||
|
maxLength: 32768
|
||||||
|
type: string
|
||||||
|
observedGeneration:
|
||||||
|
description: observedGeneration represents the .metadata.generation
|
||||||
|
that the condition was set based upon. For instance, if .metadata.generation
|
||||||
|
is currently 12, but the .status.conditions[x].observedGeneration
|
||||||
|
is 9, the condition is out of date with respect to the current
|
||||||
|
state of the instance.
|
||||||
|
format: int64
|
||||||
|
minimum: 0
|
||||||
|
type: integer
|
||||||
|
reason:
|
||||||
|
description: reason contains a programmatic identifier indicating
|
||||||
|
the reason for the condition's last transition. Producers
|
||||||
|
of specific condition types may define expected values and
|
||||||
|
meanings for this field, and whether the values are considered
|
||||||
|
a guaranteed API. The value should be a CamelCase string.
|
||||||
|
This field may not be empty.
|
||||||
|
maxLength: 1024
|
||||||
|
minLength: 1
|
||||||
|
pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$
|
||||||
|
type: string
|
||||||
|
status:
|
||||||
|
description: status of the condition, one of True, False, Unknown.
|
||||||
|
enum:
|
||||||
|
- "True"
|
||||||
|
- "False"
|
||||||
|
- Unknown
|
||||||
|
type: string
|
||||||
|
type:
|
||||||
|
description: type of condition in CamelCase or in foo.example.com/CamelCase.
|
||||||
|
--- Many .condition.type values are consistent across resources
|
||||||
|
like Available, but because arbitrary conditions can be useful
|
||||||
|
(see .node.status.conditions), the ability to deconflict is
|
||||||
|
important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt)
|
||||||
|
maxLength: 316
|
||||||
|
pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$
|
||||||
|
type: string
|
||||||
|
required:
|
||||||
|
- lastTransitionTime
|
||||||
|
- message
|
||||||
|
- reason
|
||||||
|
- status
|
||||||
|
- type
|
||||||
|
type: object
|
||||||
|
type: array
|
||||||
|
x-kubernetes-list-map-keys:
|
||||||
|
- type
|
||||||
|
x-kubernetes-list-type: map
|
||||||
|
phase:
|
||||||
|
default: Pending
|
||||||
|
description: Phase summarizes the overall status of the FederationDomain.
|
||||||
|
enum:
|
||||||
|
- Pending
|
||||||
|
- Ready
|
||||||
|
- Error
|
||||||
type: string
|
type: string
|
||||||
secrets:
|
secrets:
|
||||||
description: Secrets contains information about this OIDC Provider's
|
description: Secrets contains information about this OIDC Provider's
|
||||||
@ -402,15 +468,6 @@ spec:
|
|||||||
type: string
|
type: string
|
||||||
type: object
|
type: object
|
||||||
type: object
|
type: object
|
||||||
status:
|
|
||||||
description: Status holds an enum that describes the state of this
|
|
||||||
OIDC Provider. Note that this Status can represent success or failure.
|
|
||||||
enum:
|
|
||||||
- Success
|
|
||||||
- Duplicate
|
|
||||||
- Invalid
|
|
||||||
- SameIssuerHostMustUseSameSecret
|
|
||||||
type: string
|
|
||||||
type: object
|
type: object
|
||||||
required:
|
required:
|
||||||
- spec
|
- spec
|
||||||
|
5
generated/1.23/README.adoc
generated
5
generated/1.23/README.adoc
generated
@ -728,9 +728,8 @@ FederationDomainStatus is a struct that describes the actual state of an OIDC Pr
|
|||||||
[cols="25a,75a", options="header"]
|
[cols="25a,75a", options="header"]
|
||||||
|===
|
|===
|
||||||
| Field | Description
|
| Field | Description
|
||||||
| *`status`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-23-apis-supervisor-config-v1alpha1-federationdomainstatuscondition[$$FederationDomainStatusCondition$$]__ | Status holds an enum that describes the state of this OIDC Provider. Note that this Status can represent success or failure.
|
| *`phase`* __FederationDomainPhase__ | Phase summarizes the overall status of the FederationDomain.
|
||||||
| *`message`* __string__ | Message provides human-readable details about the Status.
|
| *`conditions`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-23-apis-supervisor-config-v1alpha1-condition[$$Condition$$] array__ | Conditions represent the observations of an FederationDomain's current state.
|
||||||
| *`lastUpdateTime`* __link:https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#time-v1-meta[$$Time$$]__ | LastUpdateTime holds the time at which the Status was last updated. It is a pointer to get around some undesirable behavior with respect to the empty metav1.Time value (see https://github.com/kubernetes/kubernetes/issues/86811).
|
|
||||||
| *`secrets`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-23-apis-supervisor-config-v1alpha1-federationdomainsecrets[$$FederationDomainSecrets$$]__ | Secrets contains information about this OIDC Provider's secrets.
|
| *`secrets`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-23-apis-supervisor-config-v1alpha1-federationdomainsecrets[$$FederationDomainSecrets$$]__ | Secrets contains information about this OIDC Provider's secrets.
|
||||||
|===
|
|===
|
||||||
|
|
||||||
|
@ -8,14 +8,17 @@ import (
|
|||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
// +kubebuilder:validation:Enum=Success;Duplicate;Invalid;SameIssuerHostMustUseSameSecret
|
type FederationDomainPhase string
|
||||||
type FederationDomainStatusCondition string
|
|
||||||
|
|
||||||
const (
|
const (
|
||||||
SuccessFederationDomainStatusCondition = FederationDomainStatusCondition("Success")
|
// FederationDomainPhasePending is the default phase for newly-created FederationDomain resources.
|
||||||
DuplicateFederationDomainStatusCondition = FederationDomainStatusCondition("Duplicate")
|
FederationDomainPhasePending FederationDomainPhase = "Pending"
|
||||||
SameIssuerHostMustUseSameSecretFederationDomainStatusCondition = FederationDomainStatusCondition("SameIssuerHostMustUseSameSecret")
|
|
||||||
InvalidFederationDomainStatusCondition = FederationDomainStatusCondition("Invalid")
|
// FederationDomainPhaseReady is the phase for an FederationDomain resource in a healthy state.
|
||||||
|
FederationDomainPhaseReady FederationDomainPhase = "Ready"
|
||||||
|
|
||||||
|
// FederationDomainPhaseError is the phase for an FederationDomain in an unhealthy state.
|
||||||
|
FederationDomainPhaseError FederationDomainPhase = "Error"
|
||||||
)
|
)
|
||||||
|
|
||||||
// FederationDomainTLSSpec is a struct that describes the TLS configuration for an OIDC Provider.
|
// FederationDomainTLSSpec is a struct that describes the TLS configuration for an OIDC Provider.
|
||||||
@ -263,20 +266,17 @@ type FederationDomainSecrets struct {
|
|||||||
|
|
||||||
// FederationDomainStatus is a struct that describes the actual state of an OIDC Provider.
|
// FederationDomainStatus is a struct that describes the actual state of an OIDC Provider.
|
||||||
type FederationDomainStatus struct {
|
type FederationDomainStatus struct {
|
||||||
// Status holds an enum that describes the state of this OIDC Provider. Note that this Status can
|
// Phase summarizes the overall status of the FederationDomain.
|
||||||
// represent success or failure.
|
// +kubebuilder:default=Pending
|
||||||
// +optional
|
// +kubebuilder:validation:Enum=Pending;Ready;Error
|
||||||
Status FederationDomainStatusCondition `json:"status,omitempty"`
|
Phase FederationDomainPhase `json:"phase,omitempty"`
|
||||||
|
|
||||||
// Message provides human-readable details about the Status.
|
// Conditions represent the observations of an FederationDomain's current state.
|
||||||
// +optional
|
// +patchMergeKey=type
|
||||||
Message string `json:"message,omitempty"`
|
// +patchStrategy=merge
|
||||||
|
// +listType=map
|
||||||
// LastUpdateTime holds the time at which the Status was last updated. It is a pointer to get
|
// +listMapKey=type
|
||||||
// around some undesirable behavior with respect to the empty metav1.Time value (see
|
Conditions []Condition `json:"conditions,omitempty" patchStrategy:"merge" patchMergeKey:"type"`
|
||||||
// https://github.com/kubernetes/kubernetes/issues/86811).
|
|
||||||
// +optional
|
|
||||||
LastUpdateTime *metav1.Time `json:"lastUpdateTime,omitempty"`
|
|
||||||
|
|
||||||
// Secrets contains information about this OIDC Provider's secrets.
|
// Secrets contains information about this OIDC Provider's secrets.
|
||||||
// +optional
|
// +optional
|
||||||
@ -288,7 +288,7 @@ type FederationDomainStatus struct {
|
|||||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||||
// +kubebuilder:resource:categories=pinniped
|
// +kubebuilder:resource:categories=pinniped
|
||||||
// +kubebuilder:printcolumn:name="Issuer",type=string,JSONPath=`.spec.issuer`
|
// +kubebuilder:printcolumn:name="Issuer",type=string,JSONPath=`.spec.issuer`
|
||||||
// +kubebuilder:printcolumn:name="Status",type=string,JSONPath=`.status.status`
|
// +kubebuilder:printcolumn:name="Phase",type=string,JSONPath=`.status.phase`
|
||||||
// +kubebuilder:printcolumn:name="Age",type=date,JSONPath=`.metadata.creationTimestamp`
|
// +kubebuilder:printcolumn:name="Age",type=date,JSONPath=`.metadata.creationTimestamp`
|
||||||
// +kubebuilder:subresource:status
|
// +kubebuilder:subresource:status
|
||||||
type FederationDomain struct {
|
type FederationDomain struct {
|
||||||
|
@ -8,14 +8,14 @@ import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|||||||
type OIDCClientPhase string
|
type OIDCClientPhase string
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// PhasePending is the default phase for newly-created OIDCClient resources.
|
// OIDCClientPhasePending is the default phase for newly-created OIDCClient resources.
|
||||||
PhasePending OIDCClientPhase = "Pending"
|
OIDCClientPhasePending OIDCClientPhase = "Pending"
|
||||||
|
|
||||||
// PhaseReady is the phase for an OIDCClient resource in a healthy state.
|
// OIDCClientPhaseReady is the phase for an OIDCClient resource in a healthy state.
|
||||||
PhaseReady OIDCClientPhase = "Ready"
|
OIDCClientPhaseReady OIDCClientPhase = "Ready"
|
||||||
|
|
||||||
// PhaseError is the phase for an OIDCClient in an unhealthy state.
|
// OIDCClientPhaseError is the phase for an OIDCClient in an unhealthy state.
|
||||||
PhaseError OIDCClientPhase = "Error"
|
OIDCClientPhaseError OIDCClientPhase = "Error"
|
||||||
)
|
)
|
||||||
|
|
||||||
// +kubebuilder:validation:Pattern=`^https://.+|^http://(127\.0\.0\.1|\[::1\])(:\d+)?/`
|
// +kubebuilder:validation:Pattern=`^https://.+|^http://(127\.0\.0\.1|\[::1\])(:\d+)?/`
|
||||||
|
@ -143,9 +143,12 @@ func (in *FederationDomainSpec) DeepCopy() *FederationDomainSpec {
|
|||||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
func (in *FederationDomainStatus) DeepCopyInto(out *FederationDomainStatus) {
|
func (in *FederationDomainStatus) DeepCopyInto(out *FederationDomainStatus) {
|
||||||
*out = *in
|
*out = *in
|
||||||
if in.LastUpdateTime != nil {
|
if in.Conditions != nil {
|
||||||
in, out := &in.LastUpdateTime, &out.LastUpdateTime
|
in, out := &in.Conditions, &out.Conditions
|
||||||
*out = (*in).DeepCopy()
|
*out = make([]Condition, len(*in))
|
||||||
|
for i := range *in {
|
||||||
|
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||||
|
}
|
||||||
}
|
}
|
||||||
out.Secrets = in.Secrets
|
out.Secrets = in.Secrets
|
||||||
return
|
return
|
||||||
|
@ -21,8 +21,8 @@ spec:
|
|||||||
- jsonPath: .spec.issuer
|
- jsonPath: .spec.issuer
|
||||||
name: Issuer
|
name: Issuer
|
||||||
type: string
|
type: string
|
||||||
- jsonPath: .status.status
|
- jsonPath: .status.phase
|
||||||
name: Status
|
name: Phase
|
||||||
type: string
|
type: string
|
||||||
- jsonPath: .metadata.creationTimestamp
|
- jsonPath: .metadata.creationTimestamp
|
||||||
name: Age
|
name: Age
|
||||||
@ -348,14 +348,80 @@ spec:
|
|||||||
status:
|
status:
|
||||||
description: Status of the OIDC provider.
|
description: Status of the OIDC provider.
|
||||||
properties:
|
properties:
|
||||||
lastUpdateTime:
|
conditions:
|
||||||
description: LastUpdateTime holds the time at which the Status was
|
description: Conditions represent the observations of an FederationDomain's
|
||||||
last updated. It is a pointer to get around some undesirable behavior
|
current state.
|
||||||
with respect to the empty metav1.Time value (see https://github.com/kubernetes/kubernetes/issues/86811).
|
items:
|
||||||
|
description: Condition status of a resource (mirrored from the metav1.Condition
|
||||||
|
type added in Kubernetes 1.19). In a future API version we can
|
||||||
|
switch to using the upstream type. See https://github.com/kubernetes/apimachinery/blob/v0.19.0/pkg/apis/meta/v1/types.go#L1353-L1413.
|
||||||
|
properties:
|
||||||
|
lastTransitionTime:
|
||||||
|
description: lastTransitionTime is the last time the condition
|
||||||
|
transitioned from one status to another. This should be when
|
||||||
|
the underlying condition changed. If that is not known, then
|
||||||
|
using the time when the API field changed is acceptable.
|
||||||
format: date-time
|
format: date-time
|
||||||
type: string
|
type: string
|
||||||
message:
|
message:
|
||||||
description: Message provides human-readable details about the Status.
|
description: message is a human readable message indicating
|
||||||
|
details about the transition. This may be an empty string.
|
||||||
|
maxLength: 32768
|
||||||
|
type: string
|
||||||
|
observedGeneration:
|
||||||
|
description: observedGeneration represents the .metadata.generation
|
||||||
|
that the condition was set based upon. For instance, if .metadata.generation
|
||||||
|
is currently 12, but the .status.conditions[x].observedGeneration
|
||||||
|
is 9, the condition is out of date with respect to the current
|
||||||
|
state of the instance.
|
||||||
|
format: int64
|
||||||
|
minimum: 0
|
||||||
|
type: integer
|
||||||
|
reason:
|
||||||
|
description: reason contains a programmatic identifier indicating
|
||||||
|
the reason for the condition's last transition. Producers
|
||||||
|
of specific condition types may define expected values and
|
||||||
|
meanings for this field, and whether the values are considered
|
||||||
|
a guaranteed API. The value should be a CamelCase string.
|
||||||
|
This field may not be empty.
|
||||||
|
maxLength: 1024
|
||||||
|
minLength: 1
|
||||||
|
pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$
|
||||||
|
type: string
|
||||||
|
status:
|
||||||
|
description: status of the condition, one of True, False, Unknown.
|
||||||
|
enum:
|
||||||
|
- "True"
|
||||||
|
- "False"
|
||||||
|
- Unknown
|
||||||
|
type: string
|
||||||
|
type:
|
||||||
|
description: type of condition in CamelCase or in foo.example.com/CamelCase.
|
||||||
|
--- Many .condition.type values are consistent across resources
|
||||||
|
like Available, but because arbitrary conditions can be useful
|
||||||
|
(see .node.status.conditions), the ability to deconflict is
|
||||||
|
important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt)
|
||||||
|
maxLength: 316
|
||||||
|
pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$
|
||||||
|
type: string
|
||||||
|
required:
|
||||||
|
- lastTransitionTime
|
||||||
|
- message
|
||||||
|
- reason
|
||||||
|
- status
|
||||||
|
- type
|
||||||
|
type: object
|
||||||
|
type: array
|
||||||
|
x-kubernetes-list-map-keys:
|
||||||
|
- type
|
||||||
|
x-kubernetes-list-type: map
|
||||||
|
phase:
|
||||||
|
default: Pending
|
||||||
|
description: Phase summarizes the overall status of the FederationDomain.
|
||||||
|
enum:
|
||||||
|
- Pending
|
||||||
|
- Ready
|
||||||
|
- Error
|
||||||
type: string
|
type: string
|
||||||
secrets:
|
secrets:
|
||||||
description: Secrets contains information about this OIDC Provider's
|
description: Secrets contains information about this OIDC Provider's
|
||||||
@ -402,15 +468,6 @@ spec:
|
|||||||
type: string
|
type: string
|
||||||
type: object
|
type: object
|
||||||
type: object
|
type: object
|
||||||
status:
|
|
||||||
description: Status holds an enum that describes the state of this
|
|
||||||
OIDC Provider. Note that this Status can represent success or failure.
|
|
||||||
enum:
|
|
||||||
- Success
|
|
||||||
- Duplicate
|
|
||||||
- Invalid
|
|
||||||
- SameIssuerHostMustUseSameSecret
|
|
||||||
type: string
|
|
||||||
type: object
|
type: object
|
||||||
required:
|
required:
|
||||||
- spec
|
- spec
|
||||||
|
5
generated/1.24/README.adoc
generated
5
generated/1.24/README.adoc
generated
@ -728,9 +728,8 @@ FederationDomainStatus is a struct that describes the actual state of an OIDC Pr
|
|||||||
[cols="25a,75a", options="header"]
|
[cols="25a,75a", options="header"]
|
||||||
|===
|
|===
|
||||||
| Field | Description
|
| Field | Description
|
||||||
| *`status`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-24-apis-supervisor-config-v1alpha1-federationdomainstatuscondition[$$FederationDomainStatusCondition$$]__ | Status holds an enum that describes the state of this OIDC Provider. Note that this Status can represent success or failure.
|
| *`phase`* __FederationDomainPhase__ | Phase summarizes the overall status of the FederationDomain.
|
||||||
| *`message`* __string__ | Message provides human-readable details about the Status.
|
| *`conditions`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-24-apis-supervisor-config-v1alpha1-condition[$$Condition$$] array__ | Conditions represent the observations of an FederationDomain's current state.
|
||||||
| *`lastUpdateTime`* __link:https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.24/#time-v1-meta[$$Time$$]__ | LastUpdateTime holds the time at which the Status was last updated. It is a pointer to get around some undesirable behavior with respect to the empty metav1.Time value (see https://github.com/kubernetes/kubernetes/issues/86811).
|
|
||||||
| *`secrets`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-24-apis-supervisor-config-v1alpha1-federationdomainsecrets[$$FederationDomainSecrets$$]__ | Secrets contains information about this OIDC Provider's secrets.
|
| *`secrets`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-24-apis-supervisor-config-v1alpha1-federationdomainsecrets[$$FederationDomainSecrets$$]__ | Secrets contains information about this OIDC Provider's secrets.
|
||||||
|===
|
|===
|
||||||
|
|
||||||
|
@ -8,14 +8,17 @@ import (
|
|||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
// +kubebuilder:validation:Enum=Success;Duplicate;Invalid;SameIssuerHostMustUseSameSecret
|
type FederationDomainPhase string
|
||||||
type FederationDomainStatusCondition string
|
|
||||||
|
|
||||||
const (
|
const (
|
||||||
SuccessFederationDomainStatusCondition = FederationDomainStatusCondition("Success")
|
// FederationDomainPhasePending is the default phase for newly-created FederationDomain resources.
|
||||||
DuplicateFederationDomainStatusCondition = FederationDomainStatusCondition("Duplicate")
|
FederationDomainPhasePending FederationDomainPhase = "Pending"
|
||||||
SameIssuerHostMustUseSameSecretFederationDomainStatusCondition = FederationDomainStatusCondition("SameIssuerHostMustUseSameSecret")
|
|
||||||
InvalidFederationDomainStatusCondition = FederationDomainStatusCondition("Invalid")
|
// FederationDomainPhaseReady is the phase for an FederationDomain resource in a healthy state.
|
||||||
|
FederationDomainPhaseReady FederationDomainPhase = "Ready"
|
||||||
|
|
||||||
|
// FederationDomainPhaseError is the phase for an FederationDomain in an unhealthy state.
|
||||||
|
FederationDomainPhaseError FederationDomainPhase = "Error"
|
||||||
)
|
)
|
||||||
|
|
||||||
// FederationDomainTLSSpec is a struct that describes the TLS configuration for an OIDC Provider.
|
// FederationDomainTLSSpec is a struct that describes the TLS configuration for an OIDC Provider.
|
||||||
@ -263,20 +266,17 @@ type FederationDomainSecrets struct {
|
|||||||
|
|
||||||
// FederationDomainStatus is a struct that describes the actual state of an OIDC Provider.
|
// FederationDomainStatus is a struct that describes the actual state of an OIDC Provider.
|
||||||
type FederationDomainStatus struct {
|
type FederationDomainStatus struct {
|
||||||
// Status holds an enum that describes the state of this OIDC Provider. Note that this Status can
|
// Phase summarizes the overall status of the FederationDomain.
|
||||||
// represent success or failure.
|
// +kubebuilder:default=Pending
|
||||||
// +optional
|
// +kubebuilder:validation:Enum=Pending;Ready;Error
|
||||||
Status FederationDomainStatusCondition `json:"status,omitempty"`
|
Phase FederationDomainPhase `json:"phase,omitempty"`
|
||||||
|
|
||||||
// Message provides human-readable details about the Status.
|
// Conditions represent the observations of an FederationDomain's current state.
|
||||||
// +optional
|
// +patchMergeKey=type
|
||||||
Message string `json:"message,omitempty"`
|
// +patchStrategy=merge
|
||||||
|
// +listType=map
|
||||||
// LastUpdateTime holds the time at which the Status was last updated. It is a pointer to get
|
// +listMapKey=type
|
||||||
// around some undesirable behavior with respect to the empty metav1.Time value (see
|
Conditions []Condition `json:"conditions,omitempty" patchStrategy:"merge" patchMergeKey:"type"`
|
||||||
// https://github.com/kubernetes/kubernetes/issues/86811).
|
|
||||||
// +optional
|
|
||||||
LastUpdateTime *metav1.Time `json:"lastUpdateTime,omitempty"`
|
|
||||||
|
|
||||||
// Secrets contains information about this OIDC Provider's secrets.
|
// Secrets contains information about this OIDC Provider's secrets.
|
||||||
// +optional
|
// +optional
|
||||||
@ -288,7 +288,7 @@ type FederationDomainStatus struct {
|
|||||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||||
// +kubebuilder:resource:categories=pinniped
|
// +kubebuilder:resource:categories=pinniped
|
||||||
// +kubebuilder:printcolumn:name="Issuer",type=string,JSONPath=`.spec.issuer`
|
// +kubebuilder:printcolumn:name="Issuer",type=string,JSONPath=`.spec.issuer`
|
||||||
// +kubebuilder:printcolumn:name="Status",type=string,JSONPath=`.status.status`
|
// +kubebuilder:printcolumn:name="Phase",type=string,JSONPath=`.status.phase`
|
||||||
// +kubebuilder:printcolumn:name="Age",type=date,JSONPath=`.metadata.creationTimestamp`
|
// +kubebuilder:printcolumn:name="Age",type=date,JSONPath=`.metadata.creationTimestamp`
|
||||||
// +kubebuilder:subresource:status
|
// +kubebuilder:subresource:status
|
||||||
type FederationDomain struct {
|
type FederationDomain struct {
|
||||||
|
@ -8,14 +8,14 @@ import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|||||||
type OIDCClientPhase string
|
type OIDCClientPhase string
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// PhasePending is the default phase for newly-created OIDCClient resources.
|
// OIDCClientPhasePending is the default phase for newly-created OIDCClient resources.
|
||||||
PhasePending OIDCClientPhase = "Pending"
|
OIDCClientPhasePending OIDCClientPhase = "Pending"
|
||||||
|
|
||||||
// PhaseReady is the phase for an OIDCClient resource in a healthy state.
|
// OIDCClientPhaseReady is the phase for an OIDCClient resource in a healthy state.
|
||||||
PhaseReady OIDCClientPhase = "Ready"
|
OIDCClientPhaseReady OIDCClientPhase = "Ready"
|
||||||
|
|
||||||
// PhaseError is the phase for an OIDCClient in an unhealthy state.
|
// OIDCClientPhaseError is the phase for an OIDCClient in an unhealthy state.
|
||||||
PhaseError OIDCClientPhase = "Error"
|
OIDCClientPhaseError OIDCClientPhase = "Error"
|
||||||
)
|
)
|
||||||
|
|
||||||
// +kubebuilder:validation:Pattern=`^https://.+|^http://(127\.0\.0\.1|\[::1\])(:\d+)?/`
|
// +kubebuilder:validation:Pattern=`^https://.+|^http://(127\.0\.0\.1|\[::1\])(:\d+)?/`
|
||||||
|
@ -143,9 +143,12 @@ func (in *FederationDomainSpec) DeepCopy() *FederationDomainSpec {
|
|||||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
func (in *FederationDomainStatus) DeepCopyInto(out *FederationDomainStatus) {
|
func (in *FederationDomainStatus) DeepCopyInto(out *FederationDomainStatus) {
|
||||||
*out = *in
|
*out = *in
|
||||||
if in.LastUpdateTime != nil {
|
if in.Conditions != nil {
|
||||||
in, out := &in.LastUpdateTime, &out.LastUpdateTime
|
in, out := &in.Conditions, &out.Conditions
|
||||||
*out = (*in).DeepCopy()
|
*out = make([]Condition, len(*in))
|
||||||
|
for i := range *in {
|
||||||
|
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||||
|
}
|
||||||
}
|
}
|
||||||
out.Secrets = in.Secrets
|
out.Secrets = in.Secrets
|
||||||
return
|
return
|
||||||
|
@ -21,8 +21,8 @@ spec:
|
|||||||
- jsonPath: .spec.issuer
|
- jsonPath: .spec.issuer
|
||||||
name: Issuer
|
name: Issuer
|
||||||
type: string
|
type: string
|
||||||
- jsonPath: .status.status
|
- jsonPath: .status.phase
|
||||||
name: Status
|
name: Phase
|
||||||
type: string
|
type: string
|
||||||
- jsonPath: .metadata.creationTimestamp
|
- jsonPath: .metadata.creationTimestamp
|
||||||
name: Age
|
name: Age
|
||||||
@ -348,14 +348,80 @@ spec:
|
|||||||
status:
|
status:
|
||||||
description: Status of the OIDC provider.
|
description: Status of the OIDC provider.
|
||||||
properties:
|
properties:
|
||||||
lastUpdateTime:
|
conditions:
|
||||||
description: LastUpdateTime holds the time at which the Status was
|
description: Conditions represent the observations of an FederationDomain's
|
||||||
last updated. It is a pointer to get around some undesirable behavior
|
current state.
|
||||||
with respect to the empty metav1.Time value (see https://github.com/kubernetes/kubernetes/issues/86811).
|
items:
|
||||||
|
description: Condition status of a resource (mirrored from the metav1.Condition
|
||||||
|
type added in Kubernetes 1.19). In a future API version we can
|
||||||
|
switch to using the upstream type. See https://github.com/kubernetes/apimachinery/blob/v0.19.0/pkg/apis/meta/v1/types.go#L1353-L1413.
|
||||||
|
properties:
|
||||||
|
lastTransitionTime:
|
||||||
|
description: lastTransitionTime is the last time the condition
|
||||||
|
transitioned from one status to another. This should be when
|
||||||
|
the underlying condition changed. If that is not known, then
|
||||||
|
using the time when the API field changed is acceptable.
|
||||||
format: date-time
|
format: date-time
|
||||||
type: string
|
type: string
|
||||||
message:
|
message:
|
||||||
description: Message provides human-readable details about the Status.
|
description: message is a human readable message indicating
|
||||||
|
details about the transition. This may be an empty string.
|
||||||
|
maxLength: 32768
|
||||||
|
type: string
|
||||||
|
observedGeneration:
|
||||||
|
description: observedGeneration represents the .metadata.generation
|
||||||
|
that the condition was set based upon. For instance, if .metadata.generation
|
||||||
|
is currently 12, but the .status.conditions[x].observedGeneration
|
||||||
|
is 9, the condition is out of date with respect to the current
|
||||||
|
state of the instance.
|
||||||
|
format: int64
|
||||||
|
minimum: 0
|
||||||
|
type: integer
|
||||||
|
reason:
|
||||||
|
description: reason contains a programmatic identifier indicating
|
||||||
|
the reason for the condition's last transition. Producers
|
||||||
|
of specific condition types may define expected values and
|
||||||
|
meanings for this field, and whether the values are considered
|
||||||
|
a guaranteed API. The value should be a CamelCase string.
|
||||||
|
This field may not be empty.
|
||||||
|
maxLength: 1024
|
||||||
|
minLength: 1
|
||||||
|
pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$
|
||||||
|
type: string
|
||||||
|
status:
|
||||||
|
description: status of the condition, one of True, False, Unknown.
|
||||||
|
enum:
|
||||||
|
- "True"
|
||||||
|
- "False"
|
||||||
|
- Unknown
|
||||||
|
type: string
|
||||||
|
type:
|
||||||
|
description: type of condition in CamelCase or in foo.example.com/CamelCase.
|
||||||
|
--- Many .condition.type values are consistent across resources
|
||||||
|
like Available, but because arbitrary conditions can be useful
|
||||||
|
(see .node.status.conditions), the ability to deconflict is
|
||||||
|
important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt)
|
||||||
|
maxLength: 316
|
||||||
|
pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$
|
||||||
|
type: string
|
||||||
|
required:
|
||||||
|
- lastTransitionTime
|
||||||
|
- message
|
||||||
|
- reason
|
||||||
|
- status
|
||||||
|
- type
|
||||||
|
type: object
|
||||||
|
type: array
|
||||||
|
x-kubernetes-list-map-keys:
|
||||||
|
- type
|
||||||
|
x-kubernetes-list-type: map
|
||||||
|
phase:
|
||||||
|
default: Pending
|
||||||
|
description: Phase summarizes the overall status of the FederationDomain.
|
||||||
|
enum:
|
||||||
|
- Pending
|
||||||
|
- Ready
|
||||||
|
- Error
|
||||||
type: string
|
type: string
|
||||||
secrets:
|
secrets:
|
||||||
description: Secrets contains information about this OIDC Provider's
|
description: Secrets contains information about this OIDC Provider's
|
||||||
@ -402,15 +468,6 @@ spec:
|
|||||||
type: string
|
type: string
|
||||||
type: object
|
type: object
|
||||||
type: object
|
type: object
|
||||||
status:
|
|
||||||
description: Status holds an enum that describes the state of this
|
|
||||||
OIDC Provider. Note that this Status can represent success or failure.
|
|
||||||
enum:
|
|
||||||
- Success
|
|
||||||
- Duplicate
|
|
||||||
- Invalid
|
|
||||||
- SameIssuerHostMustUseSameSecret
|
|
||||||
type: string
|
|
||||||
type: object
|
type: object
|
||||||
required:
|
required:
|
||||||
- spec
|
- spec
|
||||||
|
5
generated/1.25/README.adoc
generated
5
generated/1.25/README.adoc
generated
@ -726,9 +726,8 @@ FederationDomainStatus is a struct that describes the actual state of an OIDC Pr
|
|||||||
[cols="25a,75a", options="header"]
|
[cols="25a,75a", options="header"]
|
||||||
|===
|
|===
|
||||||
| Field | Description
|
| Field | Description
|
||||||
| *`status`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-25-apis-supervisor-config-v1alpha1-federationdomainstatuscondition[$$FederationDomainStatusCondition$$]__ | Status holds an enum that describes the state of this OIDC Provider. Note that this Status can represent success or failure.
|
| *`phase`* __FederationDomainPhase__ | Phase summarizes the overall status of the FederationDomain.
|
||||||
| *`message`* __string__ | Message provides human-readable details about the Status.
|
| *`conditions`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-25-apis-supervisor-config-v1alpha1-condition[$$Condition$$] array__ | Conditions represent the observations of an FederationDomain's current state.
|
||||||
| *`lastUpdateTime`* __link:https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.25/#time-v1-meta[$$Time$$]__ | LastUpdateTime holds the time at which the Status was last updated. It is a pointer to get around some undesirable behavior with respect to the empty metav1.Time value (see https://github.com/kubernetes/kubernetes/issues/86811).
|
|
||||||
| *`secrets`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-25-apis-supervisor-config-v1alpha1-federationdomainsecrets[$$FederationDomainSecrets$$]__ | Secrets contains information about this OIDC Provider's secrets.
|
| *`secrets`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-25-apis-supervisor-config-v1alpha1-federationdomainsecrets[$$FederationDomainSecrets$$]__ | Secrets contains information about this OIDC Provider's secrets.
|
||||||
|===
|
|===
|
||||||
|
|
||||||
|
@ -8,14 +8,17 @@ import (
|
|||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
// +kubebuilder:validation:Enum=Success;Duplicate;Invalid;SameIssuerHostMustUseSameSecret
|
type FederationDomainPhase string
|
||||||
type FederationDomainStatusCondition string
|
|
||||||
|
|
||||||
const (
|
const (
|
||||||
SuccessFederationDomainStatusCondition = FederationDomainStatusCondition("Success")
|
// FederationDomainPhasePending is the default phase for newly-created FederationDomain resources.
|
||||||
DuplicateFederationDomainStatusCondition = FederationDomainStatusCondition("Duplicate")
|
FederationDomainPhasePending FederationDomainPhase = "Pending"
|
||||||
SameIssuerHostMustUseSameSecretFederationDomainStatusCondition = FederationDomainStatusCondition("SameIssuerHostMustUseSameSecret")
|
|
||||||
InvalidFederationDomainStatusCondition = FederationDomainStatusCondition("Invalid")
|
// FederationDomainPhaseReady is the phase for an FederationDomain resource in a healthy state.
|
||||||
|
FederationDomainPhaseReady FederationDomainPhase = "Ready"
|
||||||
|
|
||||||
|
// FederationDomainPhaseError is the phase for an FederationDomain in an unhealthy state.
|
||||||
|
FederationDomainPhaseError FederationDomainPhase = "Error"
|
||||||
)
|
)
|
||||||
|
|
||||||
// FederationDomainTLSSpec is a struct that describes the TLS configuration for an OIDC Provider.
|
// FederationDomainTLSSpec is a struct that describes the TLS configuration for an OIDC Provider.
|
||||||
@ -263,20 +266,17 @@ type FederationDomainSecrets struct {
|
|||||||
|
|
||||||
// FederationDomainStatus is a struct that describes the actual state of an OIDC Provider.
|
// FederationDomainStatus is a struct that describes the actual state of an OIDC Provider.
|
||||||
type FederationDomainStatus struct {
|
type FederationDomainStatus struct {
|
||||||
// Status holds an enum that describes the state of this OIDC Provider. Note that this Status can
|
// Phase summarizes the overall status of the FederationDomain.
|
||||||
// represent success or failure.
|
// +kubebuilder:default=Pending
|
||||||
// +optional
|
// +kubebuilder:validation:Enum=Pending;Ready;Error
|
||||||
Status FederationDomainStatusCondition `json:"status,omitempty"`
|
Phase FederationDomainPhase `json:"phase,omitempty"`
|
||||||
|
|
||||||
// Message provides human-readable details about the Status.
|
// Conditions represent the observations of an FederationDomain's current state.
|
||||||
// +optional
|
// +patchMergeKey=type
|
||||||
Message string `json:"message,omitempty"`
|
// +patchStrategy=merge
|
||||||
|
// +listType=map
|
||||||
// LastUpdateTime holds the time at which the Status was last updated. It is a pointer to get
|
// +listMapKey=type
|
||||||
// around some undesirable behavior with respect to the empty metav1.Time value (see
|
Conditions []Condition `json:"conditions,omitempty" patchStrategy:"merge" patchMergeKey:"type"`
|
||||||
// https://github.com/kubernetes/kubernetes/issues/86811).
|
|
||||||
// +optional
|
|
||||||
LastUpdateTime *metav1.Time `json:"lastUpdateTime,omitempty"`
|
|
||||||
|
|
||||||
// Secrets contains information about this OIDC Provider's secrets.
|
// Secrets contains information about this OIDC Provider's secrets.
|
||||||
// +optional
|
// +optional
|
||||||
@ -288,7 +288,7 @@ type FederationDomainStatus struct {
|
|||||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||||
// +kubebuilder:resource:categories=pinniped
|
// +kubebuilder:resource:categories=pinniped
|
||||||
// +kubebuilder:printcolumn:name="Issuer",type=string,JSONPath=`.spec.issuer`
|
// +kubebuilder:printcolumn:name="Issuer",type=string,JSONPath=`.spec.issuer`
|
||||||
// +kubebuilder:printcolumn:name="Status",type=string,JSONPath=`.status.status`
|
// +kubebuilder:printcolumn:name="Phase",type=string,JSONPath=`.status.phase`
|
||||||
// +kubebuilder:printcolumn:name="Age",type=date,JSONPath=`.metadata.creationTimestamp`
|
// +kubebuilder:printcolumn:name="Age",type=date,JSONPath=`.metadata.creationTimestamp`
|
||||||
// +kubebuilder:subresource:status
|
// +kubebuilder:subresource:status
|
||||||
type FederationDomain struct {
|
type FederationDomain struct {
|
||||||
|
@ -8,14 +8,14 @@ import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|||||||
type OIDCClientPhase string
|
type OIDCClientPhase string
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// PhasePending is the default phase for newly-created OIDCClient resources.
|
// OIDCClientPhasePending is the default phase for newly-created OIDCClient resources.
|
||||||
PhasePending OIDCClientPhase = "Pending"
|
OIDCClientPhasePending OIDCClientPhase = "Pending"
|
||||||
|
|
||||||
// PhaseReady is the phase for an OIDCClient resource in a healthy state.
|
// OIDCClientPhaseReady is the phase for an OIDCClient resource in a healthy state.
|
||||||
PhaseReady OIDCClientPhase = "Ready"
|
OIDCClientPhaseReady OIDCClientPhase = "Ready"
|
||||||
|
|
||||||
// PhaseError is the phase for an OIDCClient in an unhealthy state.
|
// OIDCClientPhaseError is the phase for an OIDCClient in an unhealthy state.
|
||||||
PhaseError OIDCClientPhase = "Error"
|
OIDCClientPhaseError OIDCClientPhase = "Error"
|
||||||
)
|
)
|
||||||
|
|
||||||
// +kubebuilder:validation:Pattern=`^https://.+|^http://(127\.0\.0\.1|\[::1\])(:\d+)?/`
|
// +kubebuilder:validation:Pattern=`^https://.+|^http://(127\.0\.0\.1|\[::1\])(:\d+)?/`
|
||||||
|
@ -143,9 +143,12 @@ func (in *FederationDomainSpec) DeepCopy() *FederationDomainSpec {
|
|||||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
func (in *FederationDomainStatus) DeepCopyInto(out *FederationDomainStatus) {
|
func (in *FederationDomainStatus) DeepCopyInto(out *FederationDomainStatus) {
|
||||||
*out = *in
|
*out = *in
|
||||||
if in.LastUpdateTime != nil {
|
if in.Conditions != nil {
|
||||||
in, out := &in.LastUpdateTime, &out.LastUpdateTime
|
in, out := &in.Conditions, &out.Conditions
|
||||||
*out = (*in).DeepCopy()
|
*out = make([]Condition, len(*in))
|
||||||
|
for i := range *in {
|
||||||
|
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||||
|
}
|
||||||
}
|
}
|
||||||
out.Secrets = in.Secrets
|
out.Secrets = in.Secrets
|
||||||
return
|
return
|
||||||
|
@ -21,8 +21,8 @@ spec:
|
|||||||
- jsonPath: .spec.issuer
|
- jsonPath: .spec.issuer
|
||||||
name: Issuer
|
name: Issuer
|
||||||
type: string
|
type: string
|
||||||
- jsonPath: .status.status
|
- jsonPath: .status.phase
|
||||||
name: Status
|
name: Phase
|
||||||
type: string
|
type: string
|
||||||
- jsonPath: .metadata.creationTimestamp
|
- jsonPath: .metadata.creationTimestamp
|
||||||
name: Age
|
name: Age
|
||||||
@ -348,14 +348,80 @@ spec:
|
|||||||
status:
|
status:
|
||||||
description: Status of the OIDC provider.
|
description: Status of the OIDC provider.
|
||||||
properties:
|
properties:
|
||||||
lastUpdateTime:
|
conditions:
|
||||||
description: LastUpdateTime holds the time at which the Status was
|
description: Conditions represent the observations of an FederationDomain's
|
||||||
last updated. It is a pointer to get around some undesirable behavior
|
current state.
|
||||||
with respect to the empty metav1.Time value (see https://github.com/kubernetes/kubernetes/issues/86811).
|
items:
|
||||||
|
description: Condition status of a resource (mirrored from the metav1.Condition
|
||||||
|
type added in Kubernetes 1.19). In a future API version we can
|
||||||
|
switch to using the upstream type. See https://github.com/kubernetes/apimachinery/blob/v0.19.0/pkg/apis/meta/v1/types.go#L1353-L1413.
|
||||||
|
properties:
|
||||||
|
lastTransitionTime:
|
||||||
|
description: lastTransitionTime is the last time the condition
|
||||||
|
transitioned from one status to another. This should be when
|
||||||
|
the underlying condition changed. If that is not known, then
|
||||||
|
using the time when the API field changed is acceptable.
|
||||||
format: date-time
|
format: date-time
|
||||||
type: string
|
type: string
|
||||||
message:
|
message:
|
||||||
description: Message provides human-readable details about the Status.
|
description: message is a human readable message indicating
|
||||||
|
details about the transition. This may be an empty string.
|
||||||
|
maxLength: 32768
|
||||||
|
type: string
|
||||||
|
observedGeneration:
|
||||||
|
description: observedGeneration represents the .metadata.generation
|
||||||
|
that the condition was set based upon. For instance, if .metadata.generation
|
||||||
|
is currently 12, but the .status.conditions[x].observedGeneration
|
||||||
|
is 9, the condition is out of date with respect to the current
|
||||||
|
state of the instance.
|
||||||
|
format: int64
|
||||||
|
minimum: 0
|
||||||
|
type: integer
|
||||||
|
reason:
|
||||||
|
description: reason contains a programmatic identifier indicating
|
||||||
|
the reason for the condition's last transition. Producers
|
||||||
|
of specific condition types may define expected values and
|
||||||
|
meanings for this field, and whether the values are considered
|
||||||
|
a guaranteed API. The value should be a CamelCase string.
|
||||||
|
This field may not be empty.
|
||||||
|
maxLength: 1024
|
||||||
|
minLength: 1
|
||||||
|
pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$
|
||||||
|
type: string
|
||||||
|
status:
|
||||||
|
description: status of the condition, one of True, False, Unknown.
|
||||||
|
enum:
|
||||||
|
- "True"
|
||||||
|
- "False"
|
||||||
|
- Unknown
|
||||||
|
type: string
|
||||||
|
type:
|
||||||
|
description: type of condition in CamelCase or in foo.example.com/CamelCase.
|
||||||
|
--- Many .condition.type values are consistent across resources
|
||||||
|
like Available, but because arbitrary conditions can be useful
|
||||||
|
(see .node.status.conditions), the ability to deconflict is
|
||||||
|
important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt)
|
||||||
|
maxLength: 316
|
||||||
|
pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$
|
||||||
|
type: string
|
||||||
|
required:
|
||||||
|
- lastTransitionTime
|
||||||
|
- message
|
||||||
|
- reason
|
||||||
|
- status
|
||||||
|
- type
|
||||||
|
type: object
|
||||||
|
type: array
|
||||||
|
x-kubernetes-list-map-keys:
|
||||||
|
- type
|
||||||
|
x-kubernetes-list-type: map
|
||||||
|
phase:
|
||||||
|
default: Pending
|
||||||
|
description: Phase summarizes the overall status of the FederationDomain.
|
||||||
|
enum:
|
||||||
|
- Pending
|
||||||
|
- Ready
|
||||||
|
- Error
|
||||||
type: string
|
type: string
|
||||||
secrets:
|
secrets:
|
||||||
description: Secrets contains information about this OIDC Provider's
|
description: Secrets contains information about this OIDC Provider's
|
||||||
@ -402,15 +468,6 @@ spec:
|
|||||||
type: string
|
type: string
|
||||||
type: object
|
type: object
|
||||||
type: object
|
type: object
|
||||||
status:
|
|
||||||
description: Status holds an enum that describes the state of this
|
|
||||||
OIDC Provider. Note that this Status can represent success or failure.
|
|
||||||
enum:
|
|
||||||
- Success
|
|
||||||
- Duplicate
|
|
||||||
- Invalid
|
|
||||||
- SameIssuerHostMustUseSameSecret
|
|
||||||
type: string
|
|
||||||
type: object
|
type: object
|
||||||
required:
|
required:
|
||||||
- spec
|
- spec
|
||||||
|
5
generated/1.26/README.adoc
generated
5
generated/1.26/README.adoc
generated
@ -726,9 +726,8 @@ FederationDomainStatus is a struct that describes the actual state of an OIDC Pr
|
|||||||
[cols="25a,75a", options="header"]
|
[cols="25a,75a", options="header"]
|
||||||
|===
|
|===
|
||||||
| Field | Description
|
| Field | Description
|
||||||
| *`status`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-26-apis-supervisor-config-v1alpha1-federationdomainstatuscondition[$$FederationDomainStatusCondition$$]__ | Status holds an enum that describes the state of this OIDC Provider. Note that this Status can represent success or failure.
|
| *`phase`* __FederationDomainPhase__ | Phase summarizes the overall status of the FederationDomain.
|
||||||
| *`message`* __string__ | Message provides human-readable details about the Status.
|
| *`conditions`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-26-apis-supervisor-config-v1alpha1-condition[$$Condition$$] array__ | Conditions represent the observations of an FederationDomain's current state.
|
||||||
| *`lastUpdateTime`* __link:https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.26/#time-v1-meta[$$Time$$]__ | LastUpdateTime holds the time at which the Status was last updated. It is a pointer to get around some undesirable behavior with respect to the empty metav1.Time value (see https://github.com/kubernetes/kubernetes/issues/86811).
|
|
||||||
| *`secrets`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-26-apis-supervisor-config-v1alpha1-federationdomainsecrets[$$FederationDomainSecrets$$]__ | Secrets contains information about this OIDC Provider's secrets.
|
| *`secrets`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-26-apis-supervisor-config-v1alpha1-federationdomainsecrets[$$FederationDomainSecrets$$]__ | Secrets contains information about this OIDC Provider's secrets.
|
||||||
|===
|
|===
|
||||||
|
|
||||||
|
@ -8,14 +8,17 @@ import (
|
|||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
// +kubebuilder:validation:Enum=Success;Duplicate;Invalid;SameIssuerHostMustUseSameSecret
|
type FederationDomainPhase string
|
||||||
type FederationDomainStatusCondition string
|
|
||||||
|
|
||||||
const (
|
const (
|
||||||
SuccessFederationDomainStatusCondition = FederationDomainStatusCondition("Success")
|
// FederationDomainPhasePending is the default phase for newly-created FederationDomain resources.
|
||||||
DuplicateFederationDomainStatusCondition = FederationDomainStatusCondition("Duplicate")
|
FederationDomainPhasePending FederationDomainPhase = "Pending"
|
||||||
SameIssuerHostMustUseSameSecretFederationDomainStatusCondition = FederationDomainStatusCondition("SameIssuerHostMustUseSameSecret")
|
|
||||||
InvalidFederationDomainStatusCondition = FederationDomainStatusCondition("Invalid")
|
// FederationDomainPhaseReady is the phase for an FederationDomain resource in a healthy state.
|
||||||
|
FederationDomainPhaseReady FederationDomainPhase = "Ready"
|
||||||
|
|
||||||
|
// FederationDomainPhaseError is the phase for an FederationDomain in an unhealthy state.
|
||||||
|
FederationDomainPhaseError FederationDomainPhase = "Error"
|
||||||
)
|
)
|
||||||
|
|
||||||
// FederationDomainTLSSpec is a struct that describes the TLS configuration for an OIDC Provider.
|
// FederationDomainTLSSpec is a struct that describes the TLS configuration for an OIDC Provider.
|
||||||
@ -263,20 +266,17 @@ type FederationDomainSecrets struct {
|
|||||||
|
|
||||||
// FederationDomainStatus is a struct that describes the actual state of an OIDC Provider.
|
// FederationDomainStatus is a struct that describes the actual state of an OIDC Provider.
|
||||||
type FederationDomainStatus struct {
|
type FederationDomainStatus struct {
|
||||||
// Status holds an enum that describes the state of this OIDC Provider. Note that this Status can
|
// Phase summarizes the overall status of the FederationDomain.
|
||||||
// represent success or failure.
|
// +kubebuilder:default=Pending
|
||||||
// +optional
|
// +kubebuilder:validation:Enum=Pending;Ready;Error
|
||||||
Status FederationDomainStatusCondition `json:"status,omitempty"`
|
Phase FederationDomainPhase `json:"phase,omitempty"`
|
||||||
|
|
||||||
// Message provides human-readable details about the Status.
|
// Conditions represent the observations of an FederationDomain's current state.
|
||||||
// +optional
|
// +patchMergeKey=type
|
||||||
Message string `json:"message,omitempty"`
|
// +patchStrategy=merge
|
||||||
|
// +listType=map
|
||||||
// LastUpdateTime holds the time at which the Status was last updated. It is a pointer to get
|
// +listMapKey=type
|
||||||
// around some undesirable behavior with respect to the empty metav1.Time value (see
|
Conditions []Condition `json:"conditions,omitempty" patchStrategy:"merge" patchMergeKey:"type"`
|
||||||
// https://github.com/kubernetes/kubernetes/issues/86811).
|
|
||||||
// +optional
|
|
||||||
LastUpdateTime *metav1.Time `json:"lastUpdateTime,omitempty"`
|
|
||||||
|
|
||||||
// Secrets contains information about this OIDC Provider's secrets.
|
// Secrets contains information about this OIDC Provider's secrets.
|
||||||
// +optional
|
// +optional
|
||||||
@ -288,7 +288,7 @@ type FederationDomainStatus struct {
|
|||||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||||
// +kubebuilder:resource:categories=pinniped
|
// +kubebuilder:resource:categories=pinniped
|
||||||
// +kubebuilder:printcolumn:name="Issuer",type=string,JSONPath=`.spec.issuer`
|
// +kubebuilder:printcolumn:name="Issuer",type=string,JSONPath=`.spec.issuer`
|
||||||
// +kubebuilder:printcolumn:name="Status",type=string,JSONPath=`.status.status`
|
// +kubebuilder:printcolumn:name="Phase",type=string,JSONPath=`.status.phase`
|
||||||
// +kubebuilder:printcolumn:name="Age",type=date,JSONPath=`.metadata.creationTimestamp`
|
// +kubebuilder:printcolumn:name="Age",type=date,JSONPath=`.metadata.creationTimestamp`
|
||||||
// +kubebuilder:subresource:status
|
// +kubebuilder:subresource:status
|
||||||
type FederationDomain struct {
|
type FederationDomain struct {
|
||||||
|
@ -8,14 +8,14 @@ import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|||||||
type OIDCClientPhase string
|
type OIDCClientPhase string
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// PhasePending is the default phase for newly-created OIDCClient resources.
|
// OIDCClientPhasePending is the default phase for newly-created OIDCClient resources.
|
||||||
PhasePending OIDCClientPhase = "Pending"
|
OIDCClientPhasePending OIDCClientPhase = "Pending"
|
||||||
|
|
||||||
// PhaseReady is the phase for an OIDCClient resource in a healthy state.
|
// OIDCClientPhaseReady is the phase for an OIDCClient resource in a healthy state.
|
||||||
PhaseReady OIDCClientPhase = "Ready"
|
OIDCClientPhaseReady OIDCClientPhase = "Ready"
|
||||||
|
|
||||||
// PhaseError is the phase for an OIDCClient in an unhealthy state.
|
// OIDCClientPhaseError is the phase for an OIDCClient in an unhealthy state.
|
||||||
PhaseError OIDCClientPhase = "Error"
|
OIDCClientPhaseError OIDCClientPhase = "Error"
|
||||||
)
|
)
|
||||||
|
|
||||||
// +kubebuilder:validation:Pattern=`^https://.+|^http://(127\.0\.0\.1|\[::1\])(:\d+)?/`
|
// +kubebuilder:validation:Pattern=`^https://.+|^http://(127\.0\.0\.1|\[::1\])(:\d+)?/`
|
||||||
|
@ -143,9 +143,12 @@ func (in *FederationDomainSpec) DeepCopy() *FederationDomainSpec {
|
|||||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
func (in *FederationDomainStatus) DeepCopyInto(out *FederationDomainStatus) {
|
func (in *FederationDomainStatus) DeepCopyInto(out *FederationDomainStatus) {
|
||||||
*out = *in
|
*out = *in
|
||||||
if in.LastUpdateTime != nil {
|
if in.Conditions != nil {
|
||||||
in, out := &in.LastUpdateTime, &out.LastUpdateTime
|
in, out := &in.Conditions, &out.Conditions
|
||||||
*out = (*in).DeepCopy()
|
*out = make([]Condition, len(*in))
|
||||||
|
for i := range *in {
|
||||||
|
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||||
|
}
|
||||||
}
|
}
|
||||||
out.Secrets = in.Secrets
|
out.Secrets = in.Secrets
|
||||||
return
|
return
|
||||||
|
@ -21,8 +21,8 @@ spec:
|
|||||||
- jsonPath: .spec.issuer
|
- jsonPath: .spec.issuer
|
||||||
name: Issuer
|
name: Issuer
|
||||||
type: string
|
type: string
|
||||||
- jsonPath: .status.status
|
- jsonPath: .status.phase
|
||||||
name: Status
|
name: Phase
|
||||||
type: string
|
type: string
|
||||||
- jsonPath: .metadata.creationTimestamp
|
- jsonPath: .metadata.creationTimestamp
|
||||||
name: Age
|
name: Age
|
||||||
@ -348,14 +348,80 @@ spec:
|
|||||||
status:
|
status:
|
||||||
description: Status of the OIDC provider.
|
description: Status of the OIDC provider.
|
||||||
properties:
|
properties:
|
||||||
lastUpdateTime:
|
conditions:
|
||||||
description: LastUpdateTime holds the time at which the Status was
|
description: Conditions represent the observations of an FederationDomain's
|
||||||
last updated. It is a pointer to get around some undesirable behavior
|
current state.
|
||||||
with respect to the empty metav1.Time value (see https://github.com/kubernetes/kubernetes/issues/86811).
|
items:
|
||||||
|
description: Condition status of a resource (mirrored from the metav1.Condition
|
||||||
|
type added in Kubernetes 1.19). In a future API version we can
|
||||||
|
switch to using the upstream type. See https://github.com/kubernetes/apimachinery/blob/v0.19.0/pkg/apis/meta/v1/types.go#L1353-L1413.
|
||||||
|
properties:
|
||||||
|
lastTransitionTime:
|
||||||
|
description: lastTransitionTime is the last time the condition
|
||||||
|
transitioned from one status to another. This should be when
|
||||||
|
the underlying condition changed. If that is not known, then
|
||||||
|
using the time when the API field changed is acceptable.
|
||||||
format: date-time
|
format: date-time
|
||||||
type: string
|
type: string
|
||||||
message:
|
message:
|
||||||
description: Message provides human-readable details about the Status.
|
description: message is a human readable message indicating
|
||||||
|
details about the transition. This may be an empty string.
|
||||||
|
maxLength: 32768
|
||||||
|
type: string
|
||||||
|
observedGeneration:
|
||||||
|
description: observedGeneration represents the .metadata.generation
|
||||||
|
that the condition was set based upon. For instance, if .metadata.generation
|
||||||
|
is currently 12, but the .status.conditions[x].observedGeneration
|
||||||
|
is 9, the condition is out of date with respect to the current
|
||||||
|
state of the instance.
|
||||||
|
format: int64
|
||||||
|
minimum: 0
|
||||||
|
type: integer
|
||||||
|
reason:
|
||||||
|
description: reason contains a programmatic identifier indicating
|
||||||
|
the reason for the condition's last transition. Producers
|
||||||
|
of specific condition types may define expected values and
|
||||||
|
meanings for this field, and whether the values are considered
|
||||||
|
a guaranteed API. The value should be a CamelCase string.
|
||||||
|
This field may not be empty.
|
||||||
|
maxLength: 1024
|
||||||
|
minLength: 1
|
||||||
|
pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$
|
||||||
|
type: string
|
||||||
|
status:
|
||||||
|
description: status of the condition, one of True, False, Unknown.
|
||||||
|
enum:
|
||||||
|
- "True"
|
||||||
|
- "False"
|
||||||
|
- Unknown
|
||||||
|
type: string
|
||||||
|
type:
|
||||||
|
description: type of condition in CamelCase or in foo.example.com/CamelCase.
|
||||||
|
--- Many .condition.type values are consistent across resources
|
||||||
|
like Available, but because arbitrary conditions can be useful
|
||||||
|
(see .node.status.conditions), the ability to deconflict is
|
||||||
|
important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt)
|
||||||
|
maxLength: 316
|
||||||
|
pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$
|
||||||
|
type: string
|
||||||
|
required:
|
||||||
|
- lastTransitionTime
|
||||||
|
- message
|
||||||
|
- reason
|
||||||
|
- status
|
||||||
|
- type
|
||||||
|
type: object
|
||||||
|
type: array
|
||||||
|
x-kubernetes-list-map-keys:
|
||||||
|
- type
|
||||||
|
x-kubernetes-list-type: map
|
||||||
|
phase:
|
||||||
|
default: Pending
|
||||||
|
description: Phase summarizes the overall status of the FederationDomain.
|
||||||
|
enum:
|
||||||
|
- Pending
|
||||||
|
- Ready
|
||||||
|
- Error
|
||||||
type: string
|
type: string
|
||||||
secrets:
|
secrets:
|
||||||
description: Secrets contains information about this OIDC Provider's
|
description: Secrets contains information about this OIDC Provider's
|
||||||
@ -402,15 +468,6 @@ spec:
|
|||||||
type: string
|
type: string
|
||||||
type: object
|
type: object
|
||||||
type: object
|
type: object
|
||||||
status:
|
|
||||||
description: Status holds an enum that describes the state of this
|
|
||||||
OIDC Provider. Note that this Status can represent success or failure.
|
|
||||||
enum:
|
|
||||||
- Success
|
|
||||||
- Duplicate
|
|
||||||
- Invalid
|
|
||||||
- SameIssuerHostMustUseSameSecret
|
|
||||||
type: string
|
|
||||||
type: object
|
type: object
|
||||||
required:
|
required:
|
||||||
- spec
|
- spec
|
||||||
|
5
generated/1.27/README.adoc
generated
5
generated/1.27/README.adoc
generated
@ -726,9 +726,8 @@ FederationDomainStatus is a struct that describes the actual state of an OIDC Pr
|
|||||||
[cols="25a,75a", options="header"]
|
[cols="25a,75a", options="header"]
|
||||||
|===
|
|===
|
||||||
| Field | Description
|
| Field | Description
|
||||||
| *`status`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-27-apis-supervisor-config-v1alpha1-federationdomainstatuscondition[$$FederationDomainStatusCondition$$]__ | Status holds an enum that describes the state of this OIDC Provider. Note that this Status can represent success or failure.
|
| *`phase`* __FederationDomainPhase__ | Phase summarizes the overall status of the FederationDomain.
|
||||||
| *`message`* __string__ | Message provides human-readable details about the Status.
|
| *`conditions`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-27-apis-supervisor-config-v1alpha1-condition[$$Condition$$] array__ | Conditions represent the observations of an FederationDomain's current state.
|
||||||
| *`lastUpdateTime`* __link:https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.27/#time-v1-meta[$$Time$$]__ | LastUpdateTime holds the time at which the Status was last updated. It is a pointer to get around some undesirable behavior with respect to the empty metav1.Time value (see https://github.com/kubernetes/kubernetes/issues/86811).
|
|
||||||
| *`secrets`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-27-apis-supervisor-config-v1alpha1-federationdomainsecrets[$$FederationDomainSecrets$$]__ | Secrets contains information about this OIDC Provider's secrets.
|
| *`secrets`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-27-apis-supervisor-config-v1alpha1-federationdomainsecrets[$$FederationDomainSecrets$$]__ | Secrets contains information about this OIDC Provider's secrets.
|
||||||
|===
|
|===
|
||||||
|
|
||||||
|
@ -8,14 +8,17 @@ import (
|
|||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
// +kubebuilder:validation:Enum=Success;Duplicate;Invalid;SameIssuerHostMustUseSameSecret
|
type FederationDomainPhase string
|
||||||
type FederationDomainStatusCondition string
|
|
||||||
|
|
||||||
const (
|
const (
|
||||||
SuccessFederationDomainStatusCondition = FederationDomainStatusCondition("Success")
|
// FederationDomainPhasePending is the default phase for newly-created FederationDomain resources.
|
||||||
DuplicateFederationDomainStatusCondition = FederationDomainStatusCondition("Duplicate")
|
FederationDomainPhasePending FederationDomainPhase = "Pending"
|
||||||
SameIssuerHostMustUseSameSecretFederationDomainStatusCondition = FederationDomainStatusCondition("SameIssuerHostMustUseSameSecret")
|
|
||||||
InvalidFederationDomainStatusCondition = FederationDomainStatusCondition("Invalid")
|
// FederationDomainPhaseReady is the phase for an FederationDomain resource in a healthy state.
|
||||||
|
FederationDomainPhaseReady FederationDomainPhase = "Ready"
|
||||||
|
|
||||||
|
// FederationDomainPhaseError is the phase for an FederationDomain in an unhealthy state.
|
||||||
|
FederationDomainPhaseError FederationDomainPhase = "Error"
|
||||||
)
|
)
|
||||||
|
|
||||||
// FederationDomainTLSSpec is a struct that describes the TLS configuration for an OIDC Provider.
|
// FederationDomainTLSSpec is a struct that describes the TLS configuration for an OIDC Provider.
|
||||||
@ -263,20 +266,17 @@ type FederationDomainSecrets struct {
|
|||||||
|
|
||||||
// FederationDomainStatus is a struct that describes the actual state of an OIDC Provider.
|
// FederationDomainStatus is a struct that describes the actual state of an OIDC Provider.
|
||||||
type FederationDomainStatus struct {
|
type FederationDomainStatus struct {
|
||||||
// Status holds an enum that describes the state of this OIDC Provider. Note that this Status can
|
// Phase summarizes the overall status of the FederationDomain.
|
||||||
// represent success or failure.
|
// +kubebuilder:default=Pending
|
||||||
// +optional
|
// +kubebuilder:validation:Enum=Pending;Ready;Error
|
||||||
Status FederationDomainStatusCondition `json:"status,omitempty"`
|
Phase FederationDomainPhase `json:"phase,omitempty"`
|
||||||
|
|
||||||
// Message provides human-readable details about the Status.
|
// Conditions represent the observations of an FederationDomain's current state.
|
||||||
// +optional
|
// +patchMergeKey=type
|
||||||
Message string `json:"message,omitempty"`
|
// +patchStrategy=merge
|
||||||
|
// +listType=map
|
||||||
// LastUpdateTime holds the time at which the Status was last updated. It is a pointer to get
|
// +listMapKey=type
|
||||||
// around some undesirable behavior with respect to the empty metav1.Time value (see
|
Conditions []Condition `json:"conditions,omitempty" patchStrategy:"merge" patchMergeKey:"type"`
|
||||||
// https://github.com/kubernetes/kubernetes/issues/86811).
|
|
||||||
// +optional
|
|
||||||
LastUpdateTime *metav1.Time `json:"lastUpdateTime,omitempty"`
|
|
||||||
|
|
||||||
// Secrets contains information about this OIDC Provider's secrets.
|
// Secrets contains information about this OIDC Provider's secrets.
|
||||||
// +optional
|
// +optional
|
||||||
@ -288,7 +288,7 @@ type FederationDomainStatus struct {
|
|||||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||||
// +kubebuilder:resource:categories=pinniped
|
// +kubebuilder:resource:categories=pinniped
|
||||||
// +kubebuilder:printcolumn:name="Issuer",type=string,JSONPath=`.spec.issuer`
|
// +kubebuilder:printcolumn:name="Issuer",type=string,JSONPath=`.spec.issuer`
|
||||||
// +kubebuilder:printcolumn:name="Status",type=string,JSONPath=`.status.status`
|
// +kubebuilder:printcolumn:name="Phase",type=string,JSONPath=`.status.phase`
|
||||||
// +kubebuilder:printcolumn:name="Age",type=date,JSONPath=`.metadata.creationTimestamp`
|
// +kubebuilder:printcolumn:name="Age",type=date,JSONPath=`.metadata.creationTimestamp`
|
||||||
// +kubebuilder:subresource:status
|
// +kubebuilder:subresource:status
|
||||||
type FederationDomain struct {
|
type FederationDomain struct {
|
||||||
|
@ -8,14 +8,14 @@ import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|||||||
type OIDCClientPhase string
|
type OIDCClientPhase string
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// PhasePending is the default phase for newly-created OIDCClient resources.
|
// OIDCClientPhasePending is the default phase for newly-created OIDCClient resources.
|
||||||
PhasePending OIDCClientPhase = "Pending"
|
OIDCClientPhasePending OIDCClientPhase = "Pending"
|
||||||
|
|
||||||
// PhaseReady is the phase for an OIDCClient resource in a healthy state.
|
// OIDCClientPhaseReady is the phase for an OIDCClient resource in a healthy state.
|
||||||
PhaseReady OIDCClientPhase = "Ready"
|
OIDCClientPhaseReady OIDCClientPhase = "Ready"
|
||||||
|
|
||||||
// PhaseError is the phase for an OIDCClient in an unhealthy state.
|
// OIDCClientPhaseError is the phase for an OIDCClient in an unhealthy state.
|
||||||
PhaseError OIDCClientPhase = "Error"
|
OIDCClientPhaseError OIDCClientPhase = "Error"
|
||||||
)
|
)
|
||||||
|
|
||||||
// +kubebuilder:validation:Pattern=`^https://.+|^http://(127\.0\.0\.1|\[::1\])(:\d+)?/`
|
// +kubebuilder:validation:Pattern=`^https://.+|^http://(127\.0\.0\.1|\[::1\])(:\d+)?/`
|
||||||
|
@ -143,9 +143,12 @@ func (in *FederationDomainSpec) DeepCopy() *FederationDomainSpec {
|
|||||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
func (in *FederationDomainStatus) DeepCopyInto(out *FederationDomainStatus) {
|
func (in *FederationDomainStatus) DeepCopyInto(out *FederationDomainStatus) {
|
||||||
*out = *in
|
*out = *in
|
||||||
if in.LastUpdateTime != nil {
|
if in.Conditions != nil {
|
||||||
in, out := &in.LastUpdateTime, &out.LastUpdateTime
|
in, out := &in.Conditions, &out.Conditions
|
||||||
*out = (*in).DeepCopy()
|
*out = make([]Condition, len(*in))
|
||||||
|
for i := range *in {
|
||||||
|
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||||
|
}
|
||||||
}
|
}
|
||||||
out.Secrets = in.Secrets
|
out.Secrets = in.Secrets
|
||||||
return
|
return
|
||||||
|
@ -21,8 +21,8 @@ spec:
|
|||||||
- jsonPath: .spec.issuer
|
- jsonPath: .spec.issuer
|
||||||
name: Issuer
|
name: Issuer
|
||||||
type: string
|
type: string
|
||||||
- jsonPath: .status.status
|
- jsonPath: .status.phase
|
||||||
name: Status
|
name: Phase
|
||||||
type: string
|
type: string
|
||||||
- jsonPath: .metadata.creationTimestamp
|
- jsonPath: .metadata.creationTimestamp
|
||||||
name: Age
|
name: Age
|
||||||
@ -348,14 +348,80 @@ spec:
|
|||||||
status:
|
status:
|
||||||
description: Status of the OIDC provider.
|
description: Status of the OIDC provider.
|
||||||
properties:
|
properties:
|
||||||
lastUpdateTime:
|
conditions:
|
||||||
description: LastUpdateTime holds the time at which the Status was
|
description: Conditions represent the observations of an FederationDomain's
|
||||||
last updated. It is a pointer to get around some undesirable behavior
|
current state.
|
||||||
with respect to the empty metav1.Time value (see https://github.com/kubernetes/kubernetes/issues/86811).
|
items:
|
||||||
|
description: Condition status of a resource (mirrored from the metav1.Condition
|
||||||
|
type added in Kubernetes 1.19). In a future API version we can
|
||||||
|
switch to using the upstream type. See https://github.com/kubernetes/apimachinery/blob/v0.19.0/pkg/apis/meta/v1/types.go#L1353-L1413.
|
||||||
|
properties:
|
||||||
|
lastTransitionTime:
|
||||||
|
description: lastTransitionTime is the last time the condition
|
||||||
|
transitioned from one status to another. This should be when
|
||||||
|
the underlying condition changed. If that is not known, then
|
||||||
|
using the time when the API field changed is acceptable.
|
||||||
format: date-time
|
format: date-time
|
||||||
type: string
|
type: string
|
||||||
message:
|
message:
|
||||||
description: Message provides human-readable details about the Status.
|
description: message is a human readable message indicating
|
||||||
|
details about the transition. This may be an empty string.
|
||||||
|
maxLength: 32768
|
||||||
|
type: string
|
||||||
|
observedGeneration:
|
||||||
|
description: observedGeneration represents the .metadata.generation
|
||||||
|
that the condition was set based upon. For instance, if .metadata.generation
|
||||||
|
is currently 12, but the .status.conditions[x].observedGeneration
|
||||||
|
is 9, the condition is out of date with respect to the current
|
||||||
|
state of the instance.
|
||||||
|
format: int64
|
||||||
|
minimum: 0
|
||||||
|
type: integer
|
||||||
|
reason:
|
||||||
|
description: reason contains a programmatic identifier indicating
|
||||||
|
the reason for the condition's last transition. Producers
|
||||||
|
of specific condition types may define expected values and
|
||||||
|
meanings for this field, and whether the values are considered
|
||||||
|
a guaranteed API. The value should be a CamelCase string.
|
||||||
|
This field may not be empty.
|
||||||
|
maxLength: 1024
|
||||||
|
minLength: 1
|
||||||
|
pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$
|
||||||
|
type: string
|
||||||
|
status:
|
||||||
|
description: status of the condition, one of True, False, Unknown.
|
||||||
|
enum:
|
||||||
|
- "True"
|
||||||
|
- "False"
|
||||||
|
- Unknown
|
||||||
|
type: string
|
||||||
|
type:
|
||||||
|
description: type of condition in CamelCase or in foo.example.com/CamelCase.
|
||||||
|
--- Many .condition.type values are consistent across resources
|
||||||
|
like Available, but because arbitrary conditions can be useful
|
||||||
|
(see .node.status.conditions), the ability to deconflict is
|
||||||
|
important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt)
|
||||||
|
maxLength: 316
|
||||||
|
pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$
|
||||||
|
type: string
|
||||||
|
required:
|
||||||
|
- lastTransitionTime
|
||||||
|
- message
|
||||||
|
- reason
|
||||||
|
- status
|
||||||
|
- type
|
||||||
|
type: object
|
||||||
|
type: array
|
||||||
|
x-kubernetes-list-map-keys:
|
||||||
|
- type
|
||||||
|
x-kubernetes-list-type: map
|
||||||
|
phase:
|
||||||
|
default: Pending
|
||||||
|
description: Phase summarizes the overall status of the FederationDomain.
|
||||||
|
enum:
|
||||||
|
- Pending
|
||||||
|
- Ready
|
||||||
|
- Error
|
||||||
type: string
|
type: string
|
||||||
secrets:
|
secrets:
|
||||||
description: Secrets contains information about this OIDC Provider's
|
description: Secrets contains information about this OIDC Provider's
|
||||||
@ -402,15 +468,6 @@ spec:
|
|||||||
type: string
|
type: string
|
||||||
type: object
|
type: object
|
||||||
type: object
|
type: object
|
||||||
status:
|
|
||||||
description: Status holds an enum that describes the state of this
|
|
||||||
OIDC Provider. Note that this Status can represent success or failure.
|
|
||||||
enum:
|
|
||||||
- Success
|
|
||||||
- Duplicate
|
|
||||||
- Invalid
|
|
||||||
- SameIssuerHostMustUseSameSecret
|
|
||||||
type: string
|
|
||||||
type: object
|
type: object
|
||||||
required:
|
required:
|
||||||
- spec
|
- spec
|
||||||
|
@ -8,14 +8,17 @@ import (
|
|||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
// +kubebuilder:validation:Enum=Success;Duplicate;Invalid;SameIssuerHostMustUseSameSecret
|
type FederationDomainPhase string
|
||||||
type FederationDomainStatusCondition string
|
|
||||||
|
|
||||||
const (
|
const (
|
||||||
SuccessFederationDomainStatusCondition = FederationDomainStatusCondition("Success")
|
// FederationDomainPhasePending is the default phase for newly-created FederationDomain resources.
|
||||||
DuplicateFederationDomainStatusCondition = FederationDomainStatusCondition("Duplicate")
|
FederationDomainPhasePending FederationDomainPhase = "Pending"
|
||||||
SameIssuerHostMustUseSameSecretFederationDomainStatusCondition = FederationDomainStatusCondition("SameIssuerHostMustUseSameSecret")
|
|
||||||
InvalidFederationDomainStatusCondition = FederationDomainStatusCondition("Invalid")
|
// FederationDomainPhaseReady is the phase for an FederationDomain resource in a healthy state.
|
||||||
|
FederationDomainPhaseReady FederationDomainPhase = "Ready"
|
||||||
|
|
||||||
|
// FederationDomainPhaseError is the phase for an FederationDomain in an unhealthy state.
|
||||||
|
FederationDomainPhaseError FederationDomainPhase = "Error"
|
||||||
)
|
)
|
||||||
|
|
||||||
// FederationDomainTLSSpec is a struct that describes the TLS configuration for an OIDC Provider.
|
// FederationDomainTLSSpec is a struct that describes the TLS configuration for an OIDC Provider.
|
||||||
@ -263,20 +266,17 @@ type FederationDomainSecrets struct {
|
|||||||
|
|
||||||
// FederationDomainStatus is a struct that describes the actual state of an OIDC Provider.
|
// FederationDomainStatus is a struct that describes the actual state of an OIDC Provider.
|
||||||
type FederationDomainStatus struct {
|
type FederationDomainStatus struct {
|
||||||
// Status holds an enum that describes the state of this OIDC Provider. Note that this Status can
|
// Phase summarizes the overall status of the FederationDomain.
|
||||||
// represent success or failure.
|
// +kubebuilder:default=Pending
|
||||||
// +optional
|
// +kubebuilder:validation:Enum=Pending;Ready;Error
|
||||||
Status FederationDomainStatusCondition `json:"status,omitempty"`
|
Phase FederationDomainPhase `json:"phase,omitempty"`
|
||||||
|
|
||||||
// Message provides human-readable details about the Status.
|
// Conditions represent the observations of an FederationDomain's current state.
|
||||||
// +optional
|
// +patchMergeKey=type
|
||||||
Message string `json:"message,omitempty"`
|
// +patchStrategy=merge
|
||||||
|
// +listType=map
|
||||||
// LastUpdateTime holds the time at which the Status was last updated. It is a pointer to get
|
// +listMapKey=type
|
||||||
// around some undesirable behavior with respect to the empty metav1.Time value (see
|
Conditions []Condition `json:"conditions,omitempty" patchStrategy:"merge" patchMergeKey:"type"`
|
||||||
// https://github.com/kubernetes/kubernetes/issues/86811).
|
|
||||||
// +optional
|
|
||||||
LastUpdateTime *metav1.Time `json:"lastUpdateTime,omitempty"`
|
|
||||||
|
|
||||||
// Secrets contains information about this OIDC Provider's secrets.
|
// Secrets contains information about this OIDC Provider's secrets.
|
||||||
// +optional
|
// +optional
|
||||||
@ -288,7 +288,7 @@ type FederationDomainStatus struct {
|
|||||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||||
// +kubebuilder:resource:categories=pinniped
|
// +kubebuilder:resource:categories=pinniped
|
||||||
// +kubebuilder:printcolumn:name="Issuer",type=string,JSONPath=`.spec.issuer`
|
// +kubebuilder:printcolumn:name="Issuer",type=string,JSONPath=`.spec.issuer`
|
||||||
// +kubebuilder:printcolumn:name="Status",type=string,JSONPath=`.status.status`
|
// +kubebuilder:printcolumn:name="Phase",type=string,JSONPath=`.status.phase`
|
||||||
// +kubebuilder:printcolumn:name="Age",type=date,JSONPath=`.metadata.creationTimestamp`
|
// +kubebuilder:printcolumn:name="Age",type=date,JSONPath=`.metadata.creationTimestamp`
|
||||||
// +kubebuilder:subresource:status
|
// +kubebuilder:subresource:status
|
||||||
type FederationDomain struct {
|
type FederationDomain struct {
|
||||||
|
@ -8,14 +8,14 @@ import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|||||||
type OIDCClientPhase string
|
type OIDCClientPhase string
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// PhasePending is the default phase for newly-created OIDCClient resources.
|
// OIDCClientPhasePending is the default phase for newly-created OIDCClient resources.
|
||||||
PhasePending OIDCClientPhase = "Pending"
|
OIDCClientPhasePending OIDCClientPhase = "Pending"
|
||||||
|
|
||||||
// PhaseReady is the phase for an OIDCClient resource in a healthy state.
|
// OIDCClientPhaseReady is the phase for an OIDCClient resource in a healthy state.
|
||||||
PhaseReady OIDCClientPhase = "Ready"
|
OIDCClientPhaseReady OIDCClientPhase = "Ready"
|
||||||
|
|
||||||
// PhaseError is the phase for an OIDCClient in an unhealthy state.
|
// OIDCClientPhaseError is the phase for an OIDCClient in an unhealthy state.
|
||||||
PhaseError OIDCClientPhase = "Error"
|
OIDCClientPhaseError OIDCClientPhase = "Error"
|
||||||
)
|
)
|
||||||
|
|
||||||
// +kubebuilder:validation:Pattern=`^https://.+|^http://(127\.0\.0\.1|\[::1\])(:\d+)?/`
|
// +kubebuilder:validation:Pattern=`^https://.+|^http://(127\.0\.0\.1|\[::1\])(:\d+)?/`
|
||||||
|
@ -142,9 +142,12 @@ func (in *FederationDomainSpec) DeepCopy() *FederationDomainSpec {
|
|||||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
func (in *FederationDomainStatus) DeepCopyInto(out *FederationDomainStatus) {
|
func (in *FederationDomainStatus) DeepCopyInto(out *FederationDomainStatus) {
|
||||||
*out = *in
|
*out = *in
|
||||||
if in.LastUpdateTime != nil {
|
if in.Conditions != nil {
|
||||||
in, out := &in.LastUpdateTime, &out.LastUpdateTime
|
in, out := &in.Conditions, &out.Conditions
|
||||||
*out = (*in).DeepCopy()
|
*out = make([]Condition, len(*in))
|
||||||
|
for i := range *in {
|
||||||
|
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||||
|
}
|
||||||
}
|
}
|
||||||
out.Secrets = in.Secrets
|
out.Secrets = in.Secrets
|
||||||
return
|
return
|
||||||
|
@ -67,11 +67,11 @@ func mergeIDPCondition(existing *[]v1.Condition, new *v1.Condition) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// MergeConfigConditions merges conditions into conditionsToUpdate. If returns true if it merged any error conditions.
|
// MergeConfigConditions merges conditions into conditionsToUpdate. If returns true if it merged any error conditions.
|
||||||
func MergeConfigConditions(conditions []*v1.Condition, observedGeneration int64, conditionsToUpdate *[]v1.Condition, log plog.MinLogger) bool {
|
func MergeConfigConditions(conditions []*v1.Condition, observedGeneration int64, conditionsToUpdate *[]v1.Condition, log plog.MinLogger, now v1.Time) bool {
|
||||||
hadErrorCondition := false
|
hadErrorCondition := false
|
||||||
for i := range conditions {
|
for i := range conditions {
|
||||||
cond := conditions[i].DeepCopy()
|
cond := conditions[i].DeepCopy()
|
||||||
cond.LastTransitionTime = v1.Now()
|
cond.LastTransitionTime = now
|
||||||
cond.ObservedGeneration = observedGeneration
|
cond.ObservedGeneration = observedGeneration
|
||||||
if mergeConfigCondition(conditionsToUpdate, cond) {
|
if mergeConfigCondition(conditionsToUpdate, cond) {
|
||||||
log.Info("updated condition", "type", cond.Type, "status", cond.Status, "reason", cond.Reason, "message", cond.Message)
|
log.Info("updated condition", "type", cond.Type, "status", cond.Status, "reason", cond.Reason, "message", cond.Message)
|
||||||
|
@ -10,12 +10,11 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"k8s.io/apimachinery/pkg/api/equality"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/labels"
|
"k8s.io/apimachinery/pkg/labels"
|
||||||
"k8s.io/apimachinery/pkg/types"
|
"k8s.io/apimachinery/pkg/types"
|
||||||
"k8s.io/apimachinery/pkg/util/errors"
|
"k8s.io/apimachinery/pkg/util/errors"
|
||||||
"k8s.io/client-go/util/retry"
|
|
||||||
"k8s.io/klog/v2"
|
|
||||||
"k8s.io/utils/clock"
|
"k8s.io/utils/clock"
|
||||||
|
|
||||||
configv1alpha1 "go.pinniped.dev/generated/latest/apis/supervisor/config/v1alpha1"
|
configv1alpha1 "go.pinniped.dev/generated/latest/apis/supervisor/config/v1alpha1"
|
||||||
@ -24,12 +23,29 @@ import (
|
|||||||
idpinformers "go.pinniped.dev/generated/latest/client/supervisor/informers/externalversions/idp/v1alpha1"
|
idpinformers "go.pinniped.dev/generated/latest/client/supervisor/informers/externalversions/idp/v1alpha1"
|
||||||
"go.pinniped.dev/internal/celtransformer"
|
"go.pinniped.dev/internal/celtransformer"
|
||||||
pinnipedcontroller "go.pinniped.dev/internal/controller"
|
pinnipedcontroller "go.pinniped.dev/internal/controller"
|
||||||
|
"go.pinniped.dev/internal/controller/conditionsutil"
|
||||||
"go.pinniped.dev/internal/controllerlib"
|
"go.pinniped.dev/internal/controllerlib"
|
||||||
"go.pinniped.dev/internal/federationdomain/federationdomainproviders"
|
"go.pinniped.dev/internal/federationdomain/federationdomainproviders"
|
||||||
"go.pinniped.dev/internal/idtransform"
|
"go.pinniped.dev/internal/idtransform"
|
||||||
"go.pinniped.dev/internal/plog"
|
"go.pinniped.dev/internal/plog"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
typeReady = "Ready"
|
||||||
|
typeIssuerURLValid = "IssuerURLValid"
|
||||||
|
typeOneTLSSecretPerIssuerHostname = "OneTLSSecretPerIssuerHostname"
|
||||||
|
typeIssuerIsUnique = "IssuerIsUnique"
|
||||||
|
|
||||||
|
reasonSuccess = "Success"
|
||||||
|
reasonNotReady = "NotReady"
|
||||||
|
reasonUnableToValidate = "UnableToValidate"
|
||||||
|
reasonInvalidIssuerURL = "InvalidIssuerURL"
|
||||||
|
reasonDuplicateIssuer = "DuplicateIssuer"
|
||||||
|
reasonDifferentSecretRefsFound = "DifferentSecretRefsFound"
|
||||||
|
|
||||||
|
celTransformerMaxExpressionRuntime = 5 * time.Second
|
||||||
|
)
|
||||||
|
|
||||||
// FederationDomainsSetter can be notified of all known valid providers with its SetIssuer function.
|
// FederationDomainsSetter can be notified of all known valid providers with its SetIssuer function.
|
||||||
// If there are no longer any valid issuers, then it can be called with no arguments.
|
// If there are no longer any valid issuers, then it can be called with no arguments.
|
||||||
// Implementations of this type should be thread-safe to support calls from multiple goroutines.
|
// Implementations of this type should be thread-safe to support calls from multiple goroutines.
|
||||||
@ -109,75 +125,14 @@ func (c *federationDomainWatcherController) Sync(ctx controllerlib.Context) erro
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make a map of issuer strings -> count of how many times we saw that issuer string.
|
|
||||||
// This will help us complain when there are duplicate issuer strings.
|
|
||||||
// Also make a helper function for forming keys into this map.
|
|
||||||
issuerCounts := make(map[string]int)
|
|
||||||
issuerURLToIssuerKey := func(issuerURL *url.URL) string {
|
|
||||||
return fmt.Sprintf("%s://%s%s", issuerURL.Scheme, strings.ToLower(issuerURL.Host), issuerURL.Path)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Make a map of issuer hostnames -> set of unique secret names. This will help us complain when
|
|
||||||
// multiple FederationDomains have the same issuer hostname (excluding port) but specify
|
|
||||||
// different TLS serving Secrets. Doesn't make sense to have the one address use more than one
|
|
||||||
// TLS cert. Ignore ports because SNI information on the incoming requests is not going to include
|
|
||||||
// port numbers. Also make a helper function for forming keys into this map.
|
|
||||||
uniqueSecretNamesPerIssuerAddress := make(map[string]map[string]bool)
|
|
||||||
issuerURLToHostnameKey := lowercaseHostWithoutPort
|
|
||||||
|
|
||||||
for _, federationDomain := range federationDomains {
|
|
||||||
issuerURL, err := url.Parse(federationDomain.Spec.Issuer)
|
|
||||||
if err != nil {
|
|
||||||
continue // Skip url parse errors because they will be validated again below.
|
|
||||||
}
|
|
||||||
|
|
||||||
issuerCounts[issuerURLToIssuerKey(issuerURL)]++
|
|
||||||
|
|
||||||
setOfSecretNames := uniqueSecretNamesPerIssuerAddress[issuerURLToHostnameKey(issuerURL)]
|
|
||||||
if setOfSecretNames == nil {
|
|
||||||
setOfSecretNames = make(map[string]bool)
|
|
||||||
uniqueSecretNamesPerIssuerAddress[issuerURLToHostnameKey(issuerURL)] = setOfSecretNames
|
|
||||||
}
|
|
||||||
if federationDomain.Spec.TLS != nil {
|
|
||||||
setOfSecretNames[federationDomain.Spec.TLS.SecretName] = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var errs []error
|
var errs []error
|
||||||
|
|
||||||
federationDomainIssuers := make([]*federationdomainproviders.FederationDomainIssuer, 0)
|
federationDomainIssuers := make([]*federationdomainproviders.FederationDomainIssuer, 0)
|
||||||
|
crossDomainConfigValidator := newCrossFederationDomainConfigValidator(federationDomains)
|
||||||
|
|
||||||
for _, federationDomain := range federationDomains {
|
for _, federationDomain := range federationDomains {
|
||||||
issuerURL, urlParseErr := url.Parse(federationDomain.Spec.Issuer)
|
conditions := make([]*configv1alpha1.Condition, 0, 4)
|
||||||
|
|
||||||
// Skip url parse errors because they will be validated below.
|
conditions = crossDomainConfigValidator.Validate(federationDomain, conditions)
|
||||||
if urlParseErr == nil {
|
|
||||||
if issuerCount := issuerCounts[issuerURLToIssuerKey(issuerURL)]; issuerCount > 1 {
|
|
||||||
if err := c.updateStatus(
|
|
||||||
ctx.Context,
|
|
||||||
federationDomain.Namespace,
|
|
||||||
federationDomain.Name,
|
|
||||||
configv1alpha1.DuplicateFederationDomainStatusCondition,
|
|
||||||
"Duplicate issuer: "+federationDomain.Spec.Issuer,
|
|
||||||
); err != nil {
|
|
||||||
errs = append(errs, fmt.Errorf("could not update status: %w", err))
|
|
||||||
}
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Skip url parse errors because they will be validated below.
|
|
||||||
if urlParseErr == nil && len(uniqueSecretNamesPerIssuerAddress[issuerURLToHostnameKey(issuerURL)]) > 1 {
|
|
||||||
if err := c.updateStatus(
|
|
||||||
ctx.Context,
|
|
||||||
federationDomain.Namespace,
|
|
||||||
federationDomain.Name,
|
|
||||||
configv1alpha1.SameIssuerHostMustUseSameSecretFederationDomainStatusCondition,
|
|
||||||
"Issuers with the same DNS hostname (address not including port) must use the same secretName: "+issuerURLToHostnameKey(issuerURL),
|
|
||||||
); err != nil {
|
|
||||||
errs = append(errs, fmt.Errorf("could not update status: %w", err))
|
|
||||||
}
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Move all this identity provider stuff into helper functions. This is just a sketch of how the code would
|
// TODO: Move all this identity provider stuff into helper functions. This is just a sketch of how the code would
|
||||||
// work in the sense that this is not doing error handling, is not validating everything that it should, and
|
// work in the sense that this is not doing error handling, is not validating everything that it should, and
|
||||||
@ -232,7 +187,7 @@ func (c *federationDomainWatcherController) Sync(ctx controllerlib.Context) erro
|
|||||||
}
|
}
|
||||||
|
|
||||||
// If there is an explicit list of IDPs on the FederationDomain, then process the list.
|
// If there is an explicit list of IDPs on the FederationDomain, then process the list.
|
||||||
celTransformer, _ := celtransformer.NewCELTransformer(time.Second) // TODO: what is a good duration limit here?
|
celTransformer, _ := celtransformer.NewCELTransformer(celTransformerMaxExpressionRuntime) // TODO: what is a good duration limit here?
|
||||||
// TODO: handle err
|
// TODO: handle err
|
||||||
for _, idp := range federationDomain.Spec.IdentityProviders {
|
for _, idp := range federationDomain.Spec.IdentityProviders {
|
||||||
var idpResourceUID types.UID
|
var idpResourceUID types.UID
|
||||||
@ -375,7 +330,7 @@ func (c *federationDomainWatcherController) Sync(ctx controllerlib.Context) erro
|
|||||||
}
|
}
|
||||||
if !stringSlicesEqual(e.Expects.Groups, result.Groups) {
|
if !stringSlicesEqual(e.Expects.Groups, result.Groups) {
|
||||||
// TODO: Do we need to make this insensitive to ordering, or should the transformations evaluator be changed to always return sorted group names at the end of the pipeline?
|
// TODO: Do we need to make this insensitive to ordering, or should the transformations evaluator be changed to always return sorted group names at the end of the pipeline?
|
||||||
// TODO: What happens if the user did not write any group expectation? Treat it like expecting any empty list of groups?
|
// TODO: What happens if the user did not write any group expectation? Treat it like expecting an empty list of groups?
|
||||||
// TODO: handle this failed example
|
// TODO: handle this failed example
|
||||||
plog.Warning("FederationDomain identity provider transformations example failed: expected a different transformed groups list",
|
plog.Warning("FederationDomain identity provider transformations example failed: expected a different transformed groups list",
|
||||||
"federationDomain", federationDomain.Name,
|
"federationDomain", federationDomain.Name,
|
||||||
@ -402,7 +357,6 @@ func (c *federationDomainWatcherController) Sync(ctx controllerlib.Context) erro
|
|||||||
|
|
||||||
// Now that we have the list of IDPs for this FederationDomain, create the issuer.
|
// Now that we have the list of IDPs for this FederationDomain, create the issuer.
|
||||||
var federationDomainIssuer *federationdomainproviders.FederationDomainIssuer
|
var federationDomainIssuer *federationdomainproviders.FederationDomainIssuer
|
||||||
err = nil
|
|
||||||
if defaultFederationDomainIdentityProvider != nil {
|
if defaultFederationDomainIdentityProvider != nil {
|
||||||
// This is the constructor for the backwards compatibility mode.
|
// This is the constructor for the backwards compatibility mode.
|
||||||
federationDomainIssuer, err = federationdomainproviders.NewFederationDomainIssuerWithDefaultIDP(federationDomain.Spec.Issuer, defaultFederationDomainIdentityProvider)
|
federationDomainIssuer, err = federationdomainproviders.NewFederationDomainIssuerWithDefaultIDP(federationDomain.Spec.Issuer, defaultFederationDomainIdentityProvider)
|
||||||
@ -411,38 +365,193 @@ func (c *federationDomainWatcherController) Sync(ctx controllerlib.Context) erro
|
|||||||
federationDomainIssuer, err = federationdomainproviders.NewFederationDomainIssuer(federationDomain.Spec.Issuer, federationDomainIdentityProviders)
|
federationDomainIssuer, err = federationdomainproviders.NewFederationDomainIssuer(federationDomain.Spec.Issuer, federationDomainIdentityProviders)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// Note that the FederationDomainIssuer constructors validate the Issuer URL.
|
// Note that the FederationDomainIssuer constructors only validate the Issuer URL,
|
||||||
if err := c.updateStatus(
|
// so these are always issuer URL validation errors.
|
||||||
ctx.Context,
|
conditions = append(conditions, &configv1alpha1.Condition{
|
||||||
federationDomain.Namespace,
|
Type: typeIssuerURLValid,
|
||||||
federationDomain.Name,
|
Status: configv1alpha1.ConditionFalse,
|
||||||
configv1alpha1.InvalidFederationDomainStatusCondition,
|
Reason: reasonInvalidIssuerURL,
|
||||||
"Invalid: "+err.Error(),
|
Message: err.Error(),
|
||||||
); err != nil {
|
})
|
||||||
errs = append(errs, fmt.Errorf("could not update status: %w", err))
|
} else {
|
||||||
}
|
conditions = append(conditions, &configv1alpha1.Condition{
|
||||||
continue
|
Type: typeIssuerURLValid,
|
||||||
|
Status: configv1alpha1.ConditionTrue,
|
||||||
|
Reason: reasonSuccess,
|
||||||
|
Message: "spec.issuer is a valid URL",
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := c.updateStatus(
|
if err = c.updateStatus(ctx.Context, federationDomain, conditions); err != nil {
|
||||||
ctx.Context,
|
|
||||||
federationDomain.Namespace,
|
|
||||||
federationDomain.Name,
|
|
||||||
configv1alpha1.SuccessFederationDomainStatusCondition,
|
|
||||||
"Provider successfully created",
|
|
||||||
); err != nil {
|
|
||||||
errs = append(errs, fmt.Errorf("could not update status: %w", err))
|
errs = append(errs, fmt.Errorf("could not update status: %w", err))
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !hadErrorCondition(conditions) {
|
||||||
|
// Successfully validated the FederationDomain, so allow it to be loaded.
|
||||||
federationDomainIssuers = append(federationDomainIssuers, federationDomainIssuer)
|
federationDomainIssuers = append(federationDomainIssuers, federationDomainIssuer)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
c.federationDomainsSetter.SetFederationDomains(federationDomainIssuers...)
|
c.federationDomainsSetter.SetFederationDomains(federationDomainIssuers...)
|
||||||
|
|
||||||
return errors.NewAggregate(errs)
|
return errors.NewAggregate(errs)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *federationDomainWatcherController) updateStatus(
|
||||||
|
ctx context.Context,
|
||||||
|
federationDomain *configv1alpha1.FederationDomain,
|
||||||
|
conditions []*configv1alpha1.Condition,
|
||||||
|
) error {
|
||||||
|
updated := federationDomain.DeepCopy()
|
||||||
|
|
||||||
|
if hadErrorCondition(conditions) {
|
||||||
|
updated.Status.Phase = configv1alpha1.FederationDomainPhaseError
|
||||||
|
conditions = append(conditions, &configv1alpha1.Condition{
|
||||||
|
Type: typeReady,
|
||||||
|
Status: configv1alpha1.ConditionFalse,
|
||||||
|
Reason: reasonNotReady,
|
||||||
|
Message: "the FederationDomain is not ready: see other conditions for details",
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
updated.Status.Phase = configv1alpha1.FederationDomainPhaseReady
|
||||||
|
conditions = append(conditions, &configv1alpha1.Condition{
|
||||||
|
Type: typeReady,
|
||||||
|
Status: configv1alpha1.ConditionTrue,
|
||||||
|
Reason: reasonSuccess,
|
||||||
|
Message: fmt.Sprintf("the FederationDomain is ready and its endpoints are available: "+
|
||||||
|
"the discovery endpoint is %s/.well-known/openid-configuration", federationDomain.Spec.Issuer),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
_ = conditionsutil.MergeConfigConditions(conditions,
|
||||||
|
federationDomain.Generation, &updated.Status.Conditions, plog.New(), metav1.NewTime(c.clock.Now()))
|
||||||
|
|
||||||
|
if equality.Semantic.DeepEqual(federationDomain, updated) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err := c.client.
|
||||||
|
ConfigV1alpha1().
|
||||||
|
FederationDomains(federationDomain.Namespace).
|
||||||
|
UpdateStatus(ctx, updated, metav1.UpdateOptions{})
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
type crossFederationDomainConfigValidator struct {
|
||||||
|
issuerCounts map[string]int
|
||||||
|
uniqueSecretNamesPerIssuerAddress map[string]map[string]bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func issuerURLToHostnameKey(issuerURL *url.URL) string {
|
||||||
|
return lowercaseHostWithoutPort(issuerURL)
|
||||||
|
}
|
||||||
|
|
||||||
|
func issuerURLToIssuerKey(issuerURL *url.URL) string {
|
||||||
|
return fmt.Sprintf("%s://%s%s", issuerURL.Scheme, strings.ToLower(issuerURL.Host), issuerURL.Path)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *crossFederationDomainConfigValidator) Validate(federationDomain *configv1alpha1.FederationDomain, conditions []*configv1alpha1.Condition) []*configv1alpha1.Condition {
|
||||||
|
issuerURL, urlParseErr := url.Parse(federationDomain.Spec.Issuer)
|
||||||
|
|
||||||
|
if urlParseErr != nil {
|
||||||
|
// Don't write a condition about the issuer URL being invalid because that is added elsewhere in the controller.
|
||||||
|
conditions = append(conditions, &configv1alpha1.Condition{
|
||||||
|
Type: typeIssuerIsUnique,
|
||||||
|
Status: configv1alpha1.ConditionUnknown,
|
||||||
|
Reason: reasonUnableToValidate,
|
||||||
|
Message: "unable to check if spec.issuer is unique among all FederationDomains because URL cannot be parsed",
|
||||||
|
})
|
||||||
|
conditions = append(conditions, &configv1alpha1.Condition{
|
||||||
|
Type: typeOneTLSSecretPerIssuerHostname,
|
||||||
|
Status: configv1alpha1.ConditionUnknown,
|
||||||
|
Reason: reasonUnableToValidate,
|
||||||
|
Message: "unable to check if all FederationDomains are using the same TLS secret when using the same hostname in the spec.issuer URL because URL cannot be parsed",
|
||||||
|
})
|
||||||
|
return conditions
|
||||||
|
}
|
||||||
|
|
||||||
|
if issuerCount := v.issuerCounts[issuerURLToIssuerKey(issuerURL)]; issuerCount > 1 {
|
||||||
|
conditions = append(conditions, &configv1alpha1.Condition{
|
||||||
|
Type: typeIssuerIsUnique,
|
||||||
|
Status: configv1alpha1.ConditionFalse,
|
||||||
|
Reason: reasonDuplicateIssuer,
|
||||||
|
Message: "multiple FederationDomains have the same spec.issuer URL: these URLs must be unique (can use different hosts or paths)",
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
conditions = append(conditions, &configv1alpha1.Condition{
|
||||||
|
Type: typeIssuerIsUnique,
|
||||||
|
Status: configv1alpha1.ConditionTrue,
|
||||||
|
Reason: reasonSuccess,
|
||||||
|
Message: "spec.issuer is unique among all FederationDomains",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(v.uniqueSecretNamesPerIssuerAddress[issuerURLToHostnameKey(issuerURL)]) > 1 {
|
||||||
|
conditions = append(conditions, &configv1alpha1.Condition{
|
||||||
|
Type: typeOneTLSSecretPerIssuerHostname,
|
||||||
|
Status: configv1alpha1.ConditionFalse,
|
||||||
|
Reason: reasonDifferentSecretRefsFound,
|
||||||
|
Message: "when different FederationDomains are using the same hostname in the spec.issuer URL then they must also use the same TLS secretRef: different secretRefs found",
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
conditions = append(conditions, &configv1alpha1.Condition{
|
||||||
|
Type: typeOneTLSSecretPerIssuerHostname,
|
||||||
|
Status: configv1alpha1.ConditionTrue,
|
||||||
|
Reason: reasonSuccess,
|
||||||
|
Message: "all FederationDomains are using the same TLS secret when using the same hostname in the spec.issuer URL",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return conditions
|
||||||
|
}
|
||||||
|
|
||||||
|
func newCrossFederationDomainConfigValidator(federationDomains []*configv1alpha1.FederationDomain) *crossFederationDomainConfigValidator {
|
||||||
|
// Make a map of issuer strings -> count of how many times we saw that issuer string.
|
||||||
|
// This will help us complain when there are duplicate issuer strings.
|
||||||
|
// Also make a helper function for forming keys into this map.
|
||||||
|
issuerCounts := make(map[string]int)
|
||||||
|
|
||||||
|
// Make a map of issuer hostnames -> set of unique secret names. This will help us complain when
|
||||||
|
// multiple FederationDomains have the same issuer hostname (excluding port) but specify
|
||||||
|
// different TLS serving Secrets. Doesn't make sense to have the one address use more than one
|
||||||
|
// TLS cert. Ignore ports because SNI information on the incoming requests is not going to include
|
||||||
|
// port numbers. Also make a helper function for forming keys into this map.
|
||||||
|
uniqueSecretNamesPerIssuerAddress := make(map[string]map[string]bool)
|
||||||
|
|
||||||
|
for _, federationDomain := range federationDomains {
|
||||||
|
issuerURL, err := url.Parse(federationDomain.Spec.Issuer)
|
||||||
|
if err != nil {
|
||||||
|
continue // Skip url parse errors because they will be handled in the Validate function.
|
||||||
|
}
|
||||||
|
|
||||||
|
issuerCounts[issuerURLToIssuerKey(issuerURL)]++
|
||||||
|
|
||||||
|
setOfSecretNames := uniqueSecretNamesPerIssuerAddress[issuerURLToHostnameKey(issuerURL)]
|
||||||
|
if setOfSecretNames == nil {
|
||||||
|
setOfSecretNames = make(map[string]bool)
|
||||||
|
uniqueSecretNamesPerIssuerAddress[issuerURLToHostnameKey(issuerURL)] = setOfSecretNames
|
||||||
|
}
|
||||||
|
if federationDomain.Spec.TLS != nil {
|
||||||
|
setOfSecretNames[federationDomain.Spec.TLS.SecretName] = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return &crossFederationDomainConfigValidator{
|
||||||
|
issuerCounts: issuerCounts,
|
||||||
|
uniqueSecretNamesPerIssuerAddress: uniqueSecretNamesPerIssuerAddress,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func hadErrorCondition(conditions []*configv1alpha1.Condition) bool {
|
||||||
|
for _, c := range conditions {
|
||||||
|
if c.Status != configv1alpha1.ConditionTrue {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
func stringSlicesEqual(a []string, b []string) bool {
|
func stringSlicesEqual(a []string, b []string) bool {
|
||||||
if len(a) != len(b) {
|
if len(a) != len(b) {
|
||||||
return false
|
return false
|
||||||
@ -454,38 +563,3 @@ func stringSlicesEqual(a []string, b []string) bool {
|
|||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *federationDomainWatcherController) updateStatus(
|
|
||||||
ctx context.Context,
|
|
||||||
namespace, name string,
|
|
||||||
status configv1alpha1.FederationDomainStatusCondition,
|
|
||||||
message string,
|
|
||||||
) error {
|
|
||||||
return retry.RetryOnConflict(retry.DefaultRetry, func() error {
|
|
||||||
federationDomain, err := c.client.ConfigV1alpha1().FederationDomains(namespace).Get(ctx, name, metav1.GetOptions{})
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("get failed: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if federationDomain.Status.Status == status && federationDomain.Status.Message == message {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
plog.Debug(
|
|
||||||
"attempting status update",
|
|
||||||
"federationdomain",
|
|
||||||
klog.KRef(namespace, name),
|
|
||||||
"status",
|
|
||||||
status,
|
|
||||||
"message",
|
|
||||||
message,
|
|
||||||
)
|
|
||||||
federationDomain.Status.Status = status
|
|
||||||
federationDomain.Status.Message = message
|
|
||||||
federationDomain.Status.LastUpdateTime = timePtr(metav1.NewTime(c.clock.Now()))
|
|
||||||
_, err = c.client.ConfigV1alpha1().FederationDomains(namespace).UpdateStatus(ctx, federationDomain, metav1.UpdateOptions{})
|
|
||||||
return err
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func timePtr(t metav1.Time) *metav1.Time { return &t }
|
|
||||||
|
@ -16,7 +16,6 @@ import (
|
|||||||
"github.com/sclevine/spec"
|
"github.com/sclevine/spec"
|
||||||
"github.com/sclevine/spec/report"
|
"github.com/sclevine/spec/report"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
k8serrors "k8s.io/apimachinery/pkg/api/errors"
|
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||||
@ -28,7 +27,6 @@ import (
|
|||||||
pinnipedinformers "go.pinniped.dev/generated/latest/client/supervisor/informers/externalversions"
|
pinnipedinformers "go.pinniped.dev/generated/latest/client/supervisor/informers/externalversions"
|
||||||
"go.pinniped.dev/internal/controllerlib"
|
"go.pinniped.dev/internal/controllerlib"
|
||||||
"go.pinniped.dev/internal/federationdomain/federationdomainproviders"
|
"go.pinniped.dev/internal/federationdomain/federationdomainproviders"
|
||||||
"go.pinniped.dev/internal/here"
|
|
||||||
"go.pinniped.dev/internal/testutil"
|
"go.pinniped.dev/internal/testutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -113,8 +111,21 @@ func TestSync(t *testing.T) {
|
|||||||
var cancelContextCancelFunc context.CancelFunc
|
var cancelContextCancelFunc context.CancelFunc
|
||||||
var syncContext *controllerlib.Context
|
var syncContext *controllerlib.Context
|
||||||
var frozenNow time.Time
|
var frozenNow time.Time
|
||||||
|
var frozenMetav1Now metav1.Time
|
||||||
var federationDomainsSetter *fakeFederationDomainsSetter
|
var federationDomainsSetter *fakeFederationDomainsSetter
|
||||||
var federationDomainGVR schema.GroupVersionResource
|
var federationDomainGVR schema.GroupVersionResource
|
||||||
|
var allHappyConditions func(issuer string, time metav1.Time, observedGeneration int64) []v1alpha1.Condition
|
||||||
|
var happyReadyCondition func(issuer string, time metav1.Time, observedGeneration int64) v1alpha1.Condition
|
||||||
|
var happyIssuerIsUniqueCondition,
|
||||||
|
unknownIssuerIsUniqueCondition,
|
||||||
|
sadIssuerIsUniqueCondition,
|
||||||
|
happyOneTLSSecretPerIssuerHostnameCondition,
|
||||||
|
unknownOneTLSSecretPerIssuerHostnameCondition,
|
||||||
|
sadOneTLSSecretPerIssuerHostnameCondition,
|
||||||
|
happyIssuerURLValidCondition,
|
||||||
|
sadIssuerURLValidConditionCannotHaveQuery,
|
||||||
|
sadIssuerURLValidConditionCannotParse,
|
||||||
|
sadReadyCondition func(time metav1.Time, observedGeneration int64) v1alpha1.Condition
|
||||||
|
|
||||||
// Defer starting the informers until the last possible moment so that the
|
// Defer starting the informers until the last possible moment so that the
|
||||||
// nested Before's can keep adding things to the informer caches.
|
// nested Before's can keep adding things to the informer caches.
|
||||||
@ -163,6 +174,139 @@ func TestSync(t *testing.T) {
|
|||||||
Version: v1alpha1.SchemeGroupVersion.Version,
|
Version: v1alpha1.SchemeGroupVersion.Version,
|
||||||
Resource: "federationdomains",
|
Resource: "federationdomains",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
frozenMetav1Now = metav1.NewTime(frozenNow)
|
||||||
|
|
||||||
|
happyReadyCondition = func(issuer string, time metav1.Time, observedGeneration int64) v1alpha1.Condition {
|
||||||
|
return v1alpha1.Condition{
|
||||||
|
Type: "Ready",
|
||||||
|
Status: "True",
|
||||||
|
ObservedGeneration: observedGeneration,
|
||||||
|
LastTransitionTime: time,
|
||||||
|
Reason: "Success",
|
||||||
|
Message: fmt.Sprintf("the FederationDomain is ready and its endpoints are available: "+
|
||||||
|
"the discovery endpoint is %s/.well-known/openid-configuration", issuer),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sadReadyCondition = func(time metav1.Time, observedGeneration int64) v1alpha1.Condition {
|
||||||
|
return v1alpha1.Condition{
|
||||||
|
Type: "Ready",
|
||||||
|
Status: "False",
|
||||||
|
ObservedGeneration: observedGeneration,
|
||||||
|
LastTransitionTime: time,
|
||||||
|
Reason: "NotReady",
|
||||||
|
Message: "the FederationDomain is not ready: see other conditions for details",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
happyIssuerIsUniqueCondition = func(time metav1.Time, observedGeneration int64) v1alpha1.Condition {
|
||||||
|
return v1alpha1.Condition{
|
||||||
|
Type: "IssuerIsUnique",
|
||||||
|
Status: "True",
|
||||||
|
ObservedGeneration: observedGeneration,
|
||||||
|
LastTransitionTime: time,
|
||||||
|
Reason: "Success",
|
||||||
|
Message: "spec.issuer is unique among all FederationDomains",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unknownIssuerIsUniqueCondition = func(time metav1.Time, observedGeneration int64) v1alpha1.Condition {
|
||||||
|
return v1alpha1.Condition{
|
||||||
|
Type: "IssuerIsUnique",
|
||||||
|
Status: "Unknown",
|
||||||
|
ObservedGeneration: observedGeneration,
|
||||||
|
LastTransitionTime: time,
|
||||||
|
Reason: "UnableToValidate",
|
||||||
|
Message: "unable to check if spec.issuer is unique among all FederationDomains because URL cannot be parsed",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sadIssuerIsUniqueCondition = func(time metav1.Time, observedGeneration int64) v1alpha1.Condition {
|
||||||
|
return v1alpha1.Condition{
|
||||||
|
Type: "IssuerIsUnique",
|
||||||
|
Status: "False",
|
||||||
|
ObservedGeneration: observedGeneration,
|
||||||
|
LastTransitionTime: time,
|
||||||
|
Reason: "DuplicateIssuer",
|
||||||
|
Message: "multiple FederationDomains have the same spec.issuer URL: these URLs must be unique (can use different hosts or paths)",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
happyOneTLSSecretPerIssuerHostnameCondition = func(time metav1.Time, observedGeneration int64) v1alpha1.Condition {
|
||||||
|
return v1alpha1.Condition{
|
||||||
|
Type: "OneTLSSecretPerIssuerHostname",
|
||||||
|
Status: "True",
|
||||||
|
ObservedGeneration: observedGeneration,
|
||||||
|
LastTransitionTime: time,
|
||||||
|
Reason: "Success",
|
||||||
|
Message: "all FederationDomains are using the same TLS secret when using the same hostname in the spec.issuer URL",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unknownOneTLSSecretPerIssuerHostnameCondition = func(time metav1.Time, observedGeneration int64) v1alpha1.Condition {
|
||||||
|
return v1alpha1.Condition{
|
||||||
|
Type: "OneTLSSecretPerIssuerHostname",
|
||||||
|
Status: "Unknown",
|
||||||
|
ObservedGeneration: observedGeneration,
|
||||||
|
LastTransitionTime: time,
|
||||||
|
Reason: "UnableToValidate",
|
||||||
|
Message: "unable to check if all FederationDomains are using the same TLS secret when using the same hostname in the spec.issuer URL because URL cannot be parsed",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sadOneTLSSecretPerIssuerHostnameCondition = func(time metav1.Time, observedGeneration int64) v1alpha1.Condition {
|
||||||
|
return v1alpha1.Condition{
|
||||||
|
Type: "OneTLSSecretPerIssuerHostname",
|
||||||
|
Status: "False",
|
||||||
|
ObservedGeneration: observedGeneration,
|
||||||
|
LastTransitionTime: time,
|
||||||
|
Reason: "DifferentSecretRefsFound",
|
||||||
|
Message: "when different FederationDomains are using the same hostname in the spec.issuer URL then they must also use the same TLS secretRef: different secretRefs found",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
happyIssuerURLValidCondition = func(time metav1.Time, observedGeneration int64) v1alpha1.Condition {
|
||||||
|
return v1alpha1.Condition{
|
||||||
|
Type: "IssuerURLValid",
|
||||||
|
Status: "True",
|
||||||
|
ObservedGeneration: observedGeneration,
|
||||||
|
LastTransitionTime: time,
|
||||||
|
Reason: "Success",
|
||||||
|
Message: "spec.issuer is a valid URL",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sadIssuerURLValidConditionCannotHaveQuery = func(time metav1.Time, observedGeneration int64) v1alpha1.Condition {
|
||||||
|
return v1alpha1.Condition{
|
||||||
|
Type: "IssuerURLValid",
|
||||||
|
Status: "False",
|
||||||
|
ObservedGeneration: observedGeneration,
|
||||||
|
LastTransitionTime: time,
|
||||||
|
Reason: "InvalidIssuerURL",
|
||||||
|
Message: "issuer must not have query",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sadIssuerURLValidConditionCannotParse = func(time metav1.Time, observedGeneration int64) v1alpha1.Condition {
|
||||||
|
return v1alpha1.Condition{
|
||||||
|
Type: "IssuerURLValid",
|
||||||
|
Status: "False",
|
||||||
|
ObservedGeneration: observedGeneration,
|
||||||
|
LastTransitionTime: time,
|
||||||
|
Reason: "InvalidIssuerURL",
|
||||||
|
Message: `could not parse issuer as URL: parse ":/host//path": missing protocol scheme`,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
allHappyConditions = func(issuer string, time metav1.Time, observedGeneration int64) []v1alpha1.Condition {
|
||||||
|
return []v1alpha1.Condition{
|
||||||
|
happyIssuerIsUniqueCondition(time, observedGeneration),
|
||||||
|
happyIssuerURLValidCondition(time, observedGeneration),
|
||||||
|
happyOneTLSSecretPerIssuerHostnameCondition(time, observedGeneration),
|
||||||
|
happyReadyCondition(issuer, time, observedGeneration),
|
||||||
|
}
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
it.After(func() {
|
it.After(func() {
|
||||||
@ -177,14 +321,14 @@ func TestSync(t *testing.T) {
|
|||||||
|
|
||||||
it.Before(func() {
|
it.Before(func() {
|
||||||
federationDomain1 = &v1alpha1.FederationDomain{
|
federationDomain1 = &v1alpha1.FederationDomain{
|
||||||
ObjectMeta: metav1.ObjectMeta{Name: "config1", Namespace: namespace},
|
ObjectMeta: metav1.ObjectMeta{Name: "config1", Namespace: namespace, Generation: 123},
|
||||||
Spec: v1alpha1.FederationDomainSpec{Issuer: "https://issuer1.com"},
|
Spec: v1alpha1.FederationDomainSpec{Issuer: "https://issuer1.com"},
|
||||||
}
|
}
|
||||||
r.NoError(pinnipedAPIClient.Tracker().Add(federationDomain1))
|
r.NoError(pinnipedAPIClient.Tracker().Add(federationDomain1))
|
||||||
r.NoError(pinnipedInformerClient.Tracker().Add(federationDomain1))
|
r.NoError(pinnipedInformerClient.Tracker().Add(federationDomain1))
|
||||||
|
|
||||||
federationDomain2 = &v1alpha1.FederationDomain{
|
federationDomain2 = &v1alpha1.FederationDomain{
|
||||||
ObjectMeta: metav1.ObjectMeta{Name: "config2", Namespace: namespace},
|
ObjectMeta: metav1.ObjectMeta{Name: "config2", Namespace: namespace, Generation: 123},
|
||||||
Spec: v1alpha1.FederationDomainSpec{Issuer: "https://issuer2.com"},
|
Spec: v1alpha1.FederationDomainSpec{Issuer: "https://issuer2.com"},
|
||||||
}
|
}
|
||||||
r.NoError(pinnipedAPIClient.Tracker().Add(federationDomain2))
|
r.NoError(pinnipedAPIClient.Tracker().Add(federationDomain2))
|
||||||
@ -212,36 +356,24 @@ func TestSync(t *testing.T) {
|
|||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
it("updates the status to success in the FederationDomains", func() {
|
it("updates the status to ready in the FederationDomains", func() {
|
||||||
startInformersAndController()
|
startInformersAndController()
|
||||||
err := controllerlib.TestSync(t, subject, *syncContext)
|
err := controllerlib.TestSync(t, subject, *syncContext)
|
||||||
r.NoError(err)
|
r.NoError(err)
|
||||||
|
|
||||||
federationDomain1.Status.Status = v1alpha1.SuccessFederationDomainStatusCondition
|
federationDomain1.Status.Phase = v1alpha1.FederationDomainPhaseReady
|
||||||
federationDomain1.Status.Message = "Provider successfully created"
|
federationDomain1.Status.Conditions = allHappyConditions(federationDomain1.Spec.Issuer, frozenMetav1Now, 123)
|
||||||
federationDomain1.Status.LastUpdateTime = timePtr(metav1.NewTime(frozenNow))
|
|
||||||
|
|
||||||
federationDomain2.Status.Status = v1alpha1.SuccessFederationDomainStatusCondition
|
federationDomain2.Status.Phase = v1alpha1.FederationDomainPhaseReady
|
||||||
federationDomain2.Status.Message = "Provider successfully created"
|
federationDomain2.Status.Conditions = allHappyConditions(federationDomain2.Spec.Issuer, frozenMetav1Now, 123)
|
||||||
federationDomain2.Status.LastUpdateTime = timePtr(metav1.NewTime(frozenNow))
|
|
||||||
|
|
||||||
expectedActions := []coretesting.Action{
|
expectedActions := []coretesting.Action{
|
||||||
coretesting.NewGetAction(
|
|
||||||
federationDomainGVR,
|
|
||||||
federationDomain1.Namespace,
|
|
||||||
federationDomain1.Name,
|
|
||||||
),
|
|
||||||
coretesting.NewUpdateSubresourceAction(
|
coretesting.NewUpdateSubresourceAction(
|
||||||
federationDomainGVR,
|
federationDomainGVR,
|
||||||
"status",
|
"status",
|
||||||
federationDomain1.Namespace,
|
federationDomain1.Namespace,
|
||||||
federationDomain1,
|
federationDomain1,
|
||||||
),
|
),
|
||||||
coretesting.NewGetAction(
|
|
||||||
federationDomainGVR,
|
|
||||||
federationDomain2.Namespace,
|
|
||||||
federationDomain2.Name,
|
|
||||||
),
|
|
||||||
coretesting.NewUpdateSubresourceAction(
|
coretesting.NewUpdateSubresourceAction(
|
||||||
federationDomainGVR,
|
federationDomainGVR,
|
||||||
"status",
|
"status",
|
||||||
@ -254,9 +386,8 @@ func TestSync(t *testing.T) {
|
|||||||
|
|
||||||
when("one FederationDomain is already up to date", func() {
|
when("one FederationDomain is already up to date", func() {
|
||||||
it.Before(func() {
|
it.Before(func() {
|
||||||
federationDomain1.Status.Status = v1alpha1.SuccessFederationDomainStatusCondition
|
federationDomain1.Status.Phase = v1alpha1.FederationDomainPhaseReady
|
||||||
federationDomain1.Status.Message = "Provider successfully created"
|
federationDomain1.Status.Conditions = allHappyConditions(federationDomain1.Spec.Issuer, frozenMetav1Now, 123)
|
||||||
federationDomain1.Status.LastUpdateTime = timePtr(metav1.NewTime(frozenNow))
|
|
||||||
|
|
||||||
r.NoError(pinnipedAPIClient.Tracker().Update(federationDomainGVR, federationDomain1, federationDomain1.Namespace))
|
r.NoError(pinnipedAPIClient.Tracker().Update(federationDomainGVR, federationDomain1, federationDomain1.Namespace))
|
||||||
r.NoError(pinnipedInformerClient.Tracker().Update(federationDomainGVR, federationDomain1, federationDomain1.Namespace))
|
r.NoError(pinnipedInformerClient.Tracker().Update(federationDomainGVR, federationDomain1, federationDomain1.Namespace))
|
||||||
@ -267,21 +398,10 @@ func TestSync(t *testing.T) {
|
|||||||
err := controllerlib.TestSync(t, subject, *syncContext)
|
err := controllerlib.TestSync(t, subject, *syncContext)
|
||||||
r.NoError(err)
|
r.NoError(err)
|
||||||
|
|
||||||
federationDomain2.Status.Status = v1alpha1.SuccessFederationDomainStatusCondition
|
federationDomain2.Status.Phase = v1alpha1.FederationDomainPhaseReady
|
||||||
federationDomain2.Status.Message = "Provider successfully created"
|
federationDomain2.Status.Conditions = allHappyConditions(federationDomain2.Spec.Issuer, frozenMetav1Now, 123)
|
||||||
federationDomain2.Status.LastUpdateTime = timePtr(metav1.NewTime(frozenNow))
|
|
||||||
|
|
||||||
expectedActions := []coretesting.Action{
|
expectedActions := []coretesting.Action{
|
||||||
coretesting.NewGetAction(
|
|
||||||
federationDomainGVR,
|
|
||||||
federationDomain1.Namespace,
|
|
||||||
federationDomain1.Name,
|
|
||||||
),
|
|
||||||
coretesting.NewGetAction(
|
|
||||||
federationDomainGVR,
|
|
||||||
federationDomain2.Namespace,
|
|
||||||
federationDomain2.Name,
|
|
||||||
),
|
|
||||||
coretesting.NewUpdateSubresourceAction(
|
coretesting.NewUpdateSubresourceAction(
|
||||||
federationDomainGVR,
|
federationDomainGVR,
|
||||||
"status",
|
"status",
|
||||||
@ -314,7 +434,7 @@ func TestSync(t *testing.T) {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
when("updating only one FederationDomain fails for a reason other than conflict", func() {
|
when("updating only one FederationDomain fails", func() {
|
||||||
it.Before(func() {
|
it.Before(func() {
|
||||||
once := sync.Once{}
|
once := sync.Once{}
|
||||||
pinnipedAPIClient.PrependReactor(
|
pinnipedAPIClient.PrependReactor(
|
||||||
@ -354,31 +474,19 @@ func TestSync(t *testing.T) {
|
|||||||
err := controllerlib.TestSync(t, subject, *syncContext)
|
err := controllerlib.TestSync(t, subject, *syncContext)
|
||||||
r.EqualError(err, "could not update status: some update error")
|
r.EqualError(err, "could not update status: some update error")
|
||||||
|
|
||||||
federationDomain1.Status.Status = v1alpha1.SuccessFederationDomainStatusCondition
|
federationDomain1.Status.Phase = v1alpha1.FederationDomainPhaseReady
|
||||||
federationDomain1.Status.Message = "Provider successfully created"
|
federationDomain1.Status.Conditions = allHappyConditions(federationDomain1.Spec.Issuer, frozenMetav1Now, 123)
|
||||||
federationDomain1.Status.LastUpdateTime = timePtr(metav1.NewTime(frozenNow))
|
|
||||||
|
|
||||||
federationDomain2.Status.Status = v1alpha1.SuccessFederationDomainStatusCondition
|
federationDomain2.Status.Phase = v1alpha1.FederationDomainPhaseReady
|
||||||
federationDomain2.Status.Message = "Provider successfully created"
|
federationDomain2.Status.Conditions = allHappyConditions(federationDomain2.Spec.Issuer, frozenMetav1Now, 123)
|
||||||
federationDomain2.Status.LastUpdateTime = timePtr(metav1.NewTime(frozenNow))
|
|
||||||
|
|
||||||
expectedActions := []coretesting.Action{
|
expectedActions := []coretesting.Action{
|
||||||
coretesting.NewGetAction(
|
|
||||||
federationDomainGVR,
|
|
||||||
federationDomain1.Namespace,
|
|
||||||
federationDomain1.Name,
|
|
||||||
),
|
|
||||||
coretesting.NewUpdateSubresourceAction(
|
coretesting.NewUpdateSubresourceAction(
|
||||||
federationDomainGVR,
|
federationDomainGVR,
|
||||||
"status",
|
"status",
|
||||||
federationDomain1.Namespace,
|
federationDomain1.Namespace,
|
||||||
federationDomain1,
|
federationDomain1,
|
||||||
),
|
),
|
||||||
coretesting.NewGetAction(
|
|
||||||
federationDomainGVR,
|
|
||||||
federationDomain2.Namespace,
|
|
||||||
federationDomain2.Name,
|
|
||||||
),
|
|
||||||
coretesting.NewUpdateSubresourceAction(
|
coretesting.NewUpdateSubresourceAction(
|
||||||
federationDomainGVR,
|
federationDomainGVR,
|
||||||
"status",
|
"status",
|
||||||
@ -398,67 +506,14 @@ func TestSync(t *testing.T) {
|
|||||||
|
|
||||||
it.Before(func() {
|
it.Before(func() {
|
||||||
federationDomain = &v1alpha1.FederationDomain{
|
federationDomain = &v1alpha1.FederationDomain{
|
||||||
ObjectMeta: metav1.ObjectMeta{Name: "config", Namespace: namespace},
|
ObjectMeta: metav1.ObjectMeta{Name: "config", Namespace: namespace, Generation: 123},
|
||||||
Spec: v1alpha1.FederationDomainSpec{Issuer: "https://issuer.com"},
|
Spec: v1alpha1.FederationDomainSpec{Issuer: "https://issuer.com"},
|
||||||
}
|
}
|
||||||
r.NoError(pinnipedAPIClient.Tracker().Add(federationDomain))
|
r.NoError(pinnipedAPIClient.Tracker().Add(federationDomain))
|
||||||
r.NoError(pinnipedInformerClient.Tracker().Add(federationDomain))
|
r.NoError(pinnipedInformerClient.Tracker().Add(federationDomain))
|
||||||
})
|
})
|
||||||
|
|
||||||
when("there is a conflict while updating an FederationDomain", func() {
|
when("updating the FederationDomain fails", func() {
|
||||||
it.Before(func() {
|
|
||||||
once := sync.Once{}
|
|
||||||
pinnipedAPIClient.PrependReactor(
|
|
||||||
"update",
|
|
||||||
"federationdomains",
|
|
||||||
func(_ coretesting.Action) (bool, runtime.Object, error) {
|
|
||||||
var err error
|
|
||||||
once.Do(func() {
|
|
||||||
err = k8serrors.NewConflict(schema.GroupResource{}, "", nil)
|
|
||||||
})
|
|
||||||
return true, nil, err
|
|
||||||
},
|
|
||||||
)
|
|
||||||
})
|
|
||||||
|
|
||||||
it("retries updating the FederationDomain", func() {
|
|
||||||
startInformersAndController()
|
|
||||||
err := controllerlib.TestSync(t, subject, *syncContext)
|
|
||||||
r.NoError(err)
|
|
||||||
|
|
||||||
federationDomain.Status.Status = v1alpha1.SuccessFederationDomainStatusCondition
|
|
||||||
federationDomain.Status.Message = "Provider successfully created"
|
|
||||||
federationDomain.Status.LastUpdateTime = timePtr(metav1.NewTime(frozenNow))
|
|
||||||
|
|
||||||
expectedActions := []coretesting.Action{
|
|
||||||
coretesting.NewGetAction(
|
|
||||||
federationDomainGVR,
|
|
||||||
federationDomain.Namespace,
|
|
||||||
federationDomain.Name,
|
|
||||||
),
|
|
||||||
coretesting.NewUpdateSubresourceAction(
|
|
||||||
federationDomainGVR,
|
|
||||||
"status",
|
|
||||||
federationDomain.Namespace,
|
|
||||||
federationDomain,
|
|
||||||
),
|
|
||||||
coretesting.NewGetAction(
|
|
||||||
federationDomainGVR,
|
|
||||||
federationDomain.Namespace,
|
|
||||||
federationDomain.Name,
|
|
||||||
),
|
|
||||||
coretesting.NewUpdateSubresourceAction(
|
|
||||||
federationDomainGVR,
|
|
||||||
"status",
|
|
||||||
federationDomain.Namespace,
|
|
||||||
federationDomain,
|
|
||||||
),
|
|
||||||
}
|
|
||||||
r.Equal(expectedActions, pinnipedAPIClient.Actions())
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
when("updating the FederationDomain fails for a reason other than conflict", func() {
|
|
||||||
it.Before(func() {
|
it.Before(func() {
|
||||||
pinnipedAPIClient.PrependReactor(
|
pinnipedAPIClient.PrependReactor(
|
||||||
"update",
|
"update",
|
||||||
@ -474,16 +529,10 @@ func TestSync(t *testing.T) {
|
|||||||
err := controllerlib.TestSync(t, subject, *syncContext)
|
err := controllerlib.TestSync(t, subject, *syncContext)
|
||||||
r.EqualError(err, "could not update status: some update error")
|
r.EqualError(err, "could not update status: some update error")
|
||||||
|
|
||||||
federationDomain.Status.Status = v1alpha1.SuccessFederationDomainStatusCondition
|
federationDomain.Status.Phase = v1alpha1.FederationDomainPhaseReady
|
||||||
federationDomain.Status.Message = "Provider successfully created"
|
federationDomain.Status.Conditions = allHappyConditions(federationDomain.Spec.Issuer, frozenMetav1Now, 123)
|
||||||
federationDomain.Status.LastUpdateTime = timePtr(metav1.NewTime(frozenNow))
|
|
||||||
|
|
||||||
expectedActions := []coretesting.Action{
|
expectedActions := []coretesting.Action{
|
||||||
coretesting.NewGetAction(
|
|
||||||
federationDomainGVR,
|
|
||||||
federationDomain.Namespace,
|
|
||||||
federationDomain.Name,
|
|
||||||
),
|
|
||||||
coretesting.NewUpdateSubresourceAction(
|
coretesting.NewUpdateSubresourceAction(
|
||||||
federationDomainGVR,
|
federationDomainGVR,
|
||||||
"status",
|
"status",
|
||||||
@ -491,38 +540,7 @@ func TestSync(t *testing.T) {
|
|||||||
federationDomain,
|
federationDomain,
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
r.Equal(expectedActions, pinnipedAPIClient.Actions())
|
r.ElementsMatch(expectedActions, pinnipedAPIClient.Actions())
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
when("there is an error when getting the FederationDomain", func() {
|
|
||||||
it.Before(func() {
|
|
||||||
pinnipedAPIClient.PrependReactor(
|
|
||||||
"get",
|
|
||||||
"federationdomains",
|
|
||||||
func(_ coretesting.Action) (bool, runtime.Object, error) {
|
|
||||||
return true, nil, errors.New("some get error")
|
|
||||||
},
|
|
||||||
)
|
|
||||||
})
|
|
||||||
|
|
||||||
it("returns the get error", func() {
|
|
||||||
startInformersAndController()
|
|
||||||
err := controllerlib.TestSync(t, subject, *syncContext)
|
|
||||||
r.EqualError(err, "could not update status: get failed: some get error")
|
|
||||||
|
|
||||||
federationDomain.Status.Status = v1alpha1.SuccessFederationDomainStatusCondition
|
|
||||||
federationDomain.Status.Message = "Provider successfully created"
|
|
||||||
federationDomain.Status.LastUpdateTime = timePtr(metav1.NewTime(frozenNow))
|
|
||||||
|
|
||||||
expectedActions := []coretesting.Action{
|
|
||||||
coretesting.NewGetAction(
|
|
||||||
federationDomainGVR,
|
|
||||||
federationDomain.Namespace,
|
|
||||||
federationDomain.Name,
|
|
||||||
),
|
|
||||||
}
|
|
||||||
r.Equal(expectedActions, pinnipedAPIClient.Actions())
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@ -535,14 +553,14 @@ func TestSync(t *testing.T) {
|
|||||||
|
|
||||||
it.Before(func() {
|
it.Before(func() {
|
||||||
validFederationDomain = &v1alpha1.FederationDomain{
|
validFederationDomain = &v1alpha1.FederationDomain{
|
||||||
ObjectMeta: metav1.ObjectMeta{Name: "valid-config", Namespace: namespace},
|
ObjectMeta: metav1.ObjectMeta{Name: "valid-config", Namespace: namespace, Generation: 123},
|
||||||
Spec: v1alpha1.FederationDomainSpec{Issuer: "https://valid-issuer.com"},
|
Spec: v1alpha1.FederationDomainSpec{Issuer: "https://valid-issuer.com"},
|
||||||
}
|
}
|
||||||
r.NoError(pinnipedAPIClient.Tracker().Add(validFederationDomain))
|
r.NoError(pinnipedAPIClient.Tracker().Add(validFederationDomain))
|
||||||
r.NoError(pinnipedInformerClient.Tracker().Add(validFederationDomain))
|
r.NoError(pinnipedInformerClient.Tracker().Add(validFederationDomain))
|
||||||
|
|
||||||
invalidFederationDomain = &v1alpha1.FederationDomain{
|
invalidFederationDomain = &v1alpha1.FederationDomain{
|
||||||
ObjectMeta: metav1.ObjectMeta{Name: "invalid-config", Namespace: namespace},
|
ObjectMeta: metav1.ObjectMeta{Name: "invalid-config", Namespace: namespace, Generation: 123},
|
||||||
Spec: v1alpha1.FederationDomainSpec{Issuer: "https://invalid-issuer.com?some=query"},
|
Spec: v1alpha1.FederationDomainSpec{Issuer: "https://invalid-issuer.com?some=query"},
|
||||||
}
|
}
|
||||||
r.NoError(pinnipedAPIClient.Tracker().Add(invalidFederationDomain))
|
r.NoError(pinnipedAPIClient.Tracker().Add(invalidFederationDomain))
|
||||||
@ -566,36 +584,29 @@ func TestSync(t *testing.T) {
|
|||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
it("updates the status to success/invalid in the FederationDomains", func() {
|
it("updates the status in each FederationDomain", func() {
|
||||||
startInformersAndController()
|
startInformersAndController()
|
||||||
err := controllerlib.TestSync(t, subject, *syncContext)
|
err := controllerlib.TestSync(t, subject, *syncContext)
|
||||||
r.NoError(err)
|
r.NoError(err)
|
||||||
|
|
||||||
validFederationDomain.Status.Status = v1alpha1.SuccessFederationDomainStatusCondition
|
validFederationDomain.Status.Phase = v1alpha1.FederationDomainPhaseReady
|
||||||
validFederationDomain.Status.Message = "Provider successfully created"
|
validFederationDomain.Status.Conditions = allHappyConditions(validFederationDomain.Spec.Issuer, frozenMetav1Now, 123)
|
||||||
validFederationDomain.Status.LastUpdateTime = timePtr(metav1.NewTime(frozenNow))
|
|
||||||
|
|
||||||
invalidFederationDomain.Status.Status = v1alpha1.InvalidFederationDomainStatusCondition
|
invalidFederationDomain.Status.Phase = v1alpha1.FederationDomainPhaseError
|
||||||
invalidFederationDomain.Status.Message = "Invalid: issuer must not have query"
|
invalidFederationDomain.Status.Conditions = []v1alpha1.Condition{
|
||||||
invalidFederationDomain.Status.LastUpdateTime = timePtr(metav1.NewTime(frozenNow))
|
happyIssuerIsUniqueCondition(frozenMetav1Now, 123),
|
||||||
|
sadIssuerURLValidConditionCannotHaveQuery(frozenMetav1Now, 123),
|
||||||
|
happyOneTLSSecretPerIssuerHostnameCondition(frozenMetav1Now, 123),
|
||||||
|
sadReadyCondition(frozenMetav1Now, 123),
|
||||||
|
}
|
||||||
|
|
||||||
expectedActions := []coretesting.Action{
|
expectedActions := []coretesting.Action{
|
||||||
coretesting.NewGetAction(
|
|
||||||
federationDomainGVR,
|
|
||||||
invalidFederationDomain.Namespace,
|
|
||||||
invalidFederationDomain.Name,
|
|
||||||
),
|
|
||||||
coretesting.NewUpdateSubresourceAction(
|
coretesting.NewUpdateSubresourceAction(
|
||||||
federationDomainGVR,
|
federationDomainGVR,
|
||||||
"status",
|
"status",
|
||||||
invalidFederationDomain.Namespace,
|
invalidFederationDomain.Namespace,
|
||||||
invalidFederationDomain,
|
invalidFederationDomain,
|
||||||
),
|
),
|
||||||
coretesting.NewGetAction(
|
|
||||||
federationDomainGVR,
|
|
||||||
validFederationDomain.Namespace,
|
|
||||||
validFederationDomain.Name,
|
|
||||||
),
|
|
||||||
coretesting.NewUpdateSubresourceAction(
|
coretesting.NewUpdateSubresourceAction(
|
||||||
federationDomainGVR,
|
federationDomainGVR,
|
||||||
"status",
|
"status",
|
||||||
@ -606,7 +617,7 @@ func TestSync(t *testing.T) {
|
|||||||
r.ElementsMatch(expectedActions, pinnipedAPIClient.Actions())
|
r.ElementsMatch(expectedActions, pinnipedAPIClient.Actions())
|
||||||
})
|
})
|
||||||
|
|
||||||
when("updating only the invalid FederationDomain fails for a reason other than conflict", func() {
|
when("updating only the invalid FederationDomain fails", func() {
|
||||||
it.Before(func() {
|
it.Before(func() {
|
||||||
pinnipedAPIClient.PrependReactor(
|
pinnipedAPIClient.PrependReactor(
|
||||||
"update",
|
"update",
|
||||||
@ -645,31 +656,24 @@ func TestSync(t *testing.T) {
|
|||||||
err := controllerlib.TestSync(t, subject, *syncContext)
|
err := controllerlib.TestSync(t, subject, *syncContext)
|
||||||
r.EqualError(err, "could not update status: some update error")
|
r.EqualError(err, "could not update status: some update error")
|
||||||
|
|
||||||
validFederationDomain.Status.Status = v1alpha1.SuccessFederationDomainStatusCondition
|
validFederationDomain.Status.Phase = v1alpha1.FederationDomainPhaseReady
|
||||||
validFederationDomain.Status.Message = "Provider successfully created"
|
validFederationDomain.Status.Conditions = allHappyConditions(validFederationDomain.Spec.Issuer, frozenMetav1Now, 123)
|
||||||
validFederationDomain.Status.LastUpdateTime = timePtr(metav1.NewTime(frozenNow))
|
|
||||||
|
|
||||||
invalidFederationDomain.Status.Status = v1alpha1.InvalidFederationDomainStatusCondition
|
invalidFederationDomain.Status.Phase = v1alpha1.FederationDomainPhaseError
|
||||||
invalidFederationDomain.Status.Message = "Invalid: issuer must not have query"
|
invalidFederationDomain.Status.Conditions = []v1alpha1.Condition{
|
||||||
invalidFederationDomain.Status.LastUpdateTime = timePtr(metav1.NewTime(frozenNow))
|
happyIssuerIsUniqueCondition(frozenMetav1Now, 123),
|
||||||
|
sadIssuerURLValidConditionCannotHaveQuery(frozenMetav1Now, 123),
|
||||||
|
happyOneTLSSecretPerIssuerHostnameCondition(frozenMetav1Now, 123),
|
||||||
|
sadReadyCondition(frozenMetav1Now, 123),
|
||||||
|
}
|
||||||
|
|
||||||
expectedActions := []coretesting.Action{
|
expectedActions := []coretesting.Action{
|
||||||
coretesting.NewGetAction(
|
|
||||||
federationDomainGVR,
|
|
||||||
invalidFederationDomain.Namespace,
|
|
||||||
invalidFederationDomain.Name,
|
|
||||||
),
|
|
||||||
coretesting.NewUpdateSubresourceAction(
|
coretesting.NewUpdateSubresourceAction(
|
||||||
federationDomainGVR,
|
federationDomainGVR,
|
||||||
"status",
|
"status",
|
||||||
invalidFederationDomain.Namespace,
|
invalidFederationDomain.Namespace,
|
||||||
invalidFederationDomain,
|
invalidFederationDomain,
|
||||||
),
|
),
|
||||||
coretesting.NewGetAction(
|
|
||||||
federationDomainGVR,
|
|
||||||
validFederationDomain.Namespace,
|
|
||||||
validFederationDomain.Name,
|
|
||||||
),
|
|
||||||
coretesting.NewUpdateSubresourceAction(
|
coretesting.NewUpdateSubresourceAction(
|
||||||
federationDomainGVR,
|
federationDomainGVR,
|
||||||
"status",
|
"status",
|
||||||
@ -693,20 +697,20 @@ func TestSync(t *testing.T) {
|
|||||||
// Hostnames are case-insensitive, so consider them to be duplicates if they only differ by case.
|
// Hostnames are case-insensitive, so consider them to be duplicates if they only differ by case.
|
||||||
// Paths are case-sensitive, so having a path that differs only by case makes a new issuer.
|
// Paths are case-sensitive, so having a path that differs only by case makes a new issuer.
|
||||||
federationDomainDuplicate1 = &v1alpha1.FederationDomain{
|
federationDomainDuplicate1 = &v1alpha1.FederationDomain{
|
||||||
ObjectMeta: metav1.ObjectMeta{Name: "duplicate1", Namespace: namespace},
|
ObjectMeta: metav1.ObjectMeta{Name: "duplicate1", Namespace: namespace, Generation: 123},
|
||||||
Spec: v1alpha1.FederationDomainSpec{Issuer: "https://iSSueR-duPlicAte.cOm/a"},
|
Spec: v1alpha1.FederationDomainSpec{Issuer: "https://iSSueR-duPlicAte.cOm/a"},
|
||||||
}
|
}
|
||||||
r.NoError(pinnipedAPIClient.Tracker().Add(federationDomainDuplicate1))
|
r.NoError(pinnipedAPIClient.Tracker().Add(federationDomainDuplicate1))
|
||||||
r.NoError(pinnipedInformerClient.Tracker().Add(federationDomainDuplicate1))
|
r.NoError(pinnipedInformerClient.Tracker().Add(federationDomainDuplicate1))
|
||||||
federationDomainDuplicate2 = &v1alpha1.FederationDomain{
|
federationDomainDuplicate2 = &v1alpha1.FederationDomain{
|
||||||
ObjectMeta: metav1.ObjectMeta{Name: "duplicate2", Namespace: namespace},
|
ObjectMeta: metav1.ObjectMeta{Name: "duplicate2", Namespace: namespace, Generation: 123},
|
||||||
Spec: v1alpha1.FederationDomainSpec{Issuer: "https://issuer-duplicate.com/a"},
|
Spec: v1alpha1.FederationDomainSpec{Issuer: "https://issuer-duplicate.com/a"},
|
||||||
}
|
}
|
||||||
r.NoError(pinnipedAPIClient.Tracker().Add(federationDomainDuplicate2))
|
r.NoError(pinnipedAPIClient.Tracker().Add(federationDomainDuplicate2))
|
||||||
r.NoError(pinnipedInformerClient.Tracker().Add(federationDomainDuplicate2))
|
r.NoError(pinnipedInformerClient.Tracker().Add(federationDomainDuplicate2))
|
||||||
|
|
||||||
federationDomain = &v1alpha1.FederationDomain{
|
federationDomain = &v1alpha1.FederationDomain{
|
||||||
ObjectMeta: metav1.ObjectMeta{Name: "not-duplicate", Namespace: namespace},
|
ObjectMeta: metav1.ObjectMeta{Name: "not-duplicate", Namespace: namespace, Generation: 123},
|
||||||
Spec: v1alpha1.FederationDomainSpec{Issuer: "https://issuer-duplicate.com/A"}, // different path
|
Spec: v1alpha1.FederationDomainSpec{Issuer: "https://issuer-duplicate.com/A"}, // different path
|
||||||
}
|
}
|
||||||
r.NoError(pinnipedAPIClient.Tracker().Add(federationDomain))
|
r.NoError(pinnipedAPIClient.Tracker().Add(federationDomain))
|
||||||
@ -735,46 +739,38 @@ func TestSync(t *testing.T) {
|
|||||||
err := controllerlib.TestSync(t, subject, *syncContext)
|
err := controllerlib.TestSync(t, subject, *syncContext)
|
||||||
r.NoError(err)
|
r.NoError(err)
|
||||||
|
|
||||||
federationDomain.Status.Status = v1alpha1.SuccessFederationDomainStatusCondition
|
federationDomain.Status.Phase = v1alpha1.FederationDomainPhaseReady
|
||||||
federationDomain.Status.Message = "Provider successfully created"
|
federationDomain.Status.Conditions = allHappyConditions(federationDomain.Spec.Issuer, frozenMetav1Now, 123)
|
||||||
federationDomain.Status.LastUpdateTime = timePtr(metav1.NewTime(frozenNow))
|
|
||||||
|
|
||||||
federationDomainDuplicate1.Status.Status = v1alpha1.DuplicateFederationDomainStatusCondition
|
federationDomainDuplicate1.Status.Phase = v1alpha1.FederationDomainPhaseError
|
||||||
federationDomainDuplicate1.Status.Message = "Duplicate issuer: https://iSSueR-duPlicAte.cOm/a"
|
federationDomainDuplicate1.Status.Conditions = []v1alpha1.Condition{
|
||||||
federationDomainDuplicate1.Status.LastUpdateTime = timePtr(metav1.NewTime(frozenNow))
|
sadIssuerIsUniqueCondition(frozenMetav1Now, 123),
|
||||||
|
happyIssuerURLValidCondition(frozenMetav1Now, 123),
|
||||||
|
happyOneTLSSecretPerIssuerHostnameCondition(frozenMetav1Now, 123),
|
||||||
|
sadReadyCondition(frozenMetav1Now, 123),
|
||||||
|
}
|
||||||
|
|
||||||
federationDomainDuplicate2.Status.Status = v1alpha1.DuplicateFederationDomainStatusCondition
|
federationDomainDuplicate2.Status.Phase = v1alpha1.FederationDomainPhaseError
|
||||||
federationDomainDuplicate2.Status.Message = "Duplicate issuer: https://issuer-duplicate.com/a"
|
federationDomainDuplicate2.Status.Conditions = []v1alpha1.Condition{
|
||||||
federationDomainDuplicate2.Status.LastUpdateTime = timePtr(metav1.NewTime(frozenNow))
|
sadIssuerIsUniqueCondition(frozenMetav1Now, 123),
|
||||||
|
happyIssuerURLValidCondition(frozenMetav1Now, 123),
|
||||||
|
happyOneTLSSecretPerIssuerHostnameCondition(frozenMetav1Now, 123),
|
||||||
|
sadReadyCondition(frozenMetav1Now, 123),
|
||||||
|
}
|
||||||
|
|
||||||
expectedActions := []coretesting.Action{
|
expectedActions := []coretesting.Action{
|
||||||
coretesting.NewGetAction(
|
|
||||||
federationDomainGVR,
|
|
||||||
federationDomainDuplicate1.Namespace,
|
|
||||||
federationDomainDuplicate1.Name,
|
|
||||||
),
|
|
||||||
coretesting.NewUpdateSubresourceAction(
|
coretesting.NewUpdateSubresourceAction(
|
||||||
federationDomainGVR,
|
federationDomainGVR,
|
||||||
"status",
|
"status",
|
||||||
federationDomainDuplicate1.Namespace,
|
federationDomainDuplicate1.Namespace,
|
||||||
federationDomainDuplicate1,
|
federationDomainDuplicate1,
|
||||||
),
|
),
|
||||||
coretesting.NewGetAction(
|
|
||||||
federationDomainGVR,
|
|
||||||
federationDomainDuplicate2.Namespace,
|
|
||||||
federationDomainDuplicate2.Name,
|
|
||||||
),
|
|
||||||
coretesting.NewUpdateSubresourceAction(
|
coretesting.NewUpdateSubresourceAction(
|
||||||
federationDomainGVR,
|
federationDomainGVR,
|
||||||
"status",
|
"status",
|
||||||
federationDomainDuplicate2.Namespace,
|
federationDomainDuplicate2.Namespace,
|
||||||
federationDomainDuplicate2,
|
federationDomainDuplicate2,
|
||||||
),
|
),
|
||||||
coretesting.NewGetAction(
|
|
||||||
federationDomainGVR,
|
|
||||||
federationDomain.Namespace,
|
|
||||||
federationDomain.Name,
|
|
||||||
),
|
|
||||||
coretesting.NewUpdateSubresourceAction(
|
coretesting.NewUpdateSubresourceAction(
|
||||||
federationDomainGVR,
|
federationDomainGVR,
|
||||||
"status",
|
"status",
|
||||||
@ -784,50 +780,6 @@ func TestSync(t *testing.T) {
|
|||||||
}
|
}
|
||||||
r.ElementsMatch(expectedActions, pinnipedAPIClient.Actions())
|
r.ElementsMatch(expectedActions, pinnipedAPIClient.Actions())
|
||||||
})
|
})
|
||||||
|
|
||||||
when("we cannot talk to the API", func() {
|
|
||||||
var count int
|
|
||||||
it.Before(func() {
|
|
||||||
pinnipedAPIClient.PrependReactor(
|
|
||||||
"get",
|
|
||||||
"federationdomains",
|
|
||||||
func(_ coretesting.Action) (bool, runtime.Object, error) {
|
|
||||||
count++
|
|
||||||
return true, nil, fmt.Errorf("some get error %d", count)
|
|
||||||
},
|
|
||||||
)
|
|
||||||
})
|
|
||||||
|
|
||||||
it("returns the get errors", func() {
|
|
||||||
expectedError := here.Doc(`[could not update status: get failed: some get error 1, could not update status: get failed: some get error 2, could not update status: get failed: some get error 3]`)
|
|
||||||
startInformersAndController()
|
|
||||||
err := controllerlib.TestSync(t, subject, *syncContext)
|
|
||||||
r.EqualError(err, expectedError)
|
|
||||||
|
|
||||||
federationDomain.Status.Status = v1alpha1.SuccessFederationDomainStatusCondition
|
|
||||||
federationDomain.Status.Message = "Provider successfully created"
|
|
||||||
federationDomain.Status.LastUpdateTime = timePtr(metav1.NewTime(frozenNow))
|
|
||||||
|
|
||||||
expectedActions := []coretesting.Action{
|
|
||||||
coretesting.NewGetAction(
|
|
||||||
federationDomainGVR,
|
|
||||||
federationDomainDuplicate1.Namespace,
|
|
||||||
federationDomainDuplicate1.Name,
|
|
||||||
),
|
|
||||||
coretesting.NewGetAction(
|
|
||||||
federationDomainGVR,
|
|
||||||
federationDomainDuplicate2.Namespace,
|
|
||||||
federationDomainDuplicate2.Name,
|
|
||||||
),
|
|
||||||
coretesting.NewGetAction(
|
|
||||||
federationDomainGVR,
|
|
||||||
federationDomain.Namespace,
|
|
||||||
federationDomain.Name,
|
|
||||||
),
|
|
||||||
}
|
|
||||||
r.ElementsMatch(expectedActions, pinnipedAPIClient.Actions())
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
|
|
||||||
when("there are FederationDomains with the same issuer DNS hostname using different secretNames", func() {
|
when("there are FederationDomains with the same issuer DNS hostname using different secretNames", func() {
|
||||||
@ -840,7 +792,7 @@ func TestSync(t *testing.T) {
|
|||||||
|
|
||||||
it.Before(func() {
|
it.Before(func() {
|
||||||
federationDomainSameIssuerAddress1 = &v1alpha1.FederationDomain{
|
federationDomainSameIssuerAddress1 = &v1alpha1.FederationDomain{
|
||||||
ObjectMeta: metav1.ObjectMeta{Name: "fd1", Namespace: namespace},
|
ObjectMeta: metav1.ObjectMeta{Name: "fd1", Namespace: namespace, Generation: 123},
|
||||||
Spec: v1alpha1.FederationDomainSpec{
|
Spec: v1alpha1.FederationDomainSpec{
|
||||||
Issuer: "https://iSSueR-duPlicAte-adDress.cOm/path1",
|
Issuer: "https://iSSueR-duPlicAte-adDress.cOm/path1",
|
||||||
TLS: &v1alpha1.FederationDomainTLSSpec{SecretName: "secret1"},
|
TLS: &v1alpha1.FederationDomainTLSSpec{SecretName: "secret1"},
|
||||||
@ -849,7 +801,7 @@ func TestSync(t *testing.T) {
|
|||||||
r.NoError(pinnipedAPIClient.Tracker().Add(federationDomainSameIssuerAddress1))
|
r.NoError(pinnipedAPIClient.Tracker().Add(federationDomainSameIssuerAddress1))
|
||||||
r.NoError(pinnipedInformerClient.Tracker().Add(federationDomainSameIssuerAddress1))
|
r.NoError(pinnipedInformerClient.Tracker().Add(federationDomainSameIssuerAddress1))
|
||||||
federationDomainSameIssuerAddress2 = &v1alpha1.FederationDomain{
|
federationDomainSameIssuerAddress2 = &v1alpha1.FederationDomain{
|
||||||
ObjectMeta: metav1.ObjectMeta{Name: "fd2", Namespace: namespace},
|
ObjectMeta: metav1.ObjectMeta{Name: "fd2", Namespace: namespace, Generation: 123},
|
||||||
Spec: v1alpha1.FederationDomainSpec{
|
Spec: v1alpha1.FederationDomainSpec{
|
||||||
// Validation treats these as the same DNS hostname even though they have different port numbers,
|
// Validation treats these as the same DNS hostname even though they have different port numbers,
|
||||||
// because SNI information on the incoming requests is not going to include port numbers.
|
// because SNI information on the incoming requests is not going to include port numbers.
|
||||||
@ -861,7 +813,7 @@ func TestSync(t *testing.T) {
|
|||||||
r.NoError(pinnipedInformerClient.Tracker().Add(federationDomainSameIssuerAddress2))
|
r.NoError(pinnipedInformerClient.Tracker().Add(federationDomainSameIssuerAddress2))
|
||||||
|
|
||||||
federationDomainDifferentIssuerAddress = &v1alpha1.FederationDomain{
|
federationDomainDifferentIssuerAddress = &v1alpha1.FederationDomain{
|
||||||
ObjectMeta: metav1.ObjectMeta{Name: "differentIssuerAddressFederationDomain", Namespace: namespace},
|
ObjectMeta: metav1.ObjectMeta{Name: "differentIssuerAddressFederationDomain", Namespace: namespace, Generation: 123},
|
||||||
Spec: v1alpha1.FederationDomainSpec{
|
Spec: v1alpha1.FederationDomainSpec{
|
||||||
Issuer: "https://issuer-not-duplicate.com",
|
Issuer: "https://issuer-not-duplicate.com",
|
||||||
TLS: &v1alpha1.FederationDomainTLSSpec{SecretName: "secret1"},
|
TLS: &v1alpha1.FederationDomainTLSSpec{SecretName: "secret1"},
|
||||||
@ -876,7 +828,7 @@ func TestSync(t *testing.T) {
|
|||||||
_, err := url.Parse(invalidIssuerURL) //nolint:staticcheck // Yes, this URL is intentionally invalid.
|
_, err := url.Parse(invalidIssuerURL) //nolint:staticcheck // Yes, this URL is intentionally invalid.
|
||||||
r.Error(err)
|
r.Error(err)
|
||||||
federationDomainWithInvalidIssuerURL = &v1alpha1.FederationDomain{
|
federationDomainWithInvalidIssuerURL = &v1alpha1.FederationDomain{
|
||||||
ObjectMeta: metav1.ObjectMeta{Name: "invalidIssuerURLFederationDomain", Namespace: namespace},
|
ObjectMeta: metav1.ObjectMeta{Name: "invalidIssuerURLFederationDomain", Namespace: namespace, Generation: 123},
|
||||||
Spec: v1alpha1.FederationDomainSpec{
|
Spec: v1alpha1.FederationDomainSpec{
|
||||||
Issuer: invalidIssuerURL,
|
Issuer: invalidIssuerURL,
|
||||||
TLS: &v1alpha1.FederationDomainTLSSpec{SecretName: "secret1"},
|
TLS: &v1alpha1.FederationDomainTLSSpec{SecretName: "secret1"},
|
||||||
@ -908,27 +860,39 @@ func TestSync(t *testing.T) {
|
|||||||
err := controllerlib.TestSync(t, subject, *syncContext)
|
err := controllerlib.TestSync(t, subject, *syncContext)
|
||||||
r.NoError(err)
|
r.NoError(err)
|
||||||
|
|
||||||
federationDomainDifferentIssuerAddress.Status.Status = v1alpha1.SuccessFederationDomainStatusCondition
|
federationDomainDifferentIssuerAddress.Status.Phase = v1alpha1.FederationDomainPhaseReady
|
||||||
federationDomainDifferentIssuerAddress.Status.Message = "Provider successfully created"
|
federationDomainDifferentIssuerAddress.Status.Conditions = allHappyConditions(federationDomainDifferentIssuerAddress.Spec.Issuer, frozenMetav1Now, 123)
|
||||||
federationDomainDifferentIssuerAddress.Status.LastUpdateTime = timePtr(metav1.NewTime(frozenNow))
|
|
||||||
|
|
||||||
federationDomainSameIssuerAddress1.Status.Status = v1alpha1.SameIssuerHostMustUseSameSecretFederationDomainStatusCondition
|
federationDomainSameIssuerAddress1.Status.Phase = v1alpha1.FederationDomainPhaseError
|
||||||
federationDomainSameIssuerAddress1.Status.Message = "Issuers with the same DNS hostname (address not including port) must use the same secretName: issuer-duplicate-address.com"
|
federationDomainSameIssuerAddress1.Status.Conditions = []v1alpha1.Condition{
|
||||||
federationDomainSameIssuerAddress1.Status.LastUpdateTime = timePtr(metav1.NewTime(frozenNow))
|
happyIssuerIsUniqueCondition(frozenMetav1Now, 123),
|
||||||
|
happyIssuerURLValidCondition(frozenMetav1Now, 123),
|
||||||
|
sadOneTLSSecretPerIssuerHostnameCondition(frozenMetav1Now, 123),
|
||||||
|
sadReadyCondition(frozenMetav1Now, 123),
|
||||||
|
}
|
||||||
|
|
||||||
federationDomainSameIssuerAddress2.Status.Status = v1alpha1.SameIssuerHostMustUseSameSecretFederationDomainStatusCondition
|
federationDomainSameIssuerAddress2.Status.Phase = v1alpha1.FederationDomainPhaseError
|
||||||
federationDomainSameIssuerAddress2.Status.Message = "Issuers with the same DNS hostname (address not including port) must use the same secretName: issuer-duplicate-address.com"
|
federationDomainSameIssuerAddress2.Status.Conditions = []v1alpha1.Condition{
|
||||||
federationDomainSameIssuerAddress2.Status.LastUpdateTime = timePtr(metav1.NewTime(frozenNow))
|
happyIssuerIsUniqueCondition(frozenMetav1Now, 123),
|
||||||
|
happyIssuerURLValidCondition(frozenMetav1Now, 123),
|
||||||
|
sadOneTLSSecretPerIssuerHostnameCondition(frozenMetav1Now, 123),
|
||||||
|
sadReadyCondition(frozenMetav1Now, 123),
|
||||||
|
}
|
||||||
|
|
||||||
federationDomainWithInvalidIssuerURL.Status.Status = v1alpha1.InvalidFederationDomainStatusCondition
|
federationDomainWithInvalidIssuerURL.Status.Phase = v1alpha1.FederationDomainPhaseError
|
||||||
federationDomainWithInvalidIssuerURL.Status.Message = `Invalid: could not parse issuer as URL: parse ":/host//path": missing protocol scheme`
|
federationDomainWithInvalidIssuerURL.Status.Conditions = []v1alpha1.Condition{
|
||||||
federationDomainWithInvalidIssuerURL.Status.LastUpdateTime = timePtr(metav1.NewTime(frozenNow))
|
unknownIssuerIsUniqueCondition(frozenMetav1Now, 123),
|
||||||
|
sadIssuerURLValidConditionCannotParse(frozenMetav1Now, 123),
|
||||||
|
unknownOneTLSSecretPerIssuerHostnameCondition(frozenMetav1Now, 123),
|
||||||
|
sadReadyCondition(frozenMetav1Now, 123),
|
||||||
|
}
|
||||||
|
|
||||||
expectedActions := []coretesting.Action{
|
expectedActions := []coretesting.Action{
|
||||||
coretesting.NewGetAction(
|
coretesting.NewUpdateSubresourceAction(
|
||||||
federationDomainGVR,
|
federationDomainGVR,
|
||||||
federationDomainSameIssuerAddress1.Namespace,
|
"status",
|
||||||
federationDomainSameIssuerAddress1.Name,
|
federationDomainDifferentIssuerAddress.Namespace,
|
||||||
|
federationDomainDifferentIssuerAddress,
|
||||||
),
|
),
|
||||||
coretesting.NewUpdateSubresourceAction(
|
coretesting.NewUpdateSubresourceAction(
|
||||||
federationDomainGVR,
|
federationDomainGVR,
|
||||||
@ -936,33 +900,12 @@ func TestSync(t *testing.T) {
|
|||||||
federationDomainSameIssuerAddress1.Namespace,
|
federationDomainSameIssuerAddress1.Namespace,
|
||||||
federationDomainSameIssuerAddress1,
|
federationDomainSameIssuerAddress1,
|
||||||
),
|
),
|
||||||
coretesting.NewGetAction(
|
|
||||||
federationDomainGVR,
|
|
||||||
federationDomainSameIssuerAddress2.Namespace,
|
|
||||||
federationDomainSameIssuerAddress2.Name,
|
|
||||||
),
|
|
||||||
coretesting.NewUpdateSubresourceAction(
|
coretesting.NewUpdateSubresourceAction(
|
||||||
federationDomainGVR,
|
federationDomainGVR,
|
||||||
"status",
|
"status",
|
||||||
federationDomainSameIssuerAddress2.Namespace,
|
federationDomainSameIssuerAddress2.Namespace,
|
||||||
federationDomainSameIssuerAddress2,
|
federationDomainSameIssuerAddress2,
|
||||||
),
|
),
|
||||||
coretesting.NewGetAction(
|
|
||||||
federationDomainGVR,
|
|
||||||
federationDomainDifferentIssuerAddress.Namespace,
|
|
||||||
federationDomainDifferentIssuerAddress.Name,
|
|
||||||
),
|
|
||||||
coretesting.NewUpdateSubresourceAction(
|
|
||||||
federationDomainGVR,
|
|
||||||
"status",
|
|
||||||
federationDomainDifferentIssuerAddress.Namespace,
|
|
||||||
federationDomainDifferentIssuerAddress,
|
|
||||||
),
|
|
||||||
coretesting.NewGetAction(
|
|
||||||
federationDomainGVR,
|
|
||||||
federationDomainWithInvalidIssuerURL.Namespace,
|
|
||||||
federationDomainWithInvalidIssuerURL.Name,
|
|
||||||
),
|
|
||||||
coretesting.NewUpdateSubresourceAction(
|
coretesting.NewUpdateSubresourceAction(
|
||||||
federationDomainGVR,
|
federationDomainGVR,
|
||||||
"status",
|
"status",
|
||||||
@ -972,55 +915,6 @@ func TestSync(t *testing.T) {
|
|||||||
}
|
}
|
||||||
r.ElementsMatch(expectedActions, pinnipedAPIClient.Actions())
|
r.ElementsMatch(expectedActions, pinnipedAPIClient.Actions())
|
||||||
})
|
})
|
||||||
|
|
||||||
when("we cannot talk to the API", func() {
|
|
||||||
var count int
|
|
||||||
it.Before(func() {
|
|
||||||
pinnipedAPIClient.PrependReactor(
|
|
||||||
"get",
|
|
||||||
"federationdomains",
|
|
||||||
func(_ coretesting.Action) (bool, runtime.Object, error) {
|
|
||||||
count++
|
|
||||||
return true, nil, fmt.Errorf("some get error %d", count)
|
|
||||||
},
|
|
||||||
)
|
|
||||||
})
|
|
||||||
|
|
||||||
it("returns the get errors", func() {
|
|
||||||
expectedError := here.Doc(`[could not update status: get failed: some get error 1, could not update status: get failed: some get error 2, could not update status: get failed: some get error 3, could not update status: get failed: some get error 4]`)
|
|
||||||
startInformersAndController()
|
|
||||||
err := controllerlib.TestSync(t, subject, *syncContext)
|
|
||||||
r.EqualError(err, expectedError)
|
|
||||||
|
|
||||||
federationDomainDifferentIssuerAddress.Status.Status = v1alpha1.SuccessFederationDomainStatusCondition
|
|
||||||
federationDomainDifferentIssuerAddress.Status.Message = "Provider successfully created"
|
|
||||||
federationDomainDifferentIssuerAddress.Status.LastUpdateTime = timePtr(metav1.NewTime(frozenNow))
|
|
||||||
|
|
||||||
expectedActions := []coretesting.Action{
|
|
||||||
coretesting.NewGetAction(
|
|
||||||
federationDomainGVR,
|
|
||||||
federationDomainSameIssuerAddress1.Namespace,
|
|
||||||
federationDomainSameIssuerAddress1.Name,
|
|
||||||
),
|
|
||||||
coretesting.NewGetAction(
|
|
||||||
federationDomainGVR,
|
|
||||||
federationDomainSameIssuerAddress2.Namespace,
|
|
||||||
federationDomainSameIssuerAddress2.Name,
|
|
||||||
),
|
|
||||||
coretesting.NewGetAction(
|
|
||||||
federationDomainGVR,
|
|
||||||
federationDomainDifferentIssuerAddress.Namespace,
|
|
||||||
federationDomainDifferentIssuerAddress.Name,
|
|
||||||
),
|
|
||||||
coretesting.NewGetAction(
|
|
||||||
federationDomainGVR,
|
|
||||||
federationDomainWithInvalidIssuerURL.Namespace,
|
|
||||||
federationDomainWithInvalidIssuerURL.Name,
|
|
||||||
),
|
|
||||||
}
|
|
||||||
r.ElementsMatch(expectedActions, pinnipedAPIClient.Actions())
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
|
|
||||||
when("there are no FederationDomains in the informer", func() {
|
when("there are no FederationDomains in the informer", func() {
|
||||||
|
@ -133,11 +133,12 @@ func (c *oidcClientWatcherController) updateStatus(
|
|||||||
) error {
|
) error {
|
||||||
updated := upstream.DeepCopy()
|
updated := upstream.DeepCopy()
|
||||||
|
|
||||||
hadErrorCondition := conditionsutil.MergeConfigConditions(conditions, upstream.Generation, &updated.Status.Conditions, plog.New())
|
hadErrorCondition := conditionsutil.MergeConfigConditions(conditions,
|
||||||
|
upstream.Generation, &updated.Status.Conditions, plog.New(), metav1.Now())
|
||||||
|
|
||||||
updated.Status.Phase = v1alpha1.PhaseReady
|
updated.Status.Phase = v1alpha1.OIDCClientPhaseReady
|
||||||
if hadErrorCondition {
|
if hadErrorCondition {
|
||||||
updated.Status.Phase = v1alpha1.PhaseError
|
updated.Status.Phase = v1alpha1.OIDCClientPhaseError
|
||||||
}
|
}
|
||||||
|
|
||||||
updated.Status.TotalClientSecrets = int32(totalClientSecrets)
|
updated.Status.TotalClientSecrets = int32(totalClientSecrets)
|
||||||
|
@ -103,7 +103,7 @@ func TestE2EFullIntegration_Browser(t *testing.T) {
|
|||||||
downstream := testlib.CreateTestFederationDomain(topSetupCtx, t,
|
downstream := testlib.CreateTestFederationDomain(topSetupCtx, t,
|
||||||
issuerURL.String(),
|
issuerURL.String(),
|
||||||
certSecret.Name,
|
certSecret.Name,
|
||||||
configv1alpha1.SuccessFederationDomainStatusCondition,
|
configv1alpha1.FederationDomainPhaseReady,
|
||||||
)
|
)
|
||||||
|
|
||||||
// Create a JWTAuthenticator that will validate the tokens from the downstream issuer.
|
// Create a JWTAuthenticator that will validate the tokens from the downstream issuer.
|
||||||
|
@ -441,7 +441,7 @@ func TestGetAPIResourceList(t *testing.T) { //nolint:gocyclo // each t.Run is pr
|
|||||||
// over time, make a rudimentary assertion that this test exercised the whole tree of all fields of all
|
// over time, make a rudimentary assertion that this test exercised the whole tree of all fields of all
|
||||||
// Pinniped API resources. Without this, the test could accidentally skip parts of the tree if the
|
// Pinniped API resources. Without this, the test could accidentally skip parts of the tree if the
|
||||||
// format has changed.
|
// format has changed.
|
||||||
require.Equal(t, 254, foundFieldNames,
|
require.Equal(t, 259, foundFieldNames,
|
||||||
"Expected to find all known fields of all Pinniped API resources. "+
|
"Expected to find all known fields of all Pinniped API resources. "+
|
||||||
"You may will need to update this expectation if you added new fields to the API types.",
|
"You may will need to update this expectation if you added new fields to the API types.",
|
||||||
)
|
)
|
||||||
|
@ -125,14 +125,24 @@ func TestSupervisorOIDCDiscovery_Disruptive(t *testing.T) {
|
|||||||
// When the same issuer is added twice, both issuers are marked as duplicates, and neither provider is serving.
|
// When the same issuer is added twice, both issuers are marked as duplicates, and neither provider is serving.
|
||||||
config6Duplicate1, _ := requireCreatingFederationDomainCausesDiscoveryEndpointsToAppear(ctx, t, scheme, addr, caBundle, issuer6, client)
|
config6Duplicate1, _ := requireCreatingFederationDomainCausesDiscoveryEndpointsToAppear(ctx, t, scheme, addr, caBundle, issuer6, client)
|
||||||
config6Duplicate2 := testlib.CreateTestFederationDomain(ctx, t, issuer6, "", "")
|
config6Duplicate2 := testlib.CreateTestFederationDomain(ctx, t, issuer6, "", "")
|
||||||
requireStatus(t, client, ns, config6Duplicate1.Name, v1alpha1.DuplicateFederationDomainStatusCondition)
|
requireStatus(t, client, ns, config6Duplicate1.Name, v1alpha1.FederationDomainPhaseError, map[string]v1alpha1.ConditionStatus{
|
||||||
requireStatus(t, client, ns, config6Duplicate2.Name, v1alpha1.DuplicateFederationDomainStatusCondition)
|
"Ready": v1alpha1.ConditionFalse,
|
||||||
|
"IssuerIsUnique": v1alpha1.ConditionFalse,
|
||||||
|
"OneTLSSecretPerIssuerHostname": v1alpha1.ConditionTrue,
|
||||||
|
"IssuerURLValid": v1alpha1.ConditionTrue,
|
||||||
|
})
|
||||||
|
requireStatus(t, client, ns, config6Duplicate2.Name, v1alpha1.FederationDomainPhaseError, map[string]v1alpha1.ConditionStatus{
|
||||||
|
"Ready": v1alpha1.ConditionFalse,
|
||||||
|
"IssuerIsUnique": v1alpha1.ConditionFalse,
|
||||||
|
"OneTLSSecretPerIssuerHostname": v1alpha1.ConditionTrue,
|
||||||
|
"IssuerURLValid": v1alpha1.ConditionTrue,
|
||||||
|
})
|
||||||
requireDiscoveryEndpointsAreNotFound(t, scheme, addr, caBundle, issuer6)
|
requireDiscoveryEndpointsAreNotFound(t, scheme, addr, caBundle, issuer6)
|
||||||
|
|
||||||
// If we delete the first duplicate issuer, the second duplicate issuer starts serving.
|
// If we delete the first duplicate issuer, the second duplicate issuer starts serving.
|
||||||
requireDelete(t, client, ns, config6Duplicate1.Name)
|
requireDelete(t, client, ns, config6Duplicate1.Name)
|
||||||
requireWellKnownEndpointIsWorking(t, scheme, addr, caBundle, issuer6, nil)
|
requireWellKnownEndpointIsWorking(t, scheme, addr, caBundle, issuer6, nil)
|
||||||
requireStatus(t, client, ns, config6Duplicate2.Name, v1alpha1.SuccessFederationDomainStatusCondition)
|
requireFullySuccessfulStatus(t, client, ns, config6Duplicate2.Name)
|
||||||
|
|
||||||
// When we finally delete all issuers, the endpoint should be down.
|
// When we finally delete all issuers, the endpoint should be down.
|
||||||
requireDeletingFederationDomainCausesDiscoveryEndpointsToDisappear(t, config6Duplicate2, client, ns, scheme, addr, caBundle, issuer6)
|
requireDeletingFederationDomainCausesDiscoveryEndpointsToDisappear(t, config6Duplicate2, client, ns, scheme, addr, caBundle, issuer6)
|
||||||
@ -144,7 +154,12 @@ func TestSupervisorOIDCDiscovery_Disruptive(t *testing.T) {
|
|||||||
|
|
||||||
// When we create a provider with an invalid issuer, the status is set to invalid.
|
// When we create a provider with an invalid issuer, the status is set to invalid.
|
||||||
badConfig := testlib.CreateTestFederationDomain(ctx, t, badIssuer, "", "")
|
badConfig := testlib.CreateTestFederationDomain(ctx, t, badIssuer, "", "")
|
||||||
requireStatus(t, client, ns, badConfig.Name, v1alpha1.InvalidFederationDomainStatusCondition)
|
requireStatus(t, client, ns, badConfig.Name, v1alpha1.FederationDomainPhaseError, map[string]v1alpha1.ConditionStatus{
|
||||||
|
"Ready": v1alpha1.ConditionFalse,
|
||||||
|
"IssuerIsUnique": v1alpha1.ConditionTrue,
|
||||||
|
"OneTLSSecretPerIssuerHostname": v1alpha1.ConditionTrue,
|
||||||
|
"IssuerURLValid": v1alpha1.ConditionFalse,
|
||||||
|
})
|
||||||
requireDiscoveryEndpointsAreNotFound(t, scheme, addr, caBundle, badIssuer)
|
requireDiscoveryEndpointsAreNotFound(t, scheme, addr, caBundle, badIssuer)
|
||||||
requireDeletingFederationDomainCausesDiscoveryEndpointsToDisappear(t, badConfig, client, ns, scheme, addr, caBundle, badIssuer)
|
requireDeletingFederationDomainCausesDiscoveryEndpointsToDisappear(t, badConfig, client, ns, scheme, addr, caBundle, badIssuer)
|
||||||
})
|
})
|
||||||
@ -172,7 +187,7 @@ func TestSupervisorTLSTerminationWithSNI_Disruptive(t *testing.T) {
|
|||||||
|
|
||||||
// Create an FederationDomain with a spec.tls.secretName.
|
// Create an FederationDomain with a spec.tls.secretName.
|
||||||
federationDomain1 := testlib.CreateTestFederationDomain(ctx, t, issuer1, certSecretName1, "")
|
federationDomain1 := testlib.CreateTestFederationDomain(ctx, t, issuer1, certSecretName1, "")
|
||||||
requireStatus(t, pinnipedClient, federationDomain1.Namespace, federationDomain1.Name, v1alpha1.SuccessFederationDomainStatusCondition)
|
requireFullySuccessfulStatus(t, pinnipedClient, federationDomain1.Namespace, federationDomain1.Name)
|
||||||
|
|
||||||
// The spec.tls.secretName Secret does not exist, so the endpoints should fail with TLS errors.
|
// The spec.tls.secretName Secret does not exist, so the endpoints should fail with TLS errors.
|
||||||
requireEndpointHasBootstrapTLSErrorBecauseCertificatesAreNotReady(t, issuer1)
|
requireEndpointHasBootstrapTLSErrorBecauseCertificatesAreNotReady(t, issuer1)
|
||||||
@ -212,7 +227,7 @@ func TestSupervisorTLSTerminationWithSNI_Disruptive(t *testing.T) {
|
|||||||
|
|
||||||
// Create an FederationDomain with a spec.tls.secretName.
|
// Create an FederationDomain with a spec.tls.secretName.
|
||||||
federationDomain2 := testlib.CreateTestFederationDomain(ctx, t, issuer2, certSecretName2, "")
|
federationDomain2 := testlib.CreateTestFederationDomain(ctx, t, issuer2, certSecretName2, "")
|
||||||
requireStatus(t, pinnipedClient, federationDomain2.Namespace, federationDomain2.Name, v1alpha1.SuccessFederationDomainStatusCondition)
|
requireFullySuccessfulStatus(t, pinnipedClient, federationDomain2.Namespace, federationDomain2.Name)
|
||||||
|
|
||||||
// Create the Secret.
|
// Create the Secret.
|
||||||
ca2 := createTLSCertificateSecret(ctx, t, ns, hostname2, nil, certSecretName2, kubeClient)
|
ca2 := createTLSCertificateSecret(ctx, t, ns, hostname2, nil, certSecretName2, kubeClient)
|
||||||
@ -256,7 +271,7 @@ func TestSupervisorTLSTerminationWithDefaultCerts_Disruptive(t *testing.T) {
|
|||||||
|
|
||||||
// Create an FederationDomain without a spec.tls.secretName.
|
// Create an FederationDomain without a spec.tls.secretName.
|
||||||
federationDomain1 := testlib.CreateTestFederationDomain(ctx, t, issuerUsingIPAddress, "", "")
|
federationDomain1 := testlib.CreateTestFederationDomain(ctx, t, issuerUsingIPAddress, "", "")
|
||||||
requireStatus(t, pinnipedClient, federationDomain1.Namespace, federationDomain1.Name, v1alpha1.SuccessFederationDomainStatusCondition)
|
requireFullySuccessfulStatus(t, pinnipedClient, federationDomain1.Namespace, federationDomain1.Name)
|
||||||
|
|
||||||
// There is no default TLS cert and the spec.tls.secretName was not set, so the endpoints should fail with TLS errors.
|
// There is no default TLS cert and the spec.tls.secretName was not set, so the endpoints should fail with TLS errors.
|
||||||
requireEndpointHasBootstrapTLSErrorBecauseCertificatesAreNotReady(t, issuerUsingIPAddress)
|
requireEndpointHasBootstrapTLSErrorBecauseCertificatesAreNotReady(t, issuerUsingIPAddress)
|
||||||
@ -270,7 +285,7 @@ func TestSupervisorTLSTerminationWithDefaultCerts_Disruptive(t *testing.T) {
|
|||||||
// Create an FederationDomain with a spec.tls.secretName.
|
// Create an FederationDomain with a spec.tls.secretName.
|
||||||
certSecretName := "integration-test-cert-1"
|
certSecretName := "integration-test-cert-1"
|
||||||
federationDomain2 := testlib.CreateTestFederationDomain(ctx, t, issuerUsingHostname, certSecretName, "")
|
federationDomain2 := testlib.CreateTestFederationDomain(ctx, t, issuerUsingHostname, certSecretName, "")
|
||||||
requireStatus(t, pinnipedClient, federationDomain2.Namespace, federationDomain2.Name, v1alpha1.SuccessFederationDomainStatusCondition)
|
requireFullySuccessfulStatus(t, pinnipedClient, federationDomain2.Namespace, federationDomain2.Name)
|
||||||
|
|
||||||
// Create the Secret.
|
// Create the Secret.
|
||||||
certCA := createTLSCertificateSecret(ctx, t, ns, hostname, nil, certSecretName, kubeClient)
|
certCA := createTLSCertificateSecret(ctx, t, ns, hostname, nil, certSecretName, kubeClient)
|
||||||
@ -458,7 +473,7 @@ func requireCreatingFederationDomainCausesDiscoveryEndpointsToAppear(
|
|||||||
t.Helper()
|
t.Helper()
|
||||||
newFederationDomain := testlib.CreateTestFederationDomain(ctx, t, issuerName, "", "")
|
newFederationDomain := testlib.CreateTestFederationDomain(ctx, t, issuerName, "", "")
|
||||||
jwksResult := requireDiscoveryEndpointsAreWorking(t, supervisorScheme, supervisorAddress, supervisorCABundle, issuerName, nil)
|
jwksResult := requireDiscoveryEndpointsAreWorking(t, supervisorScheme, supervisorAddress, supervisorCABundle, issuerName, nil)
|
||||||
requireStatus(t, client, newFederationDomain.Namespace, newFederationDomain.Name, v1alpha1.SuccessFederationDomainStatusCondition)
|
requireFullySuccessfulStatus(t, client, newFederationDomain.Namespace, newFederationDomain.Name)
|
||||||
return newFederationDomain, jwksResult
|
return newFederationDomain, jwksResult
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -626,7 +641,16 @@ func requireDelete(t *testing.T, client pinnipedclientset.Interface, ns, name st
|
|||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
func requireStatus(t *testing.T, client pinnipedclientset.Interface, ns, name string, status v1alpha1.FederationDomainStatusCondition) {
|
func requireFullySuccessfulStatus(t *testing.T, client pinnipedclientset.Interface, ns, name string) {
|
||||||
|
requireStatus(t, client, ns, name, v1alpha1.FederationDomainPhaseReady, map[string]v1alpha1.ConditionStatus{
|
||||||
|
"Ready": v1alpha1.ConditionTrue,
|
||||||
|
"IssuerIsUnique": v1alpha1.ConditionTrue,
|
||||||
|
"OneTLSSecretPerIssuerHostname": v1alpha1.ConditionTrue,
|
||||||
|
"IssuerURLValid": v1alpha1.ConditionTrue,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func requireStatus(t *testing.T, client pinnipedclientset.Interface, ns, name string, phase v1alpha1.FederationDomainPhase, conditionTypeToStatus map[string]v1alpha1.ConditionStatus) {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
|
|
||||||
testlib.RequireEventually(t, func(requireEventually *require.Assertions) {
|
testlib.RequireEventually(t, func(requireEventually *require.Assertions) {
|
||||||
@ -636,8 +660,14 @@ func requireStatus(t *testing.T, client pinnipedclientset.Interface, ns, name st
|
|||||||
federationDomain, err := client.ConfigV1alpha1().FederationDomains(ns).Get(ctx, name, metav1.GetOptions{})
|
federationDomain, err := client.ConfigV1alpha1().FederationDomains(ns).Get(ctx, name, metav1.GetOptions{})
|
||||||
requireEventually.NoError(err)
|
requireEventually.NoError(err)
|
||||||
|
|
||||||
t.Logf("found FederationDomain %s/%s with status %s", ns, name, federationDomain.Status.Status)
|
t.Logf("found FederationDomain %s/%s with phase %s", ns, name, federationDomain.Status.Phase)
|
||||||
requireEventually.Equalf(status, federationDomain.Status.Status, "unexpected status (message = '%s')", federationDomain.Status.Message)
|
requireEventually.Equalf(phase, federationDomain.Status.Phase, "unexpected phase (conditions = '%#v')", federationDomain.Status.Conditions)
|
||||||
|
|
||||||
|
actualConditionTypeToStatus := map[string]v1alpha1.ConditionStatus{}
|
||||||
|
for _, c := range federationDomain.Status.Conditions {
|
||||||
|
actualConditionTypeToStatus[c.Type] = c.Status
|
||||||
|
}
|
||||||
|
requireEventually.Equal(conditionTypeToStatus, actualConditionTypeToStatus, "unexpected statuses for conditions by type")
|
||||||
}, 5*time.Minute, 200*time.Millisecond)
|
}, 5*time.Minute, 200*time.Millisecond)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1469,7 +1469,7 @@ func TestSupervisorLogin_Browser(t *testing.T) {
|
|||||||
AllowedRedirectURIs: []configv1alpha1.RedirectURI{configv1alpha1.RedirectURI(callbackURL)},
|
AllowedRedirectURIs: []configv1alpha1.RedirectURI{configv1alpha1.RedirectURI(callbackURL)},
|
||||||
AllowedGrantTypes: []configv1alpha1.GrantType{"authorization_code", "urn:ietf:params:oauth:grant-type:token-exchange", "refresh_token"},
|
AllowedGrantTypes: []configv1alpha1.GrantType{"authorization_code", "urn:ietf:params:oauth:grant-type:token-exchange", "refresh_token"},
|
||||||
AllowedScopes: []configv1alpha1.Scope{"openid", "offline_access", "pinniped:request-audience", "username", "groups"},
|
AllowedScopes: []configv1alpha1.Scope{"openid", "offline_access", "pinniped:request-audience", "username", "groups"},
|
||||||
}, configv1alpha1.PhaseReady)
|
}, configv1alpha1.OIDCClientPhaseReady)
|
||||||
},
|
},
|
||||||
requestAuthorization: requestAuthorizationUsingBrowserAuthcodeFlowOIDC,
|
requestAuthorization: requestAuthorizationUsingBrowserAuthcodeFlowOIDC,
|
||||||
// the ID token Subject should include the upstream user ID after the upstream issuer name
|
// the ID token Subject should include the upstream user ID after the upstream issuer name
|
||||||
@ -1502,7 +1502,7 @@ func TestSupervisorLogin_Browser(t *testing.T) {
|
|||||||
AllowedRedirectURIs: []configv1alpha1.RedirectURI{configv1alpha1.RedirectURI(callbackURL)},
|
AllowedRedirectURIs: []configv1alpha1.RedirectURI{configv1alpha1.RedirectURI(callbackURL)},
|
||||||
AllowedGrantTypes: []configv1alpha1.GrantType{"authorization_code", "urn:ietf:params:oauth:grant-type:token-exchange", "refresh_token"},
|
AllowedGrantTypes: []configv1alpha1.GrantType{"authorization_code", "urn:ietf:params:oauth:grant-type:token-exchange", "refresh_token"},
|
||||||
AllowedScopes: []configv1alpha1.Scope{"openid", "offline_access", "pinniped:request-audience", "username", "groups"},
|
AllowedScopes: []configv1alpha1.Scope{"openid", "offline_access", "pinniped:request-audience", "username", "groups"},
|
||||||
}, configv1alpha1.PhaseReady)
|
}, configv1alpha1.OIDCClientPhaseReady)
|
||||||
},
|
},
|
||||||
requestAuthorization: requestAuthorizationUsingBrowserAuthcodeFlowOIDC,
|
requestAuthorization: requestAuthorizationUsingBrowserAuthcodeFlowOIDC,
|
||||||
// the ID token Subject should include the upstream user ID after the upstream issuer name
|
// the ID token Subject should include the upstream user ID after the upstream issuer name
|
||||||
@ -1526,7 +1526,7 @@ func TestSupervisorLogin_Browser(t *testing.T) {
|
|||||||
AllowedRedirectURIs: []configv1alpha1.RedirectURI{configv1alpha1.RedirectURI(callbackURL)},
|
AllowedRedirectURIs: []configv1alpha1.RedirectURI{configv1alpha1.RedirectURI(callbackURL)},
|
||||||
AllowedGrantTypes: []configv1alpha1.GrantType{"authorization_code", "urn:ietf:params:oauth:grant-type:token-exchange", "refresh_token"},
|
AllowedGrantTypes: []configv1alpha1.GrantType{"authorization_code", "urn:ietf:params:oauth:grant-type:token-exchange", "refresh_token"},
|
||||||
AllowedScopes: []configv1alpha1.Scope{"openid", "offline_access", "pinniped:request-audience", "username", "groups"},
|
AllowedScopes: []configv1alpha1.Scope{"openid", "offline_access", "pinniped:request-audience", "username", "groups"},
|
||||||
}, configv1alpha1.PhaseReady)
|
}, configv1alpha1.OIDCClientPhaseReady)
|
||||||
},
|
},
|
||||||
testUser: func(t *testing.T) (string, string) {
|
testUser: func(t *testing.T) (string, string) {
|
||||||
// return the username and password of the existing user that we want to use for this test
|
// return the username and password of the existing user that we want to use for this test
|
||||||
@ -1558,7 +1558,7 @@ func TestSupervisorLogin_Browser(t *testing.T) {
|
|||||||
AllowedRedirectURIs: []configv1alpha1.RedirectURI{configv1alpha1.RedirectURI(callbackURL)},
|
AllowedRedirectURIs: []configv1alpha1.RedirectURI{configv1alpha1.RedirectURI(callbackURL)},
|
||||||
AllowedGrantTypes: []configv1alpha1.GrantType{"authorization_code", "refresh_token"}, // token exchange grant type not allowed
|
AllowedGrantTypes: []configv1alpha1.GrantType{"authorization_code", "refresh_token"}, // token exchange grant type not allowed
|
||||||
AllowedScopes: []configv1alpha1.Scope{"openid", "offline_access", "username", "groups"}, // a validation requires that we also disallow the pinniped:request-audience scope
|
AllowedScopes: []configv1alpha1.Scope{"openid", "offline_access", "username", "groups"}, // a validation requires that we also disallow the pinniped:request-audience scope
|
||||||
}, configv1alpha1.PhaseReady)
|
}, configv1alpha1.OIDCClientPhaseReady)
|
||||||
},
|
},
|
||||||
testUser: func(t *testing.T) (string, string) {
|
testUser: func(t *testing.T) (string, string) {
|
||||||
// return the username and password of the existing user that we want to use for this test
|
// return the username and password of the existing user that we want to use for this test
|
||||||
@ -1592,7 +1592,7 @@ func TestSupervisorLogin_Browser(t *testing.T) {
|
|||||||
AllowedRedirectURIs: []configv1alpha1.RedirectURI{configv1alpha1.RedirectURI(callbackURL)},
|
AllowedRedirectURIs: []configv1alpha1.RedirectURI{configv1alpha1.RedirectURI(callbackURL)},
|
||||||
AllowedGrantTypes: []configv1alpha1.GrantType{"authorization_code", "urn:ietf:params:oauth:grant-type:token-exchange", "refresh_token"},
|
AllowedGrantTypes: []configv1alpha1.GrantType{"authorization_code", "urn:ietf:params:oauth:grant-type:token-exchange", "refresh_token"},
|
||||||
AllowedScopes: []configv1alpha1.Scope{"openid", "offline_access", "pinniped:request-audience", "username", "groups"},
|
AllowedScopes: []configv1alpha1.Scope{"openid", "offline_access", "pinniped:request-audience", "username", "groups"},
|
||||||
}, configv1alpha1.PhaseReady)
|
}, configv1alpha1.OIDCClientPhaseReady)
|
||||||
},
|
},
|
||||||
testUser: func(t *testing.T) (string, string) {
|
testUser: func(t *testing.T) (string, string) {
|
||||||
// return the username and password of the existing user that we want to use for this test
|
// return the username and password of the existing user that we want to use for this test
|
||||||
@ -1626,7 +1626,7 @@ func TestSupervisorLogin_Browser(t *testing.T) {
|
|||||||
AllowedRedirectURIs: []configv1alpha1.RedirectURI{configv1alpha1.RedirectURI(callbackURL)},
|
AllowedRedirectURIs: []configv1alpha1.RedirectURI{configv1alpha1.RedirectURI(callbackURL)},
|
||||||
AllowedGrantTypes: []configv1alpha1.GrantType{"authorization_code", "refresh_token"}, // token exchange not allowed (required to exclude groups scope)
|
AllowedGrantTypes: []configv1alpha1.GrantType{"authorization_code", "refresh_token"}, // token exchange not allowed (required to exclude groups scope)
|
||||||
AllowedScopes: []configv1alpha1.Scope{"openid", "offline_access", "groups"}, // username not allowed
|
AllowedScopes: []configv1alpha1.Scope{"openid", "offline_access", "groups"}, // username not allowed
|
||||||
}, configv1alpha1.PhaseReady)
|
}, configv1alpha1.OIDCClientPhaseReady)
|
||||||
},
|
},
|
||||||
testUser: func(t *testing.T) (string, string) {
|
testUser: func(t *testing.T) (string, string) {
|
||||||
// return the username and password of the existing user that we want to use for this test
|
// return the username and password of the existing user that we want to use for this test
|
||||||
@ -1652,7 +1652,7 @@ func TestSupervisorLogin_Browser(t *testing.T) {
|
|||||||
AllowedRedirectURIs: []configv1alpha1.RedirectURI{configv1alpha1.RedirectURI(callbackURL)},
|
AllowedRedirectURIs: []configv1alpha1.RedirectURI{configv1alpha1.RedirectURI(callbackURL)},
|
||||||
AllowedGrantTypes: []configv1alpha1.GrantType{"authorization_code", "refresh_token"}, // token exchange not allowed (required to exclude groups scope)
|
AllowedGrantTypes: []configv1alpha1.GrantType{"authorization_code", "refresh_token"}, // token exchange not allowed (required to exclude groups scope)
|
||||||
AllowedScopes: []configv1alpha1.Scope{"openid", "offline_access", "username"}, // groups not allowed
|
AllowedScopes: []configv1alpha1.Scope{"openid", "offline_access", "username"}, // groups not allowed
|
||||||
}, configv1alpha1.PhaseReady)
|
}, configv1alpha1.OIDCClientPhaseReady)
|
||||||
},
|
},
|
||||||
testUser: func(t *testing.T) (string, string) {
|
testUser: func(t *testing.T) (string, string) {
|
||||||
// return the username and password of the existing user that we want to use for this test
|
// return the username and password of the existing user that we want to use for this test
|
||||||
@ -1678,7 +1678,7 @@ func TestSupervisorLogin_Browser(t *testing.T) {
|
|||||||
AllowedRedirectURIs: []configv1alpha1.RedirectURI{configv1alpha1.RedirectURI(callbackURL)},
|
AllowedRedirectURIs: []configv1alpha1.RedirectURI{configv1alpha1.RedirectURI(callbackURL)},
|
||||||
AllowedGrantTypes: []configv1alpha1.GrantType{"authorization_code", "urn:ietf:params:oauth:grant-type:token-exchange", "refresh_token"},
|
AllowedGrantTypes: []configv1alpha1.GrantType{"authorization_code", "urn:ietf:params:oauth:grant-type:token-exchange", "refresh_token"},
|
||||||
AllowedScopes: []configv1alpha1.Scope{"openid", "offline_access", "pinniped:request-audience", "username", "groups"},
|
AllowedScopes: []configv1alpha1.Scope{"openid", "offline_access", "pinniped:request-audience", "username", "groups"},
|
||||||
}, configv1alpha1.PhaseReady)
|
}, configv1alpha1.OIDCClientPhaseReady)
|
||||||
},
|
},
|
||||||
testUser: func(t *testing.T) (string, string) {
|
testUser: func(t *testing.T) (string, string) {
|
||||||
// return the username and password of the existing user that we want to use for this test
|
// return the username and password of the existing user that we want to use for this test
|
||||||
@ -1711,7 +1711,7 @@ func TestSupervisorLogin_Browser(t *testing.T) {
|
|||||||
AllowedRedirectURIs: []configv1alpha1.RedirectURI{configv1alpha1.RedirectURI(callbackURL)},
|
AllowedRedirectURIs: []configv1alpha1.RedirectURI{configv1alpha1.RedirectURI(callbackURL)},
|
||||||
AllowedGrantTypes: []configv1alpha1.GrantType{"authorization_code", "urn:ietf:params:oauth:grant-type:token-exchange", "refresh_token"},
|
AllowedGrantTypes: []configv1alpha1.GrantType{"authorization_code", "urn:ietf:params:oauth:grant-type:token-exchange", "refresh_token"},
|
||||||
AllowedScopes: []configv1alpha1.Scope{"openid", "offline_access", "pinniped:request-audience", "username", "groups"},
|
AllowedScopes: []configv1alpha1.Scope{"openid", "offline_access", "pinniped:request-audience", "username", "groups"},
|
||||||
}, configv1alpha1.PhaseReady)
|
}, configv1alpha1.OIDCClientPhaseReady)
|
||||||
},
|
},
|
||||||
testUser: func(t *testing.T) (string, string) {
|
testUser: func(t *testing.T) (string, string) {
|
||||||
// return the username and password of the existing user that we want to use for this test
|
// return the username and password of the existing user that we want to use for this test
|
||||||
@ -1750,7 +1750,7 @@ func TestSupervisorLogin_Browser(t *testing.T) {
|
|||||||
AllowedRedirectURIs: []configv1alpha1.RedirectURI{configv1alpha1.RedirectURI(callbackURL)},
|
AllowedRedirectURIs: []configv1alpha1.RedirectURI{configv1alpha1.RedirectURI(callbackURL)},
|
||||||
AllowedGrantTypes: []configv1alpha1.GrantType{"authorization_code", "refresh_token"},
|
AllowedGrantTypes: []configv1alpha1.GrantType{"authorization_code", "refresh_token"},
|
||||||
AllowedScopes: []configv1alpha1.Scope{"openid", "offline_access"}, // validations require that when username/groups are excluded, then token exchange must also not be allowed
|
AllowedScopes: []configv1alpha1.Scope{"openid", "offline_access"}, // validations require that when username/groups are excluded, then token exchange must also not be allowed
|
||||||
}, configv1alpha1.PhaseReady)
|
}, configv1alpha1.OIDCClientPhaseReady)
|
||||||
},
|
},
|
||||||
testUser: func(t *testing.T) (string, string) {
|
testUser: func(t *testing.T) (string, string) {
|
||||||
// return the username and password of the existing user that we want to use for this test
|
// return the username and password of the existing user that we want to use for this test
|
||||||
@ -1789,7 +1789,7 @@ func TestSupervisorLogin_Browser(t *testing.T) {
|
|||||||
AllowedRedirectURIs: []configv1alpha1.RedirectURI{configv1alpha1.RedirectURI(callbackURL)},
|
AllowedRedirectURIs: []configv1alpha1.RedirectURI{configv1alpha1.RedirectURI(callbackURL)},
|
||||||
AllowedGrantTypes: []configv1alpha1.GrantType{"authorization_code", "urn:ietf:params:oauth:grant-type:token-exchange", "refresh_token"},
|
AllowedGrantTypes: []configv1alpha1.GrantType{"authorization_code", "urn:ietf:params:oauth:grant-type:token-exchange", "refresh_token"},
|
||||||
AllowedScopes: []configv1alpha1.Scope{"openid", "offline_access", "pinniped:request-audience", "username", "groups"},
|
AllowedScopes: []configv1alpha1.Scope{"openid", "offline_access", "pinniped:request-audience", "username", "groups"},
|
||||||
}, configv1alpha1.PhaseReady)
|
}, configv1alpha1.OIDCClientPhaseReady)
|
||||||
},
|
},
|
||||||
requestAuthorization: func(t *testing.T, downstreamIssuer, downstreamAuthorizeURL, downstreamCallbackURL, _, _ string, httpClient *http.Client) {
|
requestAuthorization: func(t *testing.T, downstreamIssuer, downstreamAuthorizeURL, downstreamCallbackURL, _, _ string, httpClient *http.Client) {
|
||||||
requestAuthorizationUsingBrowserAuthcodeFlowLDAP(t,
|
requestAuthorizationUsingBrowserAuthcodeFlowLDAP(t,
|
||||||
@ -1825,7 +1825,7 @@ func TestSupervisorLogin_Browser(t *testing.T) {
|
|||||||
AllowedRedirectURIs: []configv1alpha1.RedirectURI{configv1alpha1.RedirectURI(callbackURL)},
|
AllowedRedirectURIs: []configv1alpha1.RedirectURI{configv1alpha1.RedirectURI(callbackURL)},
|
||||||
AllowedGrantTypes: []configv1alpha1.GrantType{"authorization_code", "urn:ietf:params:oauth:grant-type:token-exchange", "refresh_token"},
|
AllowedGrantTypes: []configv1alpha1.GrantType{"authorization_code", "urn:ietf:params:oauth:grant-type:token-exchange", "refresh_token"},
|
||||||
AllowedScopes: []configv1alpha1.Scope{"openid", "offline_access", "pinniped:request-audience", "username", "groups"},
|
AllowedScopes: []configv1alpha1.Scope{"openid", "offline_access", "pinniped:request-audience", "username", "groups"},
|
||||||
}, configv1alpha1.PhaseReady)
|
}, configv1alpha1.OIDCClientPhaseReady)
|
||||||
return clientID, "wrong-client-secret"
|
return clientID, "wrong-client-secret"
|
||||||
},
|
},
|
||||||
testUser: func(t *testing.T) (string, string) {
|
testUser: func(t *testing.T) (string, string) {
|
||||||
@ -2080,7 +2080,7 @@ func testSupervisorLogin(
|
|||||||
downstream := testlib.CreateTestFederationDomain(ctx, t,
|
downstream := testlib.CreateTestFederationDomain(ctx, t,
|
||||||
issuerURL.String(),
|
issuerURL.String(),
|
||||||
certSecret.Name,
|
certSecret.Name,
|
||||||
configv1alpha1.SuccessFederationDomainStatusCondition,
|
configv1alpha1.FederationDomainPhaseReady, // TODO: expect another phase because this is a legacy FederationDomain and there is no IDP yet, so it is not safe to try to do logins until the IDP exists and the controller has a chance to run again to set the default IDP
|
||||||
)
|
)
|
||||||
|
|
||||||
// Ensure the the JWKS data is created and ready for the new FederationDomain by waiting for
|
// Ensure the the JWKS data is created and ready for the new FederationDomain by waiting for
|
||||||
@ -2104,6 +2104,9 @@ func testSupervisorLogin(
|
|||||||
// Create upstream IDP and wait for it to become ready.
|
// Create upstream IDP and wait for it to become ready.
|
||||||
idpName := createIDP(t)
|
idpName := createIDP(t)
|
||||||
|
|
||||||
|
// Now that both the FederationDomain and the IDP are created, the FederationDomain should be ready.
|
||||||
|
testlib.WaitForTestFederationDomainStatus(ctx, t, downstream.Name, configv1alpha1.FederationDomainPhaseReady)
|
||||||
|
|
||||||
// Start a callback server on localhost.
|
// Start a callback server on localhost.
|
||||||
localCallbackServer := startLocalCallbackServer(t)
|
localCallbackServer := startLocalCallbackServer(t)
|
||||||
|
|
||||||
|
@ -85,7 +85,7 @@ func TestSupervisorWarnings_Browser(t *testing.T) {
|
|||||||
downstream := testlib.CreateTestFederationDomain(ctx, t,
|
downstream := testlib.CreateTestFederationDomain(ctx, t,
|
||||||
issuerURL.String(),
|
issuerURL.String(),
|
||||||
certSecret.Name,
|
certSecret.Name,
|
||||||
configv1alpha1.SuccessFederationDomainStatusCondition,
|
configv1alpha1.FederationDomainPhaseReady,
|
||||||
)
|
)
|
||||||
|
|
||||||
// Create a JWTAuthenticator that will validate the tokens from the downstream issuer.
|
// Create a JWTAuthenticator that will validate the tokens from the downstream issuer.
|
||||||
|
@ -272,7 +272,13 @@ func CreateTestJWTAuthenticator(ctx context.Context, t *testing.T, spec auth1alp
|
|||||||
// current test's lifetime.
|
// current test's lifetime.
|
||||||
// If the provided issuer is not the empty string, then it will be used for the
|
// If the provided issuer is not the empty string, then it will be used for the
|
||||||
// FederationDomain.Spec.Issuer field. Else, a random issuer will be generated.
|
// FederationDomain.Spec.Issuer field. Else, a random issuer will be generated.
|
||||||
func CreateTestFederationDomain(ctx context.Context, t *testing.T, issuer string, certSecretName string, expectStatus configv1alpha1.FederationDomainStatusCondition) *configv1alpha1.FederationDomain {
|
func CreateTestFederationDomain(
|
||||||
|
ctx context.Context,
|
||||||
|
t *testing.T,
|
||||||
|
issuer string,
|
||||||
|
certSecretName string,
|
||||||
|
expectStatus configv1alpha1.FederationDomainPhase,
|
||||||
|
) *configv1alpha1.FederationDomain {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
testEnv := IntegrationEnv(t)
|
testEnv := IntegrationEnv(t)
|
||||||
|
|
||||||
@ -283,8 +289,8 @@ func CreateTestFederationDomain(ctx context.Context, t *testing.T, issuer string
|
|||||||
issuer = fmt.Sprintf("http://test-issuer-%s.pinniped.dev", RandHex(t, 8))
|
issuer = fmt.Sprintf("http://test-issuer-%s.pinniped.dev", RandHex(t, 8))
|
||||||
}
|
}
|
||||||
|
|
||||||
federationDomains := NewSupervisorClientset(t).ConfigV1alpha1().FederationDomains(testEnv.SupervisorNamespace)
|
federationDomainsClient := NewSupervisorClientset(t).ConfigV1alpha1().FederationDomains(testEnv.SupervisorNamespace)
|
||||||
federationDomain, err := federationDomains.Create(createContext, &configv1alpha1.FederationDomain{
|
federationDomain, err := federationDomainsClient.Create(createContext, &configv1alpha1.FederationDomain{
|
||||||
ObjectMeta: testObjectMeta(t, "oidc-provider"),
|
ObjectMeta: testObjectMeta(t, "oidc-provider"),
|
||||||
Spec: configv1alpha1.FederationDomainSpec{
|
Spec: configv1alpha1.FederationDomainSpec{
|
||||||
Issuer: issuer,
|
Issuer: issuer,
|
||||||
@ -299,7 +305,7 @@ func CreateTestFederationDomain(ctx context.Context, t *testing.T, issuer string
|
|||||||
t.Logf("cleaning up test FederationDomain %s/%s", federationDomain.Namespace, federationDomain.Name)
|
t.Logf("cleaning up test FederationDomain %s/%s", federationDomain.Namespace, federationDomain.Name)
|
||||||
deleteCtx, cancel := context.WithTimeout(context.Background(), time.Minute)
|
deleteCtx, cancel := context.WithTimeout(context.Background(), time.Minute)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
err := federationDomains.Delete(deleteCtx, federationDomain.Name, metav1.DeleteOptions{})
|
err := federationDomainsClient.Delete(deleteCtx, federationDomain.Name, metav1.DeleteOptions{})
|
||||||
notFound := k8serrors.IsNotFound(err)
|
notFound := k8serrors.IsNotFound(err)
|
||||||
// It's okay if it is not found, because it might have been deleted by another part of this test.
|
// It's okay if it is not found, because it might have been deleted by another part of this test.
|
||||||
if !notFound {
|
if !notFound {
|
||||||
@ -313,22 +319,31 @@ func CreateTestFederationDomain(ctx context.Context, t *testing.T, issuer string
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Wait for the FederationDomain to enter the expected phase (or time out).
|
// Wait for the FederationDomain to enter the expected phase (or time out).
|
||||||
|
WaitForTestFederationDomainStatus(ctx, t, federationDomain.Name, expectStatus)
|
||||||
|
|
||||||
|
return federationDomain
|
||||||
|
}
|
||||||
|
|
||||||
|
func WaitForTestFederationDomainStatus(ctx context.Context, t *testing.T, federationDomainName string, expectStatus configv1alpha1.FederationDomainPhase) {
|
||||||
|
t.Helper()
|
||||||
|
testEnv := IntegrationEnv(t)
|
||||||
|
federationDomainsClient := NewSupervisorClientset(t).ConfigV1alpha1().FederationDomains(testEnv.SupervisorNamespace)
|
||||||
|
|
||||||
var result *configv1alpha1.FederationDomain
|
var result *configv1alpha1.FederationDomain
|
||||||
RequireEventuallyf(t, func(requireEventually *require.Assertions) {
|
RequireEventuallyf(t, func(requireEventually *require.Assertions) {
|
||||||
var err error
|
var err error
|
||||||
result, err = federationDomains.Get(ctx, federationDomain.Name, metav1.GetOptions{})
|
result, err = federationDomainsClient.Get(ctx, federationDomainName, metav1.GetOptions{})
|
||||||
requireEventually.NoError(err)
|
requireEventually.NoError(err)
|
||||||
requireEventually.Equal(expectStatus, result.Status.Status)
|
requireEventually.Equal(expectStatus, result.Status.Phase)
|
||||||
|
|
||||||
// If the FederationDomain was successfully created, ensure all secrets are present before continuing
|
// If the FederationDomain was successfully created, ensure all secrets are present before continuing
|
||||||
if expectStatus == configv1alpha1.SuccessFederationDomainStatusCondition {
|
if expectStatus == configv1alpha1.FederationDomainPhaseReady {
|
||||||
requireEventually.NotEmpty(result.Status.Secrets.JWKS.Name, "expected status.secrets.jwks.name not to be empty")
|
requireEventually.NotEmpty(result.Status.Secrets.JWKS.Name, "expected status.secrets.jwks.name not to be empty")
|
||||||
requireEventually.NotEmpty(result.Status.Secrets.TokenSigningKey.Name, "expected status.secrets.tokenSigningKey.name not to be empty")
|
requireEventually.NotEmpty(result.Status.Secrets.TokenSigningKey.Name, "expected status.secrets.tokenSigningKey.name not to be empty")
|
||||||
requireEventually.NotEmpty(result.Status.Secrets.StateSigningKey.Name, "expected status.secrets.stateSigningKey.name not to be empty")
|
requireEventually.NotEmpty(result.Status.Secrets.StateSigningKey.Name, "expected status.secrets.stateSigningKey.name not to be empty")
|
||||||
requireEventually.NotEmpty(result.Status.Secrets.StateEncryptionKey.Name, "expected status.secrets.stateEncryptionKey.name not to be empty")
|
requireEventually.NotEmpty(result.Status.Secrets.StateEncryptionKey.Name, "expected status.secrets.stateEncryptionKey.name not to be empty")
|
||||||
}
|
}
|
||||||
}, 60*time.Second, 1*time.Second, "expected the FederationDomain to have status %q", expectStatus)
|
}, 60*time.Second, 1*time.Second, "expected the FederationDomain to have status %q", expectStatus)
|
||||||
return federationDomain
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func RandBytes(t *testing.T, numBytes int) []byte {
|
func RandBytes(t *testing.T, numBytes int) []byte {
|
||||||
|
Loading…
Reference in New Issue
Block a user