diff --git a/PROJECT b/PROJECT index 72561db85..486d0e2d5 100644 --- a/PROJECT +++ b/PROJECT @@ -20,4 +20,49 @@ resources: kind: Securesign path: github.com/securesign/operator/api/v1alpha1 version: v1alpha1 +- api: + crdVersion: v1 + namespaced: true + controller: true + domain: redhat.com + group: rhtas + kind: Fulcio + path: github.com/securesign/operator/api/v1alpha1 + version: v1alpha1 +- api: + crdVersion: v1 + namespaced: true + controller: true + domain: redhat.com + group: rhtas + kind: Trillian + path: github.com/securesign/operator/api/v1alpha1 + version: v1alpha1 +- api: + crdVersion: v1 + namespaced: true + controller: true + domain: redhat.com + group: rhtas + kind: Rekor + path: github.com/securesign/operator/api/v1alpha1 + version: v1alpha1 +- api: + crdVersion: v1 + namespaced: true + controller: true + domain: redhat.com + group: rhtas + kind: Tuf + path: github.com/securesign/operator/api/v1alpha1 + version: v1alpha1 +- api: + crdVersion: v1 + namespaced: true + controller: true + domain: redhat.com + group: rhtas + kind: CTlog + path: github.com/securesign/operator/api/v1alpha1 + version: v1alpha1 version: "3" diff --git a/api/v1alpha1/ctlog_types.go b/api/v1alpha1/ctlog_types.go new file mode 100644 index 000000000..59c6ee57a --- /dev/null +++ b/api/v1alpha1/ctlog_types.go @@ -0,0 +1,42 @@ +package v1alpha1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN! +// NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized. + +// CTlogSpec defines the desired state of CTlog +type CTlogSpec struct { +} + +// CTlogStatus defines the observed state of CTlog +type CTlogStatus struct { + Phase Phase `json:"phase"` +} + +//+kubebuilder:object:root=true +//+kubebuilder:subresource:status + +// CTlog is the Schema for the ctlogs API +type CTlog struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec CTlogSpec `json:"spec,omitempty"` + Status CTlogStatus `json:"status,omitempty"` +} + +//+kubebuilder:object:root=true + +// CTlogList contains a list of CTlog +type CTlogList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []CTlog `json:"items"` +} + +func init() { + SchemeBuilder.Register(&CTlog{}, &CTlogList{}) +} diff --git a/api/v1alpha1/fulcio_types.go b/api/v1alpha1/fulcio_types.go new file mode 100644 index 000000000..172ad9a53 --- /dev/null +++ b/api/v1alpha1/fulcio_types.go @@ -0,0 +1,52 @@ +package v1alpha1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN! +// NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized. + +// FulcioSpec defines the desired state of Fulcio +type FulcioSpec struct { + External bool `json:"external,omitempty"` + KeySecret string `json:"keySecret,omitempty"` + OidcIssuers map[string]OidcIssuer `json:"oidcIssuers,omitempty"` +} + +type OidcIssuer struct { + ClientID string `json:"ClientID"` + IssuerURL string `json:"IssuerURL"` + Type string `json:"Type"` +} + +// FulcioStatus defines the observed state of Fulcio +type FulcioStatus struct { + Url string `json:"url,omitempty"` + Phase Phase `json:"Phase,omitempty"` +} + +//+kubebuilder:object:root=true +//+kubebuilder:subresource:status + +// Fulcio is the Schema for the fulcios API +type Fulcio struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec FulcioSpec `json:"spec,omitempty"` + Status FulcioStatus `json:"status,omitempty"` +} + +//+kubebuilder:object:root=true + +// FulcioList contains a list of Fulcio +type FulcioList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []Fulcio `json:"items"` +} + +func init() { + SchemeBuilder.Register(&Fulcio{}, &FulcioList{}) +} diff --git a/api/v1alpha1/phase.go b/api/v1alpha1/phase.go new file mode 100644 index 000000000..b523958d4 --- /dev/null +++ b/api/v1alpha1/phase.go @@ -0,0 +1,12 @@ +package v1alpha1 + +type Phase string + +const ( + PhaseNone Phase = "" + PhaseInitialization Phase = "Initialization" + PhaseReady Phase = "Ready" + PhasePending Phase = "Pending" + PhaseError Phase = "Error" + PhaseDuplicitResource = "DuplicitResource" +) diff --git a/api/v1alpha1/rekor_types.go b/api/v1alpha1/rekor_types.go new file mode 100644 index 000000000..c0a9f5e9e --- /dev/null +++ b/api/v1alpha1/rekor_types.go @@ -0,0 +1,46 @@ +package v1alpha1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN! +// NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized. + +// RekorSpec defines the desired state of Rekor +type RekorSpec struct { + External bool `json:"external,omitempty"` + KeySecret string `json:"keySecret,omitempty"` + PvcName string `json:"pvcName,omitempty"` +} + +// RekorStatus defines the observed state of Rekor +type RekorStatus struct { + Url string `json:"url,omitempty"` + Phase Phase `json:"phase,omitempty"` +} + +//+kubebuilder:object:root=true +//+kubebuilder:subresource:status + +// Rekor is the Schema for the rekors API +type Rekor struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec RekorSpec `json:"spec,omitempty"` + Status RekorStatus `json:"status,omitempty"` +} + +//+kubebuilder:object:root=true + +// RekorList contains a list of Rekor +type RekorList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []Rekor `json:"items"` +} + +func init() { + SchemeBuilder.Register(&Rekor{}, &RekorList{}) +} diff --git a/api/v1alpha1/securesign_types.go b/api/v1alpha1/securesign_types.go index dc19e9d10..b7327f47a 100644 --- a/api/v1alpha1/securesign_types.go +++ b/api/v1alpha1/securesign_types.go @@ -41,17 +41,22 @@ type SecuresignSpec struct { // Important: Run "make" to regenerate code after modifying this file // Foo is an example field of Securesign. Edit securesign_types.go to remove/update - FulcioPublicKey string `json:"fulcioPublicKey,omitempty"` - FulcioPrivateKey string `json:"fulcioPrivateKey,omitempty"` - FulcioCert string `json:"fulcioCert,omitempty"` - FulcioPassword string `json:"fulcioPassword,omitempty"` - RekorPrivateKey string `json:"rekorPrivateKey,omitempty"` + Rekor RekorSpec `json:"rekor"` + Fulcio FulcioSpec `json:"fulcio"` + Trillian TrillianSpec `json:"trillian"` + Tuf TufSpec `json:"tuf"` + Ctlog CTlogSpec `json:"ctlog,omitempty"` } // SecuresignStatus defines the observed state of Securesign type SecuresignStatus struct { // INSERT ADDITIONAL STATUS FIELD - define observed state of cluster // Important: Run "make" to regenerate code after modifying this file + Trillian string `json:"trillian"` + Fulcio string `json:"fulcio"` + Tuf string `json:"tuf"` + CTlog string `json:"ctlog"` + Rekor string `json:"rekor"` } //+kubebuilder:object:root=true diff --git a/api/v1alpha1/trillian_types.go b/api/v1alpha1/trillian_types.go new file mode 100644 index 000000000..108739b6a --- /dev/null +++ b/api/v1alpha1/trillian_types.go @@ -0,0 +1,68 @@ +/* +Copyright 2023. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1alpha1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN! +// NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized. + +// TrillianSpec defines the desired state of Trillian +type TrillianSpec struct { + // INSERT ADDITIONAL SPEC FIELDS - desired state of cluster + // Important: Run "make" to regenerate code after modifying this file + + // Foo is an example field of Trillian. Edit trillian_types.go to remove/update + LogSignerImage string `json:"logSignerImage,omitempty"` + ServerImage string `json:"serverImage,omitempty"` + DbImage string `json:"dbImage,omitempty"` + PvcName string `json:"pvcName,omitempty"` +} + +// TrillianStatus defines the observed state of Trillian +type TrillianStatus struct { + Phase Phase `json:"Phase"` + // INSERT ADDITIONAL STATUS FIELD - define observed state of cluster + // Important: Run "make" to regenerate code after modifying this file +} + +//+kubebuilder:object:root=true +//+kubebuilder:subresource:status + +// Trillian is the Schema for the trillians API +type Trillian struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec TrillianSpec `json:"spec,omitempty"` + Status TrillianStatus `json:"status,omitempty"` +} + +//+kubebuilder:object:root=true + +// TrillianList contains a list of Trillian +type TrillianList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []Trillian `json:"items"` +} + +func init() { + SchemeBuilder.Register(&Trillian{}, &TrillianList{}) +} diff --git a/api/v1alpha1/tuf_types.go b/api/v1alpha1/tuf_types.go new file mode 100644 index 000000000..261b82ba9 --- /dev/null +++ b/api/v1alpha1/tuf_types.go @@ -0,0 +1,45 @@ +package v1alpha1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN! +// NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized. + +// TufSpec defines the desired state of Tuf +type TufSpec struct { + External bool `json:"external,omitempty"` + Image string `json:"image,omitempty"` +} + +// TufStatus defines the observed state of Tuf +type TufStatus struct { + Url string `json:"url,omitempty"` + Phase Phase `json:"Phase"` +} + +//+kubebuilder:object:root=true +//+kubebuilder:subresource:status + +// Tuf is the Schema for the tufs API +type Tuf struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec TufSpec `json:"spec,omitempty"` + Status TufStatus `json:"status,omitempty"` +} + +//+kubebuilder:object:root=true + +// TufList contains a list of Tuf +type TufList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []Tuf `json:"items"` +} + +func init() { + SchemeBuilder.Register(&Tuf{}, &TufList{}) +} diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index 8a7b1e9be..d0108f89f 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -26,7 +26,207 @@ import ( ) // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *Securesign) DeepCopyInto(out *Securesign) { +func (in *CTlog) DeepCopyInto(out *CTlog) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + out.Spec = in.Spec + out.Status = in.Status +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CTlog. +func (in *CTlog) DeepCopy() *CTlog { + if in == nil { + return nil + } + out := new(CTlog) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *CTlog) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CTlogList) DeepCopyInto(out *CTlogList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]CTlog, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CTlogList. +func (in *CTlogList) DeepCopy() *CTlogList { + if in == nil { + return nil + } + out := new(CTlogList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *CTlogList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CTlogSpec) DeepCopyInto(out *CTlogSpec) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CTlogSpec. +func (in *CTlogSpec) DeepCopy() *CTlogSpec { + if in == nil { + return nil + } + out := new(CTlogSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CTlogStatus) DeepCopyInto(out *CTlogStatus) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CTlogStatus. +func (in *CTlogStatus) DeepCopy() *CTlogStatus { + if in == nil { + return nil + } + out := new(CTlogStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Fulcio) DeepCopyInto(out *Fulcio) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + out.Status = in.Status +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Fulcio. +func (in *Fulcio) DeepCopy() *Fulcio { + if in == nil { + return nil + } + out := new(Fulcio) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *Fulcio) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *FulcioList) DeepCopyInto(out *FulcioList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]Fulcio, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FulcioList. +func (in *FulcioList) DeepCopy() *FulcioList { + if in == nil { + return nil + } + out := new(FulcioList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *FulcioList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *FulcioSpec) DeepCopyInto(out *FulcioSpec) { + *out = *in + if in.OidcIssuers != nil { + in, out := &in.OidcIssuers, &out.OidcIssuers + *out = make(map[string]OidcIssuer, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FulcioSpec. +func (in *FulcioSpec) DeepCopy() *FulcioSpec { + if in == nil { + return nil + } + out := new(FulcioSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *FulcioStatus) DeepCopyInto(out *FulcioStatus) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FulcioStatus. +func (in *FulcioStatus) DeepCopy() *FulcioStatus { + if in == nil { + return nil + } + out := new(FulcioStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *OidcIssuer) DeepCopyInto(out *OidcIssuer) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OidcIssuer. +func (in *OidcIssuer) DeepCopy() *OidcIssuer { + if in == nil { + return nil + } + out := new(OidcIssuer) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Rekor) DeepCopyInto(out *Rekor) { *out = *in out.TypeMeta = in.TypeMeta in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) @@ -34,6 +234,95 @@ func (in *Securesign) DeepCopyInto(out *Securesign) { out.Status = in.Status } +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Rekor. +func (in *Rekor) DeepCopy() *Rekor { + if in == nil { + return nil + } + out := new(Rekor) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *Rekor) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *RekorList) DeepCopyInto(out *RekorList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]Rekor, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RekorList. +func (in *RekorList) DeepCopy() *RekorList { + if in == nil { + return nil + } + out := new(RekorList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *RekorList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *RekorSpec) DeepCopyInto(out *RekorSpec) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RekorSpec. +func (in *RekorSpec) DeepCopy() *RekorSpec { + if in == nil { + return nil + } + out := new(RekorSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *RekorStatus) DeepCopyInto(out *RekorStatus) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RekorStatus. +func (in *RekorStatus) DeepCopy() *RekorStatus { + if in == nil { + return nil + } + out := new(RekorStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Securesign) DeepCopyInto(out *Securesign) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + out.Status = in.Status +} + // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Securesign. func (in *Securesign) DeepCopy() *Securesign { if in == nil { @@ -87,6 +376,11 @@ func (in *SecuresignList) DeepCopyObject() runtime.Object { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *SecuresignSpec) DeepCopyInto(out *SecuresignSpec) { *out = *in + out.Rekor = in.Rekor + in.Fulcio.DeepCopyInto(&out.Fulcio) + out.Trillian = in.Trillian + out.Tuf = in.Tuf + out.Ctlog = in.Ctlog } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SecuresignSpec. @@ -113,3 +407,181 @@ func (in *SecuresignStatus) DeepCopy() *SecuresignStatus { in.DeepCopyInto(out) return out } + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Trillian) DeepCopyInto(out *Trillian) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + out.Spec = in.Spec + out.Status = in.Status +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Trillian. +func (in *Trillian) DeepCopy() *Trillian { + if in == nil { + return nil + } + out := new(Trillian) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *Trillian) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TrillianList) DeepCopyInto(out *TrillianList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]Trillian, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TrillianList. +func (in *TrillianList) DeepCopy() *TrillianList { + if in == nil { + return nil + } + out := new(TrillianList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *TrillianList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TrillianSpec) DeepCopyInto(out *TrillianSpec) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TrillianSpec. +func (in *TrillianSpec) DeepCopy() *TrillianSpec { + if in == nil { + return nil + } + out := new(TrillianSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TrillianStatus) DeepCopyInto(out *TrillianStatus) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TrillianStatus. +func (in *TrillianStatus) DeepCopy() *TrillianStatus { + if in == nil { + return nil + } + out := new(TrillianStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Tuf) DeepCopyInto(out *Tuf) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + out.Spec = in.Spec + out.Status = in.Status +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Tuf. +func (in *Tuf) DeepCopy() *Tuf { + if in == nil { + return nil + } + out := new(Tuf) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *Tuf) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TufList) DeepCopyInto(out *TufList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]Tuf, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TufList. +func (in *TufList) DeepCopy() *TufList { + if in == nil { + return nil + } + out := new(TufList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *TufList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TufSpec) DeepCopyInto(out *TufSpec) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TufSpec. +func (in *TufSpec) DeepCopy() *TufSpec { + if in == nil { + return nil + } + out := new(TufSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TufStatus) DeepCopyInto(out *TufStatus) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TufStatus. +func (in *TufStatus) DeepCopy() *TufStatus { + if in == nil { + return nil + } + out := new(TufStatus) + in.DeepCopyInto(out) + return out +} diff --git a/client/client.go b/client/client.go new file mode 100644 index 000000000..11cb3e414 --- /dev/null +++ b/client/client.go @@ -0,0 +1,67 @@ +package client + +import ( + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/client-go/kubernetes" + clientscheme "k8s.io/client-go/kubernetes/scheme" + "k8s.io/client-go/rest" + controller "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/client/config" +) + +// Client is an abstraction for a k8s client. +type Client interface { + controller.Client + kubernetes.Interface + GetScheme() *runtime.Scheme + GetConfig() *rest.Config +} + +type defaultClient struct { + controller.Client + kubernetes.Interface + scheme *runtime.Scheme + config *rest.Config +} + +func (c *defaultClient) GetScheme() *runtime.Scheme { + return c.scheme +} + +func (c *defaultClient) GetConfig() *rest.Config { + return c.config +} + +// NewClient creates a new k8s client that can be used from outside or in the cluster. +func NewClientWithScheme(scheme *runtime.Scheme) (Client, error) { + // Get a config to talk to the apiserver + cfg, err := config.GetConfig() + if err != nil { + return nil, err + } + + var clientset kubernetes.Interface + if clientset, err = kubernetes.NewForConfig(cfg); err != nil { + return nil, err + } + + // Create a new client to avoid using cache (enabled by default on operator-sdk client) + clientOptions := controller.Options{ + Scheme: scheme, + } + dynClient, err := controller.New(cfg, clientOptions) + if err != nil { + return nil, err + } + + return &defaultClient{ + Client: dynClient, + Interface: clientset, + scheme: clientOptions.Scheme, + config: cfg, + }, nil +} + +func NewClient() (Client, error) { + return NewClientWithScheme(clientscheme.Scheme) +} diff --git a/config/crd/bases/rhtas.redhat.com_ctlogs.yaml b/config/crd/bases/rhtas.redhat.com_ctlogs.yaml new file mode 100644 index 000000000..5a2f5cc4e --- /dev/null +++ b/config/crd/bases/rhtas.redhat.com_ctlogs.yaml @@ -0,0 +1,50 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.11.1 + creationTimestamp: null + name: ctlogs.rhtas.redhat.com +spec: + group: rhtas.redhat.com + names: + kind: CTlog + listKind: CTlogList + plural: ctlogs + singular: ctlog + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: CTlog is the Schema for the ctlogs API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: CTlogSpec defines the desired state of CTlog + type: object + status: + description: CTlogStatus defines the observed state of CTlog + properties: + phase: + type: string + required: + - phase + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/config/crd/bases/rhtas.redhat.com_fulcios.yaml b/config/crd/bases/rhtas.redhat.com_fulcios.yaml new file mode 100644 index 000000000..62bcaad0f --- /dev/null +++ b/config/crd/bases/rhtas.redhat.com_fulcios.yaml @@ -0,0 +1,70 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.11.1 + creationTimestamp: null + name: fulcios.rhtas.redhat.com +spec: + group: rhtas.redhat.com + names: + kind: Fulcio + listKind: FulcioList + plural: fulcios + singular: fulcio + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: Fulcio is the Schema for the fulcios API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: FulcioSpec defines the desired state of Fulcio + properties: + external: + type: boolean + keySecret: + type: string + oidcIssuers: + additionalProperties: + properties: + ClientID: + type: string + IssuerURL: + type: string + Type: + type: string + required: + - ClientID + - IssuerURL + - Type + type: object + type: object + type: object + status: + description: FulcioStatus defines the observed state of Fulcio + properties: + Phase: + type: string + url: + type: string + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/config/crd/bases/rhtas.redhat.com_rekors.yaml b/config/crd/bases/rhtas.redhat.com_rekors.yaml new file mode 100644 index 000000000..e4fd9b0c7 --- /dev/null +++ b/config/crd/bases/rhtas.redhat.com_rekors.yaml @@ -0,0 +1,57 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.11.1 + creationTimestamp: null + name: rekors.rhtas.redhat.com +spec: + group: rhtas.redhat.com + names: + kind: Rekor + listKind: RekorList + plural: rekors + singular: rekor + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: Rekor is the Schema for the rekors API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: RekorSpec defines the desired state of Rekor + properties: + external: + type: boolean + keySecret: + type: string + pvcName: + type: string + type: object + status: + description: RekorStatus defines the observed state of Rekor + properties: + phase: + type: string + url: + type: string + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/config/crd/bases/rhtas.redhat.com_securesigns.yaml b/config/crd/bases/rhtas.redhat.com_securesigns.yaml index 92b114248..9ea810615 100644 --- a/config/crd/bases/rhtas.redhat.com_securesigns.yaml +++ b/config/crd/bases/rhtas.redhat.com_securesigns.yaml @@ -35,21 +35,93 @@ spec: spec: description: SecuresignSpec defines the desired state of Securesign properties: - fulcioCert: - type: string - fulcioPassword: - type: string - fulcioPrivateKey: - type: string - fulcioPublicKey: + ctlog: + description: CTlogSpec defines the desired state of CTlog + type: object + fulcio: + description: FulcioSpec defines the desired state of Fulcio + properties: + external: + type: boolean + keySecret: + type: string + oidcIssuers: + additionalProperties: + properties: + ClientID: + type: string + IssuerURL: + type: string + Type: + type: string + required: + - ClientID + - IssuerURL + - Type + type: object + type: object + type: object + rekor: description: Foo is an example field of Securesign. Edit securesign_types.go to remove/update - type: string - rekorPrivateKey: - type: string + properties: + external: + type: boolean + keySecret: + type: string + pvcName: + type: string + type: object + trillian: + description: TrillianSpec defines the desired state of Trillian + properties: + dbImage: + type: string + logSignerImage: + description: Foo is an example field of Trillian. Edit trillian_types.go + to remove/update + type: string + pvcName: + type: string + serverImage: + type: string + type: object + tuf: + description: TufSpec defines the desired state of Tuf + properties: + external: + type: boolean + image: + type: string + type: object + required: + - fulcio + - rekor + - trillian + - tuf type: object status: description: SecuresignStatus defines the observed state of Securesign + properties: + ctlog: + type: string + fulcio: + type: string + rekor: + type: string + trillian: + description: 'INSERT ADDITIONAL STATUS FIELD - define observed state + of cluster Important: Run "make" to regenerate code after modifying + this file' + type: string + tuf: + type: string + required: + - ctlog + - fulcio + - rekor + - trillian + - tuf type: object type: object served: true diff --git a/config/crd/bases/rhtas.redhat.com_trillians.yaml b/config/crd/bases/rhtas.redhat.com_trillians.yaml new file mode 100644 index 000000000..bf12636f4 --- /dev/null +++ b/config/crd/bases/rhtas.redhat.com_trillians.yaml @@ -0,0 +1,61 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.11.1 + creationTimestamp: null + name: trillians.rhtas.redhat.com +spec: + group: rhtas.redhat.com + names: + kind: Trillian + listKind: TrillianList + plural: trillians + singular: trillian + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: Trillian is the Schema for the trillians API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: TrillianSpec defines the desired state of Trillian + properties: + dbImage: + type: string + logSignerImage: + description: Foo is an example field of Trillian. Edit trillian_types.go + to remove/update + type: string + pvcName: + type: string + serverImage: + type: string + type: object + status: + description: TrillianStatus defines the observed state of Trillian + properties: + Phase: + type: string + required: + - Phase + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/config/crd/bases/rhtas.redhat.com_tufs.yaml b/config/crd/bases/rhtas.redhat.com_tufs.yaml new file mode 100644 index 000000000..269021fce --- /dev/null +++ b/config/crd/bases/rhtas.redhat.com_tufs.yaml @@ -0,0 +1,57 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.11.1 + creationTimestamp: null + name: tufs.rhtas.redhat.com +spec: + group: rhtas.redhat.com + names: + kind: Tuf + listKind: TufList + plural: tufs + singular: tuf + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: Tuf is the Schema for the tufs API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: TufSpec defines the desired state of Tuf + properties: + external: + type: boolean + image: + type: string + type: object + status: + description: TufStatus defines the observed state of Tuf + properties: + Phase: + type: string + url: + type: string + required: + - Phase + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/config/crd/kustomization.yaml b/config/crd/kustomization.yaml index 12ea7c913..6f02a8a6f 100644 --- a/config/crd/kustomization.yaml +++ b/config/crd/kustomization.yaml @@ -3,17 +3,32 @@ # It should be run by config/default resources: - bases/rhtas.redhat.com_securesigns.yaml +- bases/rhtas.redhat.com_fulcios.yaml +- bases/rhtas.redhat.com_trillians.yaml +- bases/rhtas.redhat.com_rekors.yaml +- bases/rhtas.redhat.com_tufs.yaml +- bases/rhtas.redhat.com_ctlogs.yaml #+kubebuilder:scaffold:crdkustomizeresource patchesStrategicMerge: # [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] prefix. # patches here are for enabling the conversion webhook for each CRD #- patches/webhook_in_securesigns.yaml +#- patches/webhook_in_fulcios.yaml +#- patches/webhook_in_trillians.yaml +#- patches/webhook_in_rekors.yaml +#- patches/webhook_in_tufs.yaml +#- patches/webhook_in_ctlogs.yaml #+kubebuilder:scaffold:crdkustomizewebhookpatch # [CERTMANAGER] To enable cert-manager, uncomment all the sections with [CERTMANAGER] prefix. # patches here are for enabling the CA injection for each CRD #- patches/cainjection_in_securesigns.yaml +#- patches/cainjection_in_fulcios.yaml +#- patches/cainjection_in_trillians.yaml +#- patches/cainjection_in_rekors.yaml +#- patches/cainjection_in_tufs.yaml +#- patches/cainjection_in_ctlogs.yaml #+kubebuilder:scaffold:crdkustomizecainjectionpatch # the following config is for teaching kustomize how to do kustomization for CRDs. diff --git a/config/crd/patches/cainjection_in_ctlogs.yaml b/config/crd/patches/cainjection_in_ctlogs.yaml new file mode 100644 index 000000000..ccb961338 --- /dev/null +++ b/config/crd/patches/cainjection_in_ctlogs.yaml @@ -0,0 +1,7 @@ +# The following patch adds a directive for certmanager to inject CA into the CRD +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + cert-manager.io/inject-ca-from: $(CERTIFICATE_NAMESPACE)/$(CERTIFICATE_NAME) + name: ctlogs.rhtas.redhat.com diff --git a/config/crd/patches/cainjection_in_fulcios.yaml b/config/crd/patches/cainjection_in_fulcios.yaml new file mode 100644 index 000000000..e0775aeff --- /dev/null +++ b/config/crd/patches/cainjection_in_fulcios.yaml @@ -0,0 +1,7 @@ +# The following patch adds a directive for certmanager to inject CA into the CRD +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + cert-manager.io/inject-ca-from: $(CERTIFICATE_NAMESPACE)/$(CERTIFICATE_NAME) + name: fulcios.rhtas.redhat.com diff --git a/config/crd/patches/cainjection_in_rekors.yaml b/config/crd/patches/cainjection_in_rekors.yaml new file mode 100644 index 000000000..b04d8da34 --- /dev/null +++ b/config/crd/patches/cainjection_in_rekors.yaml @@ -0,0 +1,7 @@ +# The following patch adds a directive for certmanager to inject CA into the CRD +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + cert-manager.io/inject-ca-from: $(CERTIFICATE_NAMESPACE)/$(CERTIFICATE_NAME) + name: rekors.rhtas.redhat.com diff --git a/config/crd/patches/cainjection_in_trillians.yaml b/config/crd/patches/cainjection_in_trillians.yaml new file mode 100644 index 000000000..079008638 --- /dev/null +++ b/config/crd/patches/cainjection_in_trillians.yaml @@ -0,0 +1,7 @@ +# The following patch adds a directive for certmanager to inject CA into the CRD +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + cert-manager.io/inject-ca-from: $(CERTIFICATE_NAMESPACE)/$(CERTIFICATE_NAME) + name: trillians.rhtas.redhat.com diff --git a/config/crd/patches/cainjection_in_tufs.yaml b/config/crd/patches/cainjection_in_tufs.yaml new file mode 100644 index 000000000..8ac240930 --- /dev/null +++ b/config/crd/patches/cainjection_in_tufs.yaml @@ -0,0 +1,7 @@ +# The following patch adds a directive for certmanager to inject CA into the CRD +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + cert-manager.io/inject-ca-from: $(CERTIFICATE_NAMESPACE)/$(CERTIFICATE_NAME) + name: tufs.rhtas.redhat.com diff --git a/config/crd/patches/webhook_in_ctlogs.yaml b/config/crd/patches/webhook_in_ctlogs.yaml new file mode 100644 index 000000000..adfc3b3c3 --- /dev/null +++ b/config/crd/patches/webhook_in_ctlogs.yaml @@ -0,0 +1,16 @@ +# The following patch enables a conversion webhook for the CRD +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: ctlogs.rhtas.redhat.com +spec: + conversion: + strategy: Webhook + webhook: + clientConfig: + service: + namespace: system + name: webhook-service + path: /convert + conversionReviewVersions: + - v1 diff --git a/config/crd/patches/webhook_in_fulcios.yaml b/config/crd/patches/webhook_in_fulcios.yaml new file mode 100644 index 000000000..e65c410d4 --- /dev/null +++ b/config/crd/patches/webhook_in_fulcios.yaml @@ -0,0 +1,16 @@ +# The following patch enables a conversion webhook for the CRD +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: fulcios.rhtas.redhat.com +spec: + conversion: + strategy: Webhook + webhook: + clientConfig: + service: + namespace: system + name: webhook-service + path: /convert + conversionReviewVersions: + - v1 diff --git a/config/crd/patches/webhook_in_rekors.yaml b/config/crd/patches/webhook_in_rekors.yaml new file mode 100644 index 000000000..1acce10e4 --- /dev/null +++ b/config/crd/patches/webhook_in_rekors.yaml @@ -0,0 +1,16 @@ +# The following patch enables a conversion webhook for the CRD +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: rekors.rhtas.redhat.com +spec: + conversion: + strategy: Webhook + webhook: + clientConfig: + service: + namespace: system + name: webhook-service + path: /convert + conversionReviewVersions: + - v1 diff --git a/config/crd/patches/webhook_in_trillians.yaml b/config/crd/patches/webhook_in_trillians.yaml new file mode 100644 index 000000000..71249ada1 --- /dev/null +++ b/config/crd/patches/webhook_in_trillians.yaml @@ -0,0 +1,16 @@ +# The following patch enables a conversion webhook for the CRD +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: trillians.rhtas.redhat.com +spec: + conversion: + strategy: Webhook + webhook: + clientConfig: + service: + namespace: system + name: webhook-service + path: /convert + conversionReviewVersions: + - v1 diff --git a/config/crd/patches/webhook_in_tufs.yaml b/config/crd/patches/webhook_in_tufs.yaml new file mode 100644 index 000000000..c2b5e092a --- /dev/null +++ b/config/crd/patches/webhook_in_tufs.yaml @@ -0,0 +1,16 @@ +# The following patch enables a conversion webhook for the CRD +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: tufs.rhtas.redhat.com +spec: + conversion: + strategy: Webhook + webhook: + clientConfig: + service: + namespace: system + name: webhook-service + path: /convert + conversionReviewVersions: + - v1 diff --git a/config/manager/kustomization.yaml b/config/manager/kustomization.yaml index 10adbf7d5..d39e142ae 100644 --- a/config/manager/kustomization.yaml +++ b/config/manager/kustomization.yaml @@ -4,5 +4,5 @@ apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization images: - name: controller - newName: quay.io/rcook/securesign-controller + newName: quay.io/jbouska/securesign-controller newTag: latest diff --git a/config/rbac/ctlog_editor_role.yaml b/config/rbac/ctlog_editor_role.yaml new file mode 100644 index 000000000..dc5905896 --- /dev/null +++ b/config/rbac/ctlog_editor_role.yaml @@ -0,0 +1,31 @@ +# permissions for end users to edit ctlogs. +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + app.kubernetes.io/name: clusterrole + app.kubernetes.io/instance: ctlog-editor-role + app.kubernetes.io/component: rbac + app.kubernetes.io/created-by: operator + app.kubernetes.io/part-of: operator + app.kubernetes.io/managed-by: kustomize + name: ctlog-editor-role +rules: +- apiGroups: + - rhtas.redhat.com + resources: + - ctlogs + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - rhtas.redhat.com + resources: + - ctlogs/status + verbs: + - get diff --git a/config/rbac/ctlog_viewer_role.yaml b/config/rbac/ctlog_viewer_role.yaml new file mode 100644 index 000000000..15f6555cd --- /dev/null +++ b/config/rbac/ctlog_viewer_role.yaml @@ -0,0 +1,27 @@ +# permissions for end users to view ctlogs. +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + app.kubernetes.io/name: clusterrole + app.kubernetes.io/instance: ctlog-viewer-role + app.kubernetes.io/component: rbac + app.kubernetes.io/created-by: operator + app.kubernetes.io/part-of: operator + app.kubernetes.io/managed-by: kustomize + name: ctlog-viewer-role +rules: +- apiGroups: + - rhtas.redhat.com + resources: + - ctlogs + verbs: + - get + - list + - watch +- apiGroups: + - rhtas.redhat.com + resources: + - ctlogs/status + verbs: + - get diff --git a/config/rbac/fulcio_editor_role.yaml b/config/rbac/fulcio_editor_role.yaml new file mode 100644 index 000000000..5edaeaa6b --- /dev/null +++ b/config/rbac/fulcio_editor_role.yaml @@ -0,0 +1,31 @@ +# permissions for end users to edit fulcios. +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + app.kubernetes.io/name: clusterrole + app.kubernetes.io/instance: fulcio-editor-role + app.kubernetes.io/component: rbac + app.kubernetes.io/created-by: operator + app.kubernetes.io/part-of: operator + app.kubernetes.io/managed-by: kustomize + name: fulcio-editor-role +rules: +- apiGroups: + - rhtas.redhat.com + resources: + - fulcios + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - rhtas.redhat.com + resources: + - fulcios/status + verbs: + - get diff --git a/config/rbac/fulcio_viewer_role.yaml b/config/rbac/fulcio_viewer_role.yaml new file mode 100644 index 000000000..0c1f6aa35 --- /dev/null +++ b/config/rbac/fulcio_viewer_role.yaml @@ -0,0 +1,27 @@ +# permissions for end users to view fulcios. +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + app.kubernetes.io/name: clusterrole + app.kubernetes.io/instance: fulcio-viewer-role + app.kubernetes.io/component: rbac + app.kubernetes.io/created-by: operator + app.kubernetes.io/part-of: operator + app.kubernetes.io/managed-by: kustomize + name: fulcio-viewer-role +rules: +- apiGroups: + - rhtas.redhat.com + resources: + - fulcios + verbs: + - get + - list + - watch +- apiGroups: + - rhtas.redhat.com + resources: + - fulcios/status + verbs: + - get diff --git a/config/rbac/rekor_editor_role.yaml b/config/rbac/rekor_editor_role.yaml new file mode 100644 index 000000000..e18126e4e --- /dev/null +++ b/config/rbac/rekor_editor_role.yaml @@ -0,0 +1,31 @@ +# permissions for end users to edit rekors. +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + app.kubernetes.io/name: clusterrole + app.kubernetes.io/instance: rekor-editor-role + app.kubernetes.io/component: rbac + app.kubernetes.io/created-by: operator + app.kubernetes.io/part-of: operator + app.kubernetes.io/managed-by: kustomize + name: rekor-editor-role +rules: +- apiGroups: + - rhtas.redhat.com + resources: + - rekors + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - rhtas.redhat.com + resources: + - rekors/status + verbs: + - get diff --git a/config/rbac/rekor_viewer_role.yaml b/config/rbac/rekor_viewer_role.yaml new file mode 100644 index 000000000..e391ee38f --- /dev/null +++ b/config/rbac/rekor_viewer_role.yaml @@ -0,0 +1,27 @@ +# permissions for end users to view rekors. +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + app.kubernetes.io/name: clusterrole + app.kubernetes.io/instance: rekor-viewer-role + app.kubernetes.io/component: rbac + app.kubernetes.io/created-by: operator + app.kubernetes.io/part-of: operator + app.kubernetes.io/managed-by: kustomize + name: rekor-viewer-role +rules: +- apiGroups: + - rhtas.redhat.com + resources: + - rekors + verbs: + - get + - list + - watch +- apiGroups: + - rhtas.redhat.com + resources: + - rekors/status + verbs: + - get diff --git a/config/rbac/role.yaml b/config/rbac/role.yaml index 189eab5a4..3a63f7521 100644 --- a/config/rbac/role.yaml +++ b/config/rbac/role.yaml @@ -161,6 +161,84 @@ rules: - patch - update - watch +- apiGroups: + - rhtas.redhat.com + resources: + - ctlogs + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - rhtas.redhat.com + resources: + - ctlogs/finalizers + verbs: + - update +- apiGroups: + - rhtas.redhat.com + resources: + - ctlogs/status + verbs: + - get + - patch + - update +- apiGroups: + - rhtas.redhat.com + resources: + - fulcios + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - rhtas.redhat.com + resources: + - fulcios/finalizers + verbs: + - update +- apiGroups: + - rhtas.redhat.com + resources: + - fulcios/status + verbs: + - get + - patch + - update +- apiGroups: + - rhtas.redhat.com + resources: + - rekors + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - rhtas.redhat.com + resources: + - rekors/finalizers + verbs: + - update +- apiGroups: + - rhtas.redhat.com + resources: + - rekors/status + verbs: + - get + - patch + - update - apiGroups: - rhtas.redhat.com resources: @@ -187,3 +265,55 @@ rules: - get - patch - update +- apiGroups: + - rhtas.redhat.com + resources: + - trillians + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - rhtas.redhat.com + resources: + - trillians/finalizers + verbs: + - update +- apiGroups: + - rhtas.redhat.com + resources: + - trillians/status + verbs: + - get + - patch + - update +- apiGroups: + - rhtas.redhat.com + resources: + - tufs + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - rhtas.redhat.com + resources: + - tufs/finalizers + verbs: + - update +- apiGroups: + - rhtas.redhat.com + resources: + - tufs/status + verbs: + - get + - patch + - update diff --git a/config/rbac/trillian_editor_role.yaml b/config/rbac/trillian_editor_role.yaml new file mode 100644 index 000000000..6c54cec6f --- /dev/null +++ b/config/rbac/trillian_editor_role.yaml @@ -0,0 +1,31 @@ +# permissions for end users to edit trillians. +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + app.kubernetes.io/name: clusterrole + app.kubernetes.io/instance: trillian-editor-role + app.kubernetes.io/component: rbac + app.kubernetes.io/created-by: operator + app.kubernetes.io/part-of: operator + app.kubernetes.io/managed-by: kustomize + name: trillian-editor-role +rules: +- apiGroups: + - rhtas.redhat.com + resources: + - trillians + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - rhtas.redhat.com + resources: + - trillians/status + verbs: + - get diff --git a/config/rbac/trillian_viewer_role.yaml b/config/rbac/trillian_viewer_role.yaml new file mode 100644 index 000000000..e9bbce4fe --- /dev/null +++ b/config/rbac/trillian_viewer_role.yaml @@ -0,0 +1,27 @@ +# permissions for end users to view trillians. +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + app.kubernetes.io/name: clusterrole + app.kubernetes.io/instance: trillian-viewer-role + app.kubernetes.io/component: rbac + app.kubernetes.io/created-by: operator + app.kubernetes.io/part-of: operator + app.kubernetes.io/managed-by: kustomize + name: trillian-viewer-role +rules: +- apiGroups: + - rhtas.redhat.com + resources: + - trillians + verbs: + - get + - list + - watch +- apiGroups: + - rhtas.redhat.com + resources: + - trillians/status + verbs: + - get diff --git a/config/rbac/tuf_editor_role.yaml b/config/rbac/tuf_editor_role.yaml new file mode 100644 index 000000000..b5e5ef82c --- /dev/null +++ b/config/rbac/tuf_editor_role.yaml @@ -0,0 +1,31 @@ +# permissions for end users to edit tufs. +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + app.kubernetes.io/name: clusterrole + app.kubernetes.io/instance: tuf-editor-role + app.kubernetes.io/component: rbac + app.kubernetes.io/created-by: operator + app.kubernetes.io/part-of: operator + app.kubernetes.io/managed-by: kustomize + name: tuf-editor-role +rules: +- apiGroups: + - rhtas.redhat.com + resources: + - tufs + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - rhtas.redhat.com + resources: + - tufs/status + verbs: + - get diff --git a/config/rbac/tuf_viewer_role.yaml b/config/rbac/tuf_viewer_role.yaml new file mode 100644 index 000000000..9594ec99a --- /dev/null +++ b/config/rbac/tuf_viewer_role.yaml @@ -0,0 +1,27 @@ +# permissions for end users to view tufs. +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + app.kubernetes.io/name: clusterrole + app.kubernetes.io/instance: tuf-viewer-role + app.kubernetes.io/component: rbac + app.kubernetes.io/created-by: operator + app.kubernetes.io/part-of: operator + app.kubernetes.io/managed-by: kustomize + name: tuf-viewer-role +rules: +- apiGroups: + - rhtas.redhat.com + resources: + - tufs + verbs: + - get + - list + - watch +- apiGroups: + - rhtas.redhat.com + resources: + - tufs/status + verbs: + - get diff --git a/config/samples/kustomization.yaml b/config/samples/kustomization.yaml index 75d2e0278..ed4fb421c 100644 --- a/config/samples/kustomization.yaml +++ b/config/samples/kustomization.yaml @@ -1,4 +1,9 @@ ## Append samples you want in your CSV to this file as resources ## resources: - rhtas_v1alpha1_securesign.yaml +- rhtas_v1alpha1_fulcio.yaml +- rhtas_v1alpha1_trillian.yaml +- rhtas_v1alpha1_rekor.yaml +- rhtas_v1alpha1_tuf.yaml +- rhtas_v1alpha1_ctlog.yaml #+kubebuilder:scaffold:manifestskustomizesamples diff --git a/config/samples/rhtas_v1alpha1_ctlog.yaml b/config/samples/rhtas_v1alpha1_ctlog.yaml new file mode 100644 index 000000000..fbd70a736 --- /dev/null +++ b/config/samples/rhtas_v1alpha1_ctlog.yaml @@ -0,0 +1,12 @@ +apiVersion: rhtas.redhat.com/v1alpha1 +kind: CTlog +metadata: + labels: + app.kubernetes.io/name: ctlog + app.kubernetes.io/instance: ctlog-sample + app.kubernetes.io/part-of: operator + app.kubernetes.io/managed-by: kustomize + app.kubernetes.io/created-by: operator + name: ctlog-sample +spec: + # TODO(user): Add fields here diff --git a/config/samples/rhtas_v1alpha1_fulcio.yaml b/config/samples/rhtas_v1alpha1_fulcio.yaml new file mode 100644 index 000000000..b89fae9e6 --- /dev/null +++ b/config/samples/rhtas_v1alpha1_fulcio.yaml @@ -0,0 +1,12 @@ +apiVersion: rhtas.redhat.com/v1alpha1 +kind: Fulcio +metadata: + labels: + app.kubernetes.io/name: fulcio + app.kubernetes.io/instance: fulcio-sample + app.kubernetes.io/part-of: operator + app.kubernetes.io/managed-by: kustomize + app.kubernetes.io/created-by: operator + name: fulcio-sample +spec: + # TODO(user): Add fields here diff --git a/config/samples/rhtas_v1alpha1_rekor.yaml b/config/samples/rhtas_v1alpha1_rekor.yaml new file mode 100644 index 000000000..b7104c5c0 --- /dev/null +++ b/config/samples/rhtas_v1alpha1_rekor.yaml @@ -0,0 +1,17 @@ +apiVersion: rhtas.redhat.com/v1alpha1 +kind: Rekor +metadata: + labels: + app.kubernetes.io/name: rekor + app.kubernetes.io/instance: rekor-sample + app.kubernetes.io/part-of: operator + app.kubernetes.io/managed-by: kustomize + app.kubernetes.io/created-by: operator + name: rekor-sample +spec: + privateKey: | + -----BEGIN EC PRIVATE KEY----- + MHcCAQEEICnmFR7rXoJ3QujB9SzrKbVtXCikPXtEb2rs8EGgzYrSoAoGCCqGSM49 + AwEHoUQDQgAEnItR5lDp+1fPho5A2npEr9CygZ3lVGXB6jc0MAS/bez9PxUlPacS + XrlASWbaMaLIoporoKnYhoGHd1oiiVq1lg== + -----END EC PRIVATE KEY----- diff --git a/config/samples/rhtas_v1alpha1_securesign.yaml b/config/samples/rhtas_v1alpha1_securesign.yaml index 6ac26f90c..950f95d39 100644 --- a/config/samples/rhtas_v1alpha1_securesign.yaml +++ b/config/samples/rhtas_v1alpha1_securesign.yaml @@ -9,9 +9,21 @@ metadata: app.kubernetes.io/created-by: operator name: securesign-sample spec: - rekorPrivateKey: | #notsecret - -----BEGIN EC PRIVATE KEY----- - MHcCAQEEICnmFR7rXoJ3QujB9SzrKbVtXCikPXtEb2rs8EGgzYrSoAoGCCqGSM49 - AwEHoUQDQgAEnItR5lDp+1fPho5A2npEr9CygZ3lVGXB6jc0MAS/bez9PxUlPacS - XrlASWbaMaLIoporoKnYhoGHd1oiiVq1lg== - -----END EC PRIVATE KEY----- + rekor: + keySecret: rekor-private-key + fulcio: + keySecret: fulcio-secret-rh + oidcIssuers: + "https://keycloak-keycloak-system.apps.rosa.rurxw-fanw5-w4s.ri89.p3.openshiftapps.com/auth/realms/sigstore": + ClientID: "sigstore" + IssuerURL: "https://keycloak-keycloak-system.apps.rosa.rurxw-fanw5-w4s.ri89.p3.openshiftapps.com/auth/realms/sigstore" + Type: "email" + + trillian: + serverImage: "registry.redhat.io/rhtas-tech-preview/trillian-logserver-rhel9@sha256:43bfc6b7b8ed902592f19b830103d9030b59862f959c97c376cededba2ac3a03" + dbImage: "registry.redhat.io/rhtas-tech-preview/trillian-database-rhel9@sha256:fe4758ff57a9a6943a4655b21af63fb579384dc51838af85d0089c04290b4957" + logSignerImage: "registry.redhat.io/rhtas-tech-preview/trillian-logsigner-rhel9@sha256:fa2717c1d54400ca74cc3e9038bdf332fa834c0f5bc3215139c2d0e3579fc292" + tuf: + image: "registry.redhat.io/rhtas-tech-preview/tuf-server-rhel9@sha256:413e361de99f09e617084438b2fc3c9c477f4a8e2cd65bd5f48271e66d57a9d9" + ctlog: + diff --git a/config/samples/rhtas_v1alpha1_trillian.yaml b/config/samples/rhtas_v1alpha1_trillian.yaml new file mode 100644 index 000000000..1307ba0db --- /dev/null +++ b/config/samples/rhtas_v1alpha1_trillian.yaml @@ -0,0 +1,12 @@ +apiVersion: rhtas.redhat.com/v1alpha1 +kind: Trillian +metadata: + labels: + app.kubernetes.io/name: trillian + app.kubernetes.io/instance: trillian-sample + app.kubernetes.io/part-of: operator + app.kubernetes.io/managed-by: kustomize + app.kubernetes.io/created-by: operator + name: trillian-sample +spec: + # TODO(user): Add fields here diff --git a/config/samples/rhtas_v1alpha1_tuf.yaml b/config/samples/rhtas_v1alpha1_tuf.yaml new file mode 100644 index 000000000..a658b064e --- /dev/null +++ b/config/samples/rhtas_v1alpha1_tuf.yaml @@ -0,0 +1,12 @@ +apiVersion: rhtas.redhat.com/v1alpha1 +kind: Tuf +metadata: + labels: + app.kubernetes.io/name: tuf + app.kubernetes.io/instance: tuf-sample + app.kubernetes.io/part-of: operator + app.kubernetes.io/managed-by: kustomize + app.kubernetes.io/created-by: operator + name: tuf-sample +spec: + # TODO(user): Add fields here diff --git a/controllers/cluster_role.go b/controllers/cluster_role.go deleted file mode 100644 index b81cb2d37..000000000 --- a/controllers/cluster_role.go +++ /dev/null @@ -1,45 +0,0 @@ -package controllers - -import ( - "context" - - client "sigs.k8s.io/controller-runtime/pkg/client" - - rhtasv1alpha1 "github.com/securesign/operator/api/v1alpha1" - rbac "k8s.io/api/rbac/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - ctrllog "sigs.k8s.io/controller-runtime/pkg/log" -) - -func (r *SecuresignReconciler) ensureClusterRole(ctx context.Context, securesign *rhtasv1alpha1.Securesign, roleName string) (*rbac.ClusterRole, error) { - log := ctrllog.FromContext(ctx) - - role := &rbac.ClusterRole{ - ObjectMeta: metav1.ObjectMeta{ - Name: roleName, - }, - Rules: []rbac.PolicyRule{ - { - APIGroups: []string{""}, - Resources: []string{"secrets"}, - Verbs: []string{"get", "create"}, - }, - { - APIGroups: []string{"apps"}, - Resources: []string{"deployments"}, - Verbs: []string{"get", "list"}, - }, - }, - } - - err := r.Get(ctx, client.ObjectKey{Name: roleName}, role) - if err != nil { - log.Info("Creating ClusterRole", "ClusterRole.Namespace", role.Namespace, "ClusterRole.Name", role.Name) - err = r.Create(ctx, role) - if err != nil { - log.Error(err, "Failed to create new ClusterRole", "ClusterRole.Namespace", role.Namespace, "ClusterRole.Name", role.Name) - return nil, err - } - } - return role, nil -} diff --git a/controllers/common/base_action.go b/controllers/common/base_action.go new file mode 100644 index 000000000..19ad3fc28 --- /dev/null +++ b/controllers/common/base_action.go @@ -0,0 +1,19 @@ +package common + +import ( + "k8s.io/client-go/tools/record" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +type BaseAction struct { + Client client.Client + Recorder record.EventRecorder +} + +func (action *BaseAction) InjectClient(client client.Client) { + action.Client = client +} + +func (action *BaseAction) InjectRecorder(recorder record.EventRecorder) { + action.Recorder = recorder +} diff --git a/controllers/common/utils/deployment.go b/controllers/common/utils/deployment.go new file mode 100644 index 000000000..c9024fe9c --- /dev/null +++ b/controllers/common/utils/deployment.go @@ -0,0 +1,23 @@ +package utils + +import ( + "context" + "fmt" + + v1 "k8s.io/api/apps/v1" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +func DeploymentIsRunning(ctx context.Context, cli client.Client, namespace string, name string) (bool, error) { + var err error + d := &v1.Deployment{} + + // TODO: use object references instead hardcoded names + if err = cli.Get(ctx, client.ObjectKey{ + Namespace: namespace, + Name: name, + }, d); err != nil { + return false, fmt.Errorf("%s deployment in error state %s", name, err) + } + return d.Status.ReadyReplicas == *d.Spec.Replicas, nil +} diff --git a/controllers/common/utils/pvc.go b/controllers/common/utils/pvc.go new file mode 100644 index 000000000..62cdfb8a7 --- /dev/null +++ b/controllers/common/utils/pvc.go @@ -0,0 +1,26 @@ +package utils + +import ( + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/resource" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +func CreatePVC(namespace string, pvcName string, pvcSize string) *corev1.PersistentVolumeClaim { + return &corev1.PersistentVolumeClaim{ + ObjectMeta: metav1.ObjectMeta{ + Name: pvcName, + Namespace: namespace, + }, + Spec: corev1.PersistentVolumeClaimSpec{ + AccessModes: []corev1.PersistentVolumeAccessMode{ + "ReadWriteOnce", + }, + Resources: corev1.ResourceRequirements{ + Requests: corev1.ResourceList{ + corev1.ResourceName(corev1.ResourceStorage): resource.MustParse(pvcSize), + }, + }, + }, + } +} diff --git a/controllers/common/utils/route.go b/controllers/common/utils/route.go new file mode 100644 index 000000000..94a4360b9 --- /dev/null +++ b/controllers/common/utils/route.go @@ -0,0 +1,27 @@ +package utils + +import ( + "context" + + routev1 "github.com/openshift/api/route/v1" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +func Expose(ctx context.Context, cli client.Client, svcName string, port string) *routev1.Route { + + // TODO + //return &routev1.Route{ + // ObjectMeta: metav1.ObjectMeta{ + // Name: "", + // Namespace: "", + // }, + // Spec: routev1.RouteSpec{ + // To: routev1.RouteTargetReference{}, + // Port: &routev1.RoutePort{TargetPort: intstr.FromString(port)}, + // TLS: nil, + // WildcardPolicy: "", + // }, + //} + + return nil +} diff --git a/controllers/common/utils/service.go b/controllers/common/utils/service.go new file mode 100644 index 000000000..70b36a117 --- /dev/null +++ b/controllers/common/utils/service.go @@ -0,0 +1,37 @@ +package utils + +import ( + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + "k8s.io/apimachinery/pkg/util/intstr" +) + +func CreateService(namespace string, name string, component string, app string, port int) *corev1.Service { + return &corev1.Service{ + ObjectMeta: metav1.ObjectMeta{ + Name: name, + Namespace: namespace, + Labels: map[string]string{ + "app.kubernetes.io/component": component, + "app.kubernetes.io/name": app, + "app.kubernetes.io/instance": "trusted-artifact-signer", + }, + }, + Spec: corev1.ServiceSpec{ + Selector: map[string]string{ + "app.kubernetes.io/component": component, + "app.kubernetes.io/name": app, + "app.kubernetes.io/instance": "trusted-artifact-signer", + }, + Ports: []corev1.ServicePort{ + { + Name: name, + Protocol: corev1.ProtocolTCP, + Port: int32(port), + TargetPort: intstr.FromInt(port), + }, + }, + }, + } +} diff --git a/controllers/configmap.go b/controllers/configmap.go deleted file mode 100644 index c6e72fe3b..000000000 --- a/controllers/configmap.go +++ /dev/null @@ -1,60 +0,0 @@ -package controllers - -import ( - "context" - - client "sigs.k8s.io/controller-runtime/pkg/client" - - rhtasv1alpha1 "github.com/securesign/operator/api/v1alpha1" - corev1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - ctrllog "sigs.k8s.io/controller-runtime/pkg/log" -) - -func (r *SecuresignReconciler) ensureConfigMap(ctx context.Context, m *rhtasv1alpha1.Securesign, namespace string, configMapName string, component string) (*corev1.ConfigMap, - error) { - log := ctrllog.FromContext(ctx) - log.Info("ensuring configmap") - // Define a new ConfigMap object - configMap := &corev1.ConfigMap{ - ObjectMeta: metav1.ObjectMeta{ - Name: configMapName, - Namespace: namespace, - Labels: map[string]string{ - "app.kubernetes.io/name": component, - "app.kubernetes.io/instance": "trusted-artifact-signer", - }, - }, - Data: map[string]string{ - "__placeholder": "###################################################################\n" + - "# Just a placeholder so that reapplying this won't overwrite treeID\n" + - "# if it already exists. This caused grief, do not remove.\n" + - "###################################################################", - }, - } - - /* - data: - sharding-config.yaml: | - */ - // If the configMapName is rekor-sharding-config then replace the data with the sharding-config.yaml - if configMapName == "rekor-sharding-config" { - configMap.Data = map[string]string{ - "sharding-config.yaml": "" + - "", - } - } - - // Check if this ConfigMap already exists else create it in the namespace - err := r.Get(ctx, client.ObjectKey{Name: configMap.Name, Namespace: namespace}, configMap) - // If the ConfigMap doesn't exist, create it but if it does, do nothing - if err != nil { - log.Info("Creating a new ConfigMap") - err = r.Create(ctx, configMap) - if err != nil { - log.Error(err, "Failed to create new ConfigMap") - return nil, err - } - } - return configMap, nil -} diff --git a/controllers/create_tree_job.go b/controllers/create_tree_job.go deleted file mode 100644 index d762ef525..000000000 --- a/controllers/create_tree_job.go +++ /dev/null @@ -1,94 +0,0 @@ -package controllers - -import ( - "context" - - client "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/log" - - rhtasv1alpha1 "github.com/securesign/operator/api/v1alpha1" - batch "k8s.io/api/batch/v1" - core "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -func (r *SecuresignReconciler) ensureCTJob(ctx context.Context, m *rhtasv1alpha1.Securesign, namespace string, sA string, component string, jobName string, trn string) (*batch.Job, - error) { - log := log.FromContext(ctx) - imageName := "registry.redhat.io/rhtas-tech-preview/createtree-rhel9@sha256:8a80def74e850f2b4c73690f86669a1fe52c1043c175610750abb4644e63d4ab" - log.Info("ensuring job") - // Define a new Namespace object - job := &batch.Job{ - ObjectMeta: metav1.ObjectMeta{ - Name: jobName, - Namespace: namespace, - Labels: map[string]string{ - "app.kubernetes.io/component": "server", - "app.kubernetes.io/instance": "trusted-artifact-signer", - "app.kubernetes.io/name": component, - }, - }, - Spec: batch.JobSpec{ - Template: core.PodTemplateSpec{ - ObjectMeta: metav1.ObjectMeta{ - Labels: map[string]string{ - "app.kubernetes.io/component": "server", - "app.kubernetes.io/instance": "trusted-artifact-signer", - "app.kubernetes.io/name": component, - }, - }, - Spec: core.PodSpec{ - ServiceAccountName: sA, - RestartPolicy: core.RestartPolicyNever, - Containers: []core.Container{ - { - Name: "trusted-artifact-signer-rekor-createtree", - Image: imageName, - Args: []string{ - "--namespace=$(NAMESPACE)", - "--configmap=" + component + "-config", - "--display_name=" + component + "tree", - "--admin_server=trillian-logserver." + trn + ":8091", - "--force=false", - }, - Env: []core.EnvVar{ - { - Name: "NAMESPACE", - ValueFrom: &core.EnvVarSource{ - FieldRef: &core.ObjectFieldSelector{ - FieldPath: "metadata.namespace", - }, - }, - }, - }, - Resources: core.ResourceRequirements{}, - }, - }, - }, - }, - }, - } - - // if jobName is ctlog-createtree remove the arg --force=false - if jobName == "ctlog-createtree" { - job.Spec.Template.Spec.Containers[0].Args = []string{ - "--namespace=$(NAMESPACE)", - "--configmap=" + component + "-config", - "--display_name=" + component + "tree", - "--admin_server=trillian-logserver." + trn + ":8091", - } - } - - // Check if this Job already exists else create it - err := r.Get(ctx, client.ObjectKey{Name: job.Name, Namespace: namespace}, job) - // If the Job doesn't exist, create it but if it does, do nothing - if err != nil { - log.Info("Creating a new Job") - err = r.Create(ctx, job) - if err != nil { - log.Error(err, "Failed to create new Job") - return nil, err - } - } - return job, nil -} diff --git a/controllers/createdb_job.go b/controllers/createdb_job.go deleted file mode 100644 index a36a84abc..000000000 --- a/controllers/createdb_job.go +++ /dev/null @@ -1,113 +0,0 @@ -package controllers - -import ( - "context" - - client "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/log" - - rhtasv1alpha1 "github.com/securesign/operator/api/v1alpha1" - batch "k8s.io/api/batch/v1" - core "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -func (r *SecuresignReconciler) ensureCreateDbJob(ctx context.Context, m *rhtasv1alpha1.Securesign, namespace string, sA string, component string, jobName string, dbsecret string) (*batch.Job, - error) { - log := log.FromContext(ctx) - imageName := "registry.redhat.io/rhtas-tech-preview/createdb-rhel9@sha256:c2067866e8cd73710bcdb218cb78bb3fcc5b314339a466de2b5af56b3b456be8" - log.Info("ensuring job") - // Define a new Namespace object - job := &batch.Job{ - ObjectMeta: metav1.ObjectMeta{ - Name: jobName, - Namespace: namespace, - Labels: map[string]string{ - "app.kubernetes.io/component": "mysql", - "app.kubernetes.io/instance": "trusted-artifact-signer", - "app.kubernetes.io/name": component, - }, - }, - Spec: batch.JobSpec{ - Template: core.PodTemplateSpec{ - ObjectMeta: metav1.ObjectMeta{ - Labels: map[string]string{ - "app.kubernetes.io/component": "mysql", - "app.kubernetes.io/instance": "trusted-artifact-signer", - "app.kubernetes.io/name": component, - }, - }, - Spec: core.PodSpec{ - ServiceAccountName: sA, - RestartPolicy: core.RestartPolicyNever, - Containers: []core.Container{ - { - Name: "trusted-artifact-signer-trillian-createdb", - Image: imageName, - Args: []string{ - "--db_name=$(MYSQL_DATABASE)", - "--mysql_uri=$(MYSQL_USER):$(MYSQL_PASSWORD)@tcp($(MYSQL_HOSTNAME):$(MYSQL_PORT))/", - }, - Env: []core.EnvVar{ - { - Name: "MYSQL_USER", - Value: "mysql", - }, - { - Name: "MYSQL_PASSWORD", - ValueFrom: &core.EnvVarSource{ - SecretKeyRef: &core.SecretKeySelector{ - Key: "mysql-password", - LocalObjectReference: core.LocalObjectReference{ - Name: dbsecret, - }, - }, - }, - }, - { - Name: "MYSQL_HOSTNAME", - Value: "mysql", - }, - { - Name: "MYSQL_PORT", - Value: "3306", - }, - { - Name: "MYSQL_DATABASE", - Value: "trillian", - }, - }, - VolumeMounts: []core.VolumeMount{ - { - Name: "exit-dir", - MountPath: "/var/exitdir", - }, - }, - }, - }, - Volumes: []core.Volume{ - { - Name: "storage", - VolumeSource: core.VolumeSource{ - EmptyDir: &core.EmptyDirVolumeSource{}, - }, - }, - }, - }, - }, - }, - } - - // Check if this Job already exists else create it - err := r.Get(ctx, client.ObjectKey{Name: job.Name, Namespace: namespace}, job) - // If the Job doesn't exist, create it but if it does, do nothing - if err != nil { - log.Info("Creating a new Job") - err = r.Create(ctx, job) - if err != nil { - log.Error(err, "Failed to create new Job") - return nil, err - } - } - return job, nil -} diff --git a/controllers/ctlog/action.go b/controllers/ctlog/action.go new file mode 100644 index 000000000..7b71d8a3e --- /dev/null +++ b/controllers/ctlog/action.go @@ -0,0 +1,23 @@ +package ctlog + +import ( + "context" + + "github.com/securesign/operator/api/v1alpha1" + "k8s.io/client-go/tools/record" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +type Action interface { + InjectClient(client client.Client) + InjectRecorder(recorder record.EventRecorder) + + // a user friendly name for the action + Name() string + + // returns true if the action can handle the integration + CanHandle(trillian *v1alpha1.CTlog) bool + + // executes the handling function + Handle(ctx context.Context, trillian *v1alpha1.CTlog) (*v1alpha1.CTlog, error) +} diff --git a/controllers/ctlog/ctlog_controller.go b/controllers/ctlog/ctlog_controller.go new file mode 100644 index 000000000..3edb6fabd --- /dev/null +++ b/controllers/ctlog/ctlog_controller.go @@ -0,0 +1,102 @@ +/* +Copyright 2023. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package ctlog + +import ( + "context" + + v1 "k8s.io/api/apps/v1" + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/runtime" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/log" + "sigs.k8s.io/controller-runtime/pkg/reconcile" + + rhtasv1alpha1 "github.com/securesign/operator/api/v1alpha1" +) + +// CTlogReconciler reconciles a CTlog object +type CTlogReconciler struct { + client.Client + Scheme *runtime.Scheme +} + +//+kubebuilder:rbac:groups=rhtas.redhat.com,resources=ctlogs,verbs=get;list;watch;create;update;patch;delete +//+kubebuilder:rbac:groups=rhtas.redhat.com,resources=ctlogs/status,verbs=get;update;patch +//+kubebuilder:rbac:groups=rhtas.redhat.com,resources=ctlogs/finalizers,verbs=update + +// Reconcile is part of the main kubernetes reconciliation loop which aims to +// move the current state of the cluster closer to the desired state. +// TODO(user): Modify the Reconcile function to compare the state specified by +// the CTlog object against the actual cluster state, and then +// perform operations to make the cluster state reflect the state specified by +// the user. +// +// For more details, check Reconcile and its Result here: +// - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.14.1/pkg/reconcile +func (r *CTlogReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { + _ = log.FromContext(ctx) + + var instance rhtasv1alpha1.CTlog + + if err := r.Client.Get(ctx, req.NamespacedName, &instance); err != nil { + if errors.IsNotFound(err) { + // Request object not found, could have been deleted after reconcile request. + // Owned objects are automatically garbage collected. For additional cleanup logic use finalizers. + // Return and don't requeue + return reconcile.Result{}, nil + } + // Error reading the object - requeue the request. + return reconcile.Result{}, err + } + target := instance.DeepCopy() + actions := []Action{ + NewInitializeAction(), + NewWaitAction(), + } + + for _, a := range actions { + a.InjectClient(r.Client) + + if a.CanHandle(target) { + newTarget, err := a.Handle(ctx, target) + if err != nil { + if newTarget != nil { + _ = r.Status().Update(ctx, newTarget) + } + return reconcile.Result{}, err + } + + if newTarget != nil { + if err := r.Status().Update(ctx, newTarget); err != nil { + return reconcile.Result{}, err + } + } + break + } + } + return reconcile.Result{}, nil +} + +// SetupWithManager sets up the controller with the Manager. +func (r *CTlogReconciler) SetupWithManager(mgr ctrl.Manager) error { + return ctrl.NewControllerManagedBy(mgr). + For(&rhtasv1alpha1.CTlog{}). + Owns(&v1.Deployment{}). + Complete(r) +} diff --git a/controllers/ctlog/init.go b/controllers/ctlog/init.go new file mode 100644 index 000000000..3322c17cd --- /dev/null +++ b/controllers/ctlog/init.go @@ -0,0 +1,106 @@ +package ctlog + +import ( + "context" + "fmt" + + rhtasv1alpha1 "github.com/securesign/operator/api/v1alpha1" + "github.com/securesign/operator/controllers/common" + "github.com/securesign/operator/controllers/common/utils" + ctlogUtils "github.com/securesign/operator/controllers/ctlog/utils" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/util/intstr" + "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" +) + +const ( + deploymentName = "ctlog" + jobName = "ctlog-createtree" +) + +func NewInitializeAction() Action { + return &initializeAction{} +} + +type initializeAction struct { + common.BaseAction +} + +func (i initializeAction) Name() string { + return "initialize" +} + +func (i initializeAction) CanHandle(ctlog *rhtasv1alpha1.CTlog) bool { + return ctlog.Status.Phase == rhtasv1alpha1.PhaseNone +} + +func (i initializeAction) Handle(ctx context.Context, instance *rhtasv1alpha1.CTlog) (*rhtasv1alpha1.CTlog, error) { + //log := ctrllog.FromContext(ctx) + var err error + + server := ctlogUtils.CreateDeployment(instance.Namespace, deploymentName, "ctlog") + controllerutil.SetControllerReference(instance, server, i.Client.Scheme()) + if err = i.Client.Create(ctx, server); err != nil { + instance.Status.Phase = rhtasv1alpha1.PhaseError + return instance, fmt.Errorf("could not create job: %w", err) + } + + cm := i.initConfigmap(instance.Namespace, "ctlog-config") + controllerutil.SetControllerReference(instance, cm, i.Client.Scheme()) + if err = i.Client.Create(ctx, cm); err != nil { + instance.Status.Phase = rhtasv1alpha1.PhaseError + return instance, fmt.Errorf("could not create job: %w", err) + } + + // TODO: move code from job to operator + config := ctlogUtils.CreateCTJob(instance.Namespace, "create-config") + if err = i.Client.Create(ctx, config); err != nil { + instance.Status.Phase = rhtasv1alpha1.PhaseError + return instance, fmt.Errorf("could not create job: %w", err) + } + + // TODO: move code from job to operator + tree := ctlogUtils.CTJob(instance.Namespace, "create-tree") + if err = i.Client.Create(ctx, tree); err != nil { + instance.Status.Phase = rhtasv1alpha1.PhaseError + return instance, fmt.Errorf("could not create job: %w", err) + } + + svc := utils.CreateService(instance.Namespace, "ctlog", "ctlog", "ctlog", 6963) + svc.Spec.Ports = append(svc.Spec.Ports, corev1.ServicePort{ + Name: "80-tcp", + Protocol: corev1.ProtocolTCP, + Port: 80, + TargetPort: intstr.FromInt(6962), + }) + controllerutil.SetControllerReference(instance, svc, i.Client.Scheme()) + if err = i.Client.Create(ctx, svc); err != nil { + instance.Status.Phase = rhtasv1alpha1.PhaseError + return instance, fmt.Errorf("could not create service: %w", err) + } + + instance.Status.Phase = rhtasv1alpha1.PhaseInitialization + return instance, nil + +} + +func (i initializeAction) initConfigmap(namespace string, name string) *corev1.ConfigMap { + return &corev1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Name: name, + Namespace: namespace, + Labels: map[string]string{ + "app.kubernetes.io/name": "ctlog", + "app.kubernetes.io/instance": "trusted-artifact-signer", + }, + }, + + Data: map[string]string{ + "__placeholder": "###################################################################\n" + + "# Just a placeholder so that reapplying this won't overwrite treeID\n" + + "# if it already exists. This caused grief, do not remove.\n" + + "###################################################################", + }, + } +} diff --git a/controllers/ctlog/utils/create_tree_job.go b/controllers/ctlog/utils/create_tree_job.go new file mode 100644 index 000000000..e95602b93 --- /dev/null +++ b/controllers/ctlog/utils/create_tree_job.go @@ -0,0 +1,63 @@ +package utils + +import ( + batch "k8s.io/api/batch/v1" + core "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +func CTJob(namespace string, jobName string) *batch.Job { + + imageName := "registry.redhat.io/rhtas-tech-preview/createtree-rhel9@sha256:8a80def74e850f2b4c73690f86669a1fe52c1043c175610750abb4644e63d4ab" + + // Define a new Namespace object + return &batch.Job{ + ObjectMeta: metav1.ObjectMeta{ + Name: jobName, + Namespace: namespace, + Labels: map[string]string{ + "app.kubernetes.io/component": "server", + "app.kubernetes.io/instance": "trusted-artifact-signer", + "app.kubernetes.io/name": "ctlog", + }, + }, + Spec: batch.JobSpec{ + Template: core.PodTemplateSpec{ + ObjectMeta: metav1.ObjectMeta{ + Labels: map[string]string{ + "app.kubernetes.io/component": "server", + "app.kubernetes.io/instance": "trusted-artifact-signer", + "app.kubernetes.io/name": "ctlog", + }, + }, + Spec: core.PodSpec{ + ServiceAccountName: "sigstore-sa", + RestartPolicy: core.RestartPolicyNever, + Containers: []core.Container{ + { + Name: "trusted-artifact-signer-rekor-createtree", + Image: imageName, + Args: []string{ + "--namespace=$(NAMESPACE)", + "--configmap=ctlog-config", + "--display_name=ctlog-tree", + "--admin_server=trillian-logserver." + namespace + ":8091", + }, + Env: []core.EnvVar{ + { + Name: "NAMESPACE", + ValueFrom: &core.EnvVarSource{ + FieldRef: &core.ObjectFieldSelector{ + FieldPath: "metadata.namespace", + }, + }, + }, + }, + Resources: core.ResourceRequirements{}, + }, + }, + }, + }, + }, + } +} diff --git a/controllers/ctlog_create_job.go b/controllers/ctlog/utils/ctlog_create_job.go similarity index 67% rename from controllers/ctlog_create_job.go rename to controllers/ctlog/utils/ctlog_create_job.go index b6c35b7f7..2769477a5 100644 --- a/controllers/ctlog_create_job.go +++ b/controllers/ctlog/utils/ctlog_create_job.go @@ -1,24 +1,17 @@ -package controllers +package utils import ( - "context" - - client "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/log" - - rhtasv1alpha1 "github.com/securesign/operator/api/v1alpha1" batch "k8s.io/api/batch/v1" core "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) -func (r *SecuresignReconciler) ensureCreateCTJob(ctx context.Context, m *rhtasv1alpha1.Securesign, namespace string, sA string, jobName string, fun string, trn string) (*batch.Job, - error) { - log := log.FromContext(ctx) +func CreateCTJob(namespace string, jobName string) *batch.Job { + imageName := "registry.redhat.io/rhtas-tech-preview/createctconfig-rhel9@sha256:10155f8c2b73b12599124895b2db0c9e08b2c3953df7361574fd08467c42fd04" - log.Info("ensuring job") + // Define a new Namespace object - job := &batch.Job{ + return &batch.Job{ ObjectMeta: metav1.ObjectMeta{ Name: jobName, Namespace: namespace, @@ -36,7 +29,7 @@ func (r *SecuresignReconciler) ensureCreateCTJob(ctx context.Context, m *rhtasv1 }, }, Spec: core.PodSpec{ - ServiceAccountName: sA, + ServiceAccountName: "sigstore-sa", AutomountServiceAccountToken: &[]bool{true}[0], RestartPolicy: core.RestartPolicyNever, InitContainers: []core.Container{ @@ -64,8 +57,8 @@ func (r *SecuresignReconciler) ensureCreateCTJob(ctx context.Context, m *rhtasv1 "--configmap=ctlog-config", "--secret=ctlog-secret", "--pubkeysecret=ctlog-public-key", - "--fulcio-url=http://fulcio-server." + fun + ".svc", - "--trillian-server=trillian-logserver." + trn + ":8091", + "--fulcio-url=http://fulcio-server." + namespace + ".svc", + "--trillian-server=trillian-logserver." + namespace + ":8091", "--log-prefix=sigstorescaffolding", }, Env: []core.EnvVar{ @@ -80,17 +73,4 @@ func (r *SecuresignReconciler) ensureCreateCTJob(ctx context.Context, m *rhtasv1 }, }, } - - // Check if this Job already exists else create it - err := r.Get(ctx, client.ObjectKey{Name: job.Name, Namespace: namespace}, job) - // If the Job doesn't exist, create it but if it does, do nothing - if err != nil { - log.Info("Creating a new Job") - err = r.Create(ctx, job) - if err != nil { - log.Error(err, "Failed to create new Job") - return nil, err - } - } - return job, nil } diff --git a/controllers/ctlog_deployment.go b/controllers/ctlog/utils/ctlog_deployment.go similarity index 62% rename from controllers/ctlog_deployment.go rename to controllers/ctlog/utils/ctlog_deployment.go index 42409f3be..fd2df0ff0 100644 --- a/controllers/ctlog_deployment.go +++ b/controllers/ctlog/utils/ctlog_deployment.go @@ -1,48 +1,44 @@ -package controllers +package utils import ( - "context" - - client "sigs.k8s.io/controller-runtime/pkg/client" - - rhtasv1alpha1 "github.com/securesign/operator/api/v1alpha1" appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/util/intstr" - ctrllog "sigs.k8s.io/controller-runtime/pkg/log" ) -func (r *SecuresignReconciler) ensurectDeployment(ctx context.Context, m *rhtasv1alpha1.Securesign, namespace string, deploymentName string, sA string, ssapp string) (*appsv1.Deployment, error) { - log := ctrllog.FromContext(ctx) - log.Info("ensuring deployment") +func CreateDeployment(namespace string, deploymentName string, ssapp string) *appsv1.Deployment { + replicas := int32(1) // Define a new Deployment object - deployment := &appsv1.Deployment{ + return &appsv1.Deployment{ ObjectMeta: metav1.ObjectMeta{ Name: deploymentName, Namespace: namespace, Labels: map[string]string{ - "app.kubernetes.io/name": ssapp, - "app.kubernetes.io/instance": "trusted-artifact-signer", + "app.kubernetes.io/name": ssapp, + "app.kubernetes.io/instance": "trusted-artifact-signer", + "app.kubernetes.io/component": ssapp, }, }, Spec: appsv1.DeploymentSpec{ Replicas: &replicas, Selector: &metav1.LabelSelector{ MatchLabels: map[string]string{ - "app.kubernetes.io/name": ssapp, - "app.kubernetes.io/instance": "trusted-artifact-signer"}, + "app.kubernetes.io/name": ssapp, + "app.kubernetes.io/instance": "trusted-artifact-signer", + "app.kubernetes.io/component": ssapp}, }, Template: corev1.PodTemplateSpec{ ObjectMeta: metav1.ObjectMeta{ Labels: map[string]string{ - "app.kubernetes.io/name": ssapp, - "app.kubernetes.io/instance": "trusted-artifact-signer", + "app.kubernetes.io/name": ssapp, + "app.kubernetes.io/component": ssapp, + "app.kubernetes.io/instance": "trusted-artifact-signer", }, }, Spec: corev1.PodSpec{ - ServiceAccountName: sA, + ServiceAccountName: "sigstore-sa", Containers: []corev1.Container{ { Name: "ctlog", @@ -104,16 +100,4 @@ func (r *SecuresignReconciler) ensurectDeployment(ctx context.Context, m *rhtasv }, }, } - // Check if this Deployment already exists else create it in the namespace - err := r.Get(ctx, client.ObjectKey{Name: deployment.Name, Namespace: namespace}, deployment) - // If the Deployment doesn't exist, create it but if it does, do nothing - if err != nil { - log.Info("Creating a new Deployment") - err = r.Create(ctx, deployment) - if err != nil { - log.Error(err, "Failed to create new Deployment") - return nil, err - } - } - return deployment, nil } diff --git a/controllers/ctlog/wait.go b/controllers/ctlog/wait.go new file mode 100644 index 000000000..b94681058 --- /dev/null +++ b/controllers/ctlog/wait.go @@ -0,0 +1,44 @@ +package ctlog + +import ( + "context" + + rhtasv1alpha1 "github.com/securesign/operator/api/v1alpha1" + "github.com/securesign/operator/controllers/common" + commonUtils "github.com/securesign/operator/controllers/common/utils" +) + +func NewWaitAction() Action { + return &waitAction{} +} + +type waitAction struct { + common.BaseAction +} + +func (i waitAction) Name() string { + return "wait" +} + +func (i waitAction) CanHandle(ctlog *rhtasv1alpha1.CTlog) bool { + return ctlog.Status.Phase == rhtasv1alpha1.PhaseInitialization +} + +func (i waitAction) Handle(ctx context.Context, instance *rhtasv1alpha1.CTlog) (*rhtasv1alpha1.CTlog, error) { + var ( + ok bool + err error + ) + for _, deployment := range []string{"ctlog"} { + ok, err = commonUtils.DeploymentIsRunning(ctx, i.Client, instance.Namespace, deployment) + if err != nil { + instance.Status.Phase = rhtasv1alpha1.PhaseError + return instance, err + } + if !ok { + return instance, nil + } + } + instance.Status.Phase = rhtasv1alpha1.PhaseReady + return instance, nil +} diff --git a/controllers/dbsecret.go b/controllers/dbsecret.go deleted file mode 100644 index a694a71db..000000000 --- a/controllers/dbsecret.go +++ /dev/null @@ -1,46 +0,0 @@ -package controllers - -import ( - "context" - - client "sigs.k8s.io/controller-runtime/pkg/client" - - rhtasv1alpha1 "github.com/securesign/operator/api/v1alpha1" - corev1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - ctrllog "sigs.k8s.io/controller-runtime/pkg/log" -) - -func (r *SecuresignReconciler) ensureDBSecret(ctx context.Context, m *rhtasv1alpha1.Securesign, namespace string, secretName string) (*corev1.Secret, - error) { - log := ctrllog.FromContext(ctx) - log.Info("ensuring secret") - // Define a new Secret object - secret := &corev1.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Name: "rhtas-" + secretName, - Namespace: namespace, - }, - Type: "Opaque", - Data: map[string][]byte{ - // generate a random password for the mysql root user and the mysql password - // TODO - use a random password generator - "mysql-root-password": []byte("password"), - "mysql-password": []byte("password"), - "mysql-database": []byte("trillian"), - "mysql-user": []byte("mysql"), - }, - } - // Check if this Secret already exists else create it in the namespace - err := r.Get(ctx, client.ObjectKey{Name: secret.Name, Namespace: namespace}, secret) - // If the Secret doesn't exist, create it but if it does, do nothing - if err != nil { - log.Info("Creating a new Secret") - err = r.Create(ctx, secret) - if err != nil { - log.Error(err, "Failed to create new Secret") - return nil, err - } - } - return secret, nil -} diff --git a/controllers/fulcio/action.go b/controllers/fulcio/action.go new file mode 100644 index 000000000..d5a1e8271 --- /dev/null +++ b/controllers/fulcio/action.go @@ -0,0 +1,36 @@ +package fulcio + +import ( + "context" + + "github.com/securesign/operator/api/v1alpha1" + "k8s.io/client-go/tools/record" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +type Action interface { + InjectClient(client client.Client) + InjectRecorder(recorder record.EventRecorder) + + // a user friendly name for the action + Name() string + + // returns true if the action can handle the integration + CanHandle(*v1alpha1.Fulcio) bool + + // executes the handling function + Handle(context.Context, *v1alpha1.Fulcio) (*v1alpha1.Fulcio, error) +} + +type BaseAction struct { + Client client.Client + Recorder record.EventRecorder +} + +func (action *BaseAction) InjectClient(client client.Client) { + action.Client = client +} + +func (action *BaseAction) InjectRecorder(recorder record.EventRecorder) { + action.Recorder = recorder +} diff --git a/controllers/fulcio/fulcio_controller.go b/controllers/fulcio/fulcio_controller.go new file mode 100644 index 000000000..418045368 --- /dev/null +++ b/controllers/fulcio/fulcio_controller.go @@ -0,0 +1,100 @@ +/* +Copyright 2023. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package fulcio + +import ( + "context" + + v1 "k8s.io/api/apps/v1" + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/runtime" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/reconcile" + + rhtasv1alpha1 "github.com/securesign/operator/api/v1alpha1" +) + +// FulcioReconciler reconciles a Fulcio object +type FulcioReconciler struct { + client.Client + Scheme *runtime.Scheme +} + +//+kubebuilder:rbac:groups=rhtas.redhat.com,resources=fulcios,verbs=get;list;watch;create;update;patch;delete +//+kubebuilder:rbac:groups=rhtas.redhat.com,resources=fulcios/status,verbs=get;update;patch +//+kubebuilder:rbac:groups=rhtas.redhat.com,resources=fulcios/finalizers,verbs=update + +// Reconcile is part of the main kubernetes reconciliation loop which aims to +// move the current state of the cluster closer to the desired state. +// TODO(user): Modify the Reconcile function to compare the state specified by +// the Fulcio object against the actual cluster state, and then +// perform operations to make the cluster state reflect the state specified by +// the user. +// +// For more details, check Reconcile and its Result here: +// - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.14.1/pkg/reconcile +func (r *FulcioReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { + + var instance rhtasv1alpha1.Fulcio + + if err := r.Client.Get(ctx, req.NamespacedName, &instance); err != nil { + if errors.IsNotFound(err) { + // Request object not found, could have been deleted after reconcile request. + // Owned objects are automatically garbage collected. For additional cleanup logic use finalizers. + // Return and don't requeue + return reconcile.Result{}, nil + } + // Error reading the object - requeue the request. + return reconcile.Result{}, err + } + target := instance.DeepCopy() + actions := []Action{ + NewInitializeAction(), + NewWaitAction(), + } + + for _, a := range actions { + a.InjectClient(r.Client) + + if a.CanHandle(target) { + newTarget, err := a.Handle(ctx, target) + if err != nil { + if newTarget != nil { + _ = r.Status().Update(ctx, newTarget) + } + return reconcile.Result{}, err + } + + if newTarget != nil { + if err := r.Status().Update(ctx, newTarget); err != nil { + return reconcile.Result{}, err + } + } + break + } + } + return reconcile.Result{}, nil +} + +// SetupWithManager sets up the controller with the Manager. +func (r *FulcioReconciler) SetupWithManager(mgr ctrl.Manager) error { + return ctrl.NewControllerManagedBy(mgr). + For(&rhtasv1alpha1.Fulcio{}). + Owns(&v1.Deployment{}). + Complete(r) +} diff --git a/controllers/fulcio/init.go b/controllers/fulcio/init.go new file mode 100644 index 000000000..8494083af --- /dev/null +++ b/controllers/fulcio/init.go @@ -0,0 +1,96 @@ +package fulcio + +import ( + "context" + "encoding/json" + "fmt" + + rhtasv1alpha1 "github.com/securesign/operator/api/v1alpha1" + "github.com/securesign/operator/controllers/common" + commonUtils "github.com/securesign/operator/controllers/common/utils" + "github.com/securesign/operator/controllers/fulcio/utils" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/util/intstr" + "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" +) + +const FulcioDeploymentName = "fulcio-server" + +func NewInitializeAction() Action { + return &initializeAction{} +} + +type initializeAction struct { + common.BaseAction +} + +func (i initializeAction) Name() string { + return "initialize" +} + +func (i initializeAction) CanHandle(Fulcio *rhtasv1alpha1.Fulcio) bool { + return Fulcio.Status.Phase == rhtasv1alpha1.PhaseNone +} + +func (i initializeAction) Handle(ctx context.Context, instance *rhtasv1alpha1.Fulcio) (*rhtasv1alpha1.Fulcio, error) { + //log := ctrllog.FromContext(ctx) + var err error + if instance.Spec.KeySecret == "" { + // TODO: generate one + } + + cm := i.initConfigmap(instance.Namespace, "fulcio-server-config", *instance) + controllerutil.SetOwnerReference(instance, cm, i.Client.Scheme()) + if err = i.Client.Create(ctx, cm); err != nil { + instance.Status.Phase = rhtasv1alpha1.PhaseError + return instance, fmt.Errorf("could not create fulcio secret: %w", err) + } + + dp := utils.CreateDeployment(instance.Namespace, FulcioDeploymentName, "fulcio-server", "fulcio") + controllerutil.SetOwnerReference(instance, dp, i.Client.Scheme()) + if err = i.Client.Create(ctx, dp); err != nil { + instance.Status.Phase = rhtasv1alpha1.PhaseError + return instance, fmt.Errorf("could not create fulcio secret: %w", err) + } + + svc := commonUtils.CreateService(instance.Namespace, "fulcio-server", "fulcio-server", "fulcio", 2112) + svc.Spec.Ports = append(svc.Spec.Ports, corev1.ServicePort{ + Name: "5554-tcp", + Protocol: corev1.ProtocolTCP, + Port: 5554, + TargetPort: intstr.FromInt(5554), + }) + svc.Spec.Ports = append(svc.Spec.Ports, corev1.ServicePort{ + Name: "80-tcp", + Protocol: corev1.ProtocolTCP, + Port: 80, + TargetPort: intstr.FromInt(5555), + }) + if err = i.Client.Create(ctx, svc); err != nil { + instance.Status.Phase = rhtasv1alpha1.PhaseError + return instance, fmt.Errorf("could not create service: %w", err) + } + + instance.Status.Phase = rhtasv1alpha1.PhaseInitialization + return instance, nil + +} + +func (i initializeAction) initConfigmap(namespace string, name string, m rhtasv1alpha1.Fulcio) *corev1.ConfigMap { + issuers, _ := json.Marshal(m.Spec.OidcIssuers) + return &corev1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Name: name, + Namespace: namespace, + Labels: map[string]string{ + "app.kubernetes.io/name": "fulcio", + "app.kubernetes.io/instance": "trusted-artifact-signer", + }, + }, + + Data: map[string]string{ + "config.json": fmt.Sprintf("{\"OIDCIssuers\": %s}", issuers), + }, + } +} diff --git a/controllers/fulcio_deployment.go b/controllers/fulcio/utils/fulcio_deployment.go similarity index 80% rename from controllers/fulcio_deployment.go rename to controllers/fulcio/utils/fulcio_deployment.go index 41abe7472..90e00ed56 100644 --- a/controllers/fulcio_deployment.go +++ b/controllers/fulcio/utils/fulcio_deployment.go @@ -1,25 +1,19 @@ -package controllers +package utils import ( - "context" + "fmt" - client "sigs.k8s.io/controller-runtime/pkg/client" - - rhtasv1alpha1 "github.com/securesign/operator/api/v1alpha1" appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/util/intstr" - ctrllog "sigs.k8s.io/controller-runtime/pkg/log" ) -func (r *SecuresignReconciler) ensureFulDeployment(ctx context.Context, m *rhtasv1alpha1.Securesign, namespace string, deploymentName string, sA string, component string, ssapp string) (*appsv1.Deployment, error) { - log := ctrllog.FromContext(ctx) - log.Info("ensuring deployment") +func CreateDeployment(namespace string, deploymentName string, component string, ssapp string) *appsv1.Deployment { replicas := int32(1) mode := int32(0666) - // Define a new Deployment object - deployment := &appsv1.Deployment{ + + return &appsv1.Deployment{ ObjectMeta: metav1.ObjectMeta{ Name: deploymentName, Namespace: namespace, @@ -47,7 +41,7 @@ func (r *SecuresignReconciler) ensureFulDeployment(ctx context.Context, m *rhtas }, }, Spec: corev1.PodSpec{ - ServiceAccountName: sA, + ServiceAccountName: "sigstore-sa", Containers: []corev1.Container{ { Name: ssapp, @@ -63,7 +57,7 @@ func (r *SecuresignReconciler) ensureFulDeployment(ctx context.Context, m *rhtas "/var/run/fulcio-secrets/cert.pem", "--fileca-key-passwd", "$(PASSWORD)", - "--ct-log-url=http://ctlog.ctlog-system.svc/sigstorescaffolding", + fmt.Sprintf("--ct-log-url=http://ctlog.%s.svc/sigstorescaffolding", namespace), }, Env: []corev1.EnvVar{ { @@ -185,16 +179,4 @@ func (r *SecuresignReconciler) ensureFulDeployment(ctx context.Context, m *rhtas }, }, } - // Check if this Deployment already exists else create it in the namespace - err := r.Get(ctx, client.ObjectKey{Name: deployment.Name, Namespace: namespace}, deployment) - // If the Deployment doesn't exist, create it but if it does, do nothing - if err != nil { - log.Info("Creating a new Deployment") - err = r.Create(ctx, deployment) - if err != nil { - log.Error(err, "Failed to create new Deployment") - return nil, err - } - } - return deployment, nil } diff --git a/controllers/fulcio/wait.go b/controllers/fulcio/wait.go new file mode 100644 index 000000000..c1863db00 --- /dev/null +++ b/controllers/fulcio/wait.go @@ -0,0 +1,44 @@ +package fulcio + +import ( + "context" + + rhtasv1alpha1 "github.com/securesign/operator/api/v1alpha1" + "github.com/securesign/operator/controllers/common" + commonUtils "github.com/securesign/operator/controllers/common/utils" +) + +func NewWaitAction() Action { + return &waitAction{} +} + +type waitAction struct { + common.BaseAction +} + +func (i waitAction) Name() string { + return "wait" +} + +func (i waitAction) CanHandle(Fulcio *rhtasv1alpha1.Fulcio) bool { + return Fulcio.Status.Phase == rhtasv1alpha1.PhaseInitialization +} + +func (i waitAction) Handle(ctx context.Context, instance *rhtasv1alpha1.Fulcio) (*rhtasv1alpha1.Fulcio, error) { + var ( + ok bool + err error + ) + for _, deployment := range []string{"fulcio-server"} { + ok, err = commonUtils.DeploymentIsRunning(ctx, i.Client, instance.Namespace, deployment) + if err != nil { + instance.Status.Phase = rhtasv1alpha1.PhaseError + return instance, err + } + if !ok { + return instance, nil + } + } + instance.Status.Phase = rhtasv1alpha1.PhaseReady + return instance, nil +} diff --git a/controllers/fulcio_cert_secret.go b/controllers/fulcio_cert_secret.go deleted file mode 100644 index 5385303e5..000000000 --- a/controllers/fulcio_cert_secret.go +++ /dev/null @@ -1,44 +0,0 @@ -package controllers - -import ( - "context" - - client "sigs.k8s.io/controller-runtime/pkg/client" - - rhtasv1alpha1 "github.com/securesign/operator/api/v1alpha1" - corev1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - ctrllog "sigs.k8s.io/controller-runtime/pkg/log" -) - -func (r *SecuresignReconciler) ensureFulcioSecret(ctx context.Context, m *rhtasv1alpha1.Securesign, namespace string, secretName string) (*corev1.Secret, - error) { - log := ctrllog.FromContext(ctx) - log.Info("ensuring secret") - // Define a new Secret object - secret := &corev1.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Name: secretName, - Namespace: namespace, - }, - Type: "Opaque", - Data: map[string][]byte{ - "public": []byte(m.Spec.FulcioPublicKey), - "private": []byte(m.Spec.FulcioPrivateKey), - "cert": []byte(m.Spec.FulcioCert), - "password": []byte(m.Spec.FulcioPassword), - }, - } - // Check if this Secret already exists else create it in the namespace - err := r.Get(ctx, client.ObjectKey{Name: secret.Name, Namespace: namespace}, secret) - // If the Secret doesn't exist, create it but if it does, do nothing - if err != nil { - log.Info("Creating a new Secret") - err = r.Create(ctx, secret) - if err != nil { - log.Error(err, "Failed to create new Secret") - return nil, err - } - } - return secret, nil -} diff --git a/controllers/fulcio_configmap.go b/controllers/fulcio_configmap.go deleted file mode 100644 index ab25f21ad..000000000 --- a/controllers/fulcio_configmap.go +++ /dev/null @@ -1,53 +0,0 @@ -package controllers - -import ( - "context" - - client "sigs.k8s.io/controller-runtime/pkg/client" - - rhtasv1alpha1 "github.com/securesign/operator/api/v1alpha1" - corev1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - ctrllog "sigs.k8s.io/controller-runtime/pkg/log" -) - -func (r *SecuresignReconciler) ensureOIDCConfigMap(ctx context.Context, m *rhtasv1alpha1.Securesign, namespace string, configMapName string, component string) (*corev1.ConfigMap, - error) { - log := ctrllog.FromContext(ctx) - log.Info("ensuring configmap") - // Define a new ConfigMap object - configMap := &corev1.ConfigMap{ - ObjectMeta: metav1.ObjectMeta{ - Name: configMapName, - Namespace: namespace, - Labels: map[string]string{ - "app.kubernetes.io/name": component, - "app.kubernetes.io/instance": "trusted-artifact-signer", - }, - }, - Data: map[string]string{ - "config.json": `{ - "OIDCIssuers": { - "http://keycloak-internal.keycloak-system.svc/auth/realms/sigstore": { - "ClientID": "sigstore", - "IssuerURL": "http://keycloak-internal.keycloak-system.svc/auth/realms/sigstore", - "Type": "email" - } - } - }`, - }, - } - - // Check if this ConfigMap already exists else create it in the namespace - err := r.Get(ctx, client.ObjectKey{Name: configMap.Name, Namespace: namespace}, configMap) - // If the ConfigMap doesn't exist, create it but if it does, do nothing - if err != nil { - log.Info("Creating a new ConfigMap") - err = r.Create(ctx, configMap) - if err != nil { - log.Error(err, "Failed to create new ConfigMap") - return nil, err - } - } - return configMap, nil -} diff --git a/controllers/namespace.go b/controllers/namespace.go deleted file mode 100644 index e7a5e023c..000000000 --- a/controllers/namespace.go +++ /dev/null @@ -1,34 +0,0 @@ -package controllers - -import ( - "context" - - rhtasv1alpha1 "github.com/securesign/operator/api/v1alpha1" - corev1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - client "sigs.k8s.io/controller-runtime/pkg/client" - ctrllog "sigs.k8s.io/controller-runtime/pkg/log" -) - -func (r *SecuresignReconciler) ensureNamespace(ctx context.Context, m *rhtasv1alpha1.Securesign, component string) (*corev1.Namespace, error) { - log := ctrllog.FromContext(ctx) - - ns := &corev1.Namespace{ - ObjectMeta: metav1.ObjectMeta{ - Name: component, - }, - } - - // Check if this Namespace already exists else create it - err := r.Get(ctx, client.ObjectKey{Name: ns.Name}, ns) - // If the Namespace doesn't exist, create it but if it does, do nothing - if err != nil { - log.Info("Creating a new Namespace") - err = r.Create(ctx, ns) - if err != nil { - log.Error(err, "Failed to create new Namespace") - return nil, err - } - } - return ns, nil -} diff --git a/controllers/pvc.go b/controllers/pvc.go deleted file mode 100644 index 161b2ec4a..000000000 --- a/controllers/pvc.go +++ /dev/null @@ -1,49 +0,0 @@ -package controllers - -import ( - "context" - - client "sigs.k8s.io/controller-runtime/pkg/client" - - rhtasv1alpha1 "github.com/securesign/operator/api/v1alpha1" - corev1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/api/resource" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - ctrllog "sigs.k8s.io/controller-runtime/pkg/log" -) - -func (r *SecuresignReconciler) ensurePVC(ctx context.Context, m *rhtasv1alpha1.Securesign, namespace string, pvcName string) (*corev1.PersistentVolumeClaim, - error) { - log := ctrllog.FromContext(ctx) - log.Info("ensuring pvc") - pvcSize := "5Gi" - // Define a new PVC object - pvc := &corev1.PersistentVolumeClaim{ - ObjectMeta: metav1.ObjectMeta{ - Name: pvcName, - Namespace: namespace, - }, - Spec: corev1.PersistentVolumeClaimSpec{ - AccessModes: []corev1.PersistentVolumeAccessMode{ - "ReadWriteOnce", - }, - Resources: corev1.ResourceRequirements{ - Requests: corev1.ResourceList{ - corev1.ResourceName(corev1.ResourceStorage): resource.MustParse(pvcSize), - }, - }, - }, - } - // Check if this PVC already exists else create it in the namespace - err := r.Get(ctx, client.ObjectKey{Name: pvc.Name, Namespace: namespace}, pvc) - // If the PVC doesn't exist, create it but if it does, do nothing - if err != nil { - log.Info("Creating a new PVC") - err = r.Create(ctx, pvc) - if err != nil { - log.Error(err, "Failed to create new PVC") - return nil, err - } - } - return pvc, nil -} diff --git a/controllers/rekor/action.go b/controllers/rekor/action.go new file mode 100644 index 000000000..778986dcc --- /dev/null +++ b/controllers/rekor/action.go @@ -0,0 +1,36 @@ +package rekor + +import ( + "context" + + "github.com/securesign/operator/api/v1alpha1" + "k8s.io/client-go/tools/record" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +type Action interface { + InjectClient(client client.Client) + InjectRecorder(recorder record.EventRecorder) + + // a user friendly name for the action + Name() string + + // returns true if the action can handle the integration + CanHandle(*v1alpha1.Rekor) bool + + // executes the handling function + Handle(context.Context, *v1alpha1.Rekor) (*v1alpha1.Rekor, error) +} + +type BaseAction struct { + Client client.Client + Recorder record.EventRecorder +} + +func (action *BaseAction) InjectClient(client client.Client) { + action.Client = client +} + +func (action *BaseAction) InjectRecorder(recorder record.EventRecorder) { + action.Recorder = recorder +} diff --git a/controllers/rekor/init.go b/controllers/rekor/init.go new file mode 100644 index 000000000..ef35ca973 --- /dev/null +++ b/controllers/rekor/init.go @@ -0,0 +1,118 @@ +package rekor + +import ( + "context" + "fmt" + + rhtasv1alpha1 "github.com/securesign/operator/api/v1alpha1" + "github.com/securesign/operator/controllers/common" + utils2 "github.com/securesign/operator/controllers/common/utils" + "github.com/securesign/operator/controllers/rekor/utils" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/util/intstr" + "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" +) + +const rekorDeploymentName = "rekor-server" + +func NewInitializeAction() Action { + return &initializeAction{} +} + +type initializeAction struct { + common.BaseAction +} + +func (i initializeAction) Name() string { + return "initialize" +} + +func (i initializeAction) CanHandle(Rekor *rhtasv1alpha1.Rekor) bool { + return Rekor.Status.Phase == rhtasv1alpha1.PhaseNone +} + +func (i initializeAction) Handle(ctx context.Context, instance *rhtasv1alpha1.Rekor) (*rhtasv1alpha1.Rekor, error) { + //log := ctrllog.FromContext(ctx) + var err error + if instance.Spec.KeySecret == "" { + // TODO: generate one + } + sharding := i.initConfigmap(instance.Namespace, "rekor-sharding-config") + if err = i.Client.Create(ctx, sharding); err != nil { + instance.Status.Phase = rhtasv1alpha1.PhaseError + return instance, fmt.Errorf("could not create Rekor secret: %w", err) + } + + var rekorPvcName string + if instance.Spec.PvcName == "" { + rekorPvc := utils2.CreatePVC(instance.Namespace, "rekor-server", "5Gi") + if err = i.Client.Create(ctx, rekorPvc); err != nil { + instance.Status.Phase = rhtasv1alpha1.PhaseError + return instance, fmt.Errorf("could not create Rekor secret: %w", err) + } + rekorPvcName = rekorPvc.Name + // TODO: add status field + } else { + rekorPvcName = instance.Spec.PvcName + } + + config := i.initConfigmap(instance.Namespace, "rekor-config") + if err = i.Client.Create(ctx, config); err != nil { + instance.Status.Phase = rhtasv1alpha1.PhaseError + return instance, fmt.Errorf("could not create Rekor secret: %w", err) + } + + dp := utils.CreateRekorDeployment(instance.Namespace, rekorDeploymentName, rekorPvcName) + controllerutil.SetControllerReference(instance, dp, i.Client.Scheme()) + if err = i.Client.Create(ctx, dp); err != nil { + instance.Status.Phase = rhtasv1alpha1.PhaseError + return instance, fmt.Errorf("could not create Rekor deployment: %w", err) + } + + redis := utils.CreateRedisDeployment(instance.Namespace, "rekor-redis") + controllerutil.SetControllerReference(instance, redis, i.Client.Scheme()) + if err = i.Client.Create(ctx, redis); err != nil { + instance.Status.Phase = rhtasv1alpha1.PhaseError + return instance, fmt.Errorf("could not create Rekor-redis deployment: %w", err) + } + + svc := utils2.CreateService(instance.Namespace, rekorDeploymentName, rekorDeploymentName, rekorDeploymentName, 2112) + controllerutil.SetControllerReference(instance, svc, i.Client.Scheme()) + svc.Spec.Ports = append(svc.Spec.Ports, corev1.ServicePort{ + Name: "3000-tcp", + Protocol: corev1.ProtocolTCP, + Port: 80, + TargetPort: intstr.FromInt(3000), + }) + if err = i.Client.Create(ctx, svc); err != nil { + instance.Status.Phase = rhtasv1alpha1.PhaseError + return instance, fmt.Errorf("could not create service: %w", err) + } + + // TODO: move code from job to operator + tree := utils.CTJob(instance.Namespace, "create-tree-rekor") + if err = i.Client.Create(ctx, tree); err != nil { + instance.Status.Phase = rhtasv1alpha1.PhaseError + return instance, fmt.Errorf("could not create job: %w", err) + } + instance.Status.Phase = rhtasv1alpha1.PhaseInitialization + return instance, nil + +} + +func (i initializeAction) initConfigmap(namespace string, name string) *corev1.ConfigMap { + return &corev1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Name: name, + Namespace: namespace, + Labels: map[string]string{ + "app.kubernetes.io/name": "rekor", + "app.kubernetes.io/instance": "trusted-artifact-signer", + }, + }, + + Data: map[string]string{ + "sharding-config.yaml": ""}, + } +} diff --git a/controllers/rekor/rekor_controller.go b/controllers/rekor/rekor_controller.go new file mode 100644 index 000000000..79c22709c --- /dev/null +++ b/controllers/rekor/rekor_controller.go @@ -0,0 +1,99 @@ +/* +Copyright 2023. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package rekor + +import ( + "context" + + v12 "k8s.io/api/apps/v1" + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/runtime" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/reconcile" + + rhtasv1alpha1 "github.com/securesign/operator/api/v1alpha1" +) + +// RekorReconciler reconciles a Rekor object +type RekorReconciler struct { + client.Client + Scheme *runtime.Scheme +} + +//+kubebuilder:rbac:groups=rhtas.redhat.com,resources=rekors,verbs=get;list;watch;create;update;patch;delete +//+kubebuilder:rbac:groups=rhtas.redhat.com,resources=rekors/status,verbs=get;update;patch +//+kubebuilder:rbac:groups=rhtas.redhat.com,resources=rekors/finalizers,verbs=update + +// Reconcile is part of the main kubernetes reconciliation loop which aims to +// move the current state of the cluster closer to the desired state. +// TODO(user): Modify the Reconcile function to compare the state specified by +// the Rekor object against the actual cluster state, and then +// perform operations to make the cluster state reflect the state specified by +// the user. +// +// For more details, check Reconcile and its Result here: +// - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.14.1/pkg/reconcile +func (r *RekorReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { + var instance rhtasv1alpha1.Rekor + + if err := r.Client.Get(ctx, req.NamespacedName, &instance); err != nil { + if errors.IsNotFound(err) { + // Request object not found, could have been deleted after reconcile request. + // Owned objects are automatically garbage collected. For additional cleanup logic use finalizers. + // Return and don't requeue + return reconcile.Result{}, nil + } + // Error reading the object - requeue the request. + return reconcile.Result{}, err + } + target := instance.DeepCopy() + actions := []Action{ + NewInitializeAction(), + NewWaitAction(), + } + + for _, a := range actions { + a.InjectClient(r.Client) + + if a.CanHandle(target) { + newTarget, err := a.Handle(ctx, target) + if err != nil { + if newTarget != nil { + _ = r.Status().Update(ctx, newTarget) + } + return reconcile.Result{}, err + } + + if newTarget != nil { + if err := r.Status().Update(ctx, newTarget); err != nil { + return reconcile.Result{}, err + } + } + break + } + } + return reconcile.Result{}, nil +} + +// SetupWithManager sets up the controller with the Manager. +func (r *RekorReconciler) SetupWithManager(mgr ctrl.Manager) error { + return ctrl.NewControllerManagedBy(mgr). + For(&rhtasv1alpha1.Rekor{}). + Owns(&v12.Deployment{}). + Complete(r) +} diff --git a/controllers/rekor/utils/create_tree_job.go b/controllers/rekor/utils/create_tree_job.go new file mode 100644 index 000000000..5e55f2201 --- /dev/null +++ b/controllers/rekor/utils/create_tree_job.go @@ -0,0 +1,64 @@ +package utils + +import ( + batch "k8s.io/api/batch/v1" + core "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +func CTJob(namespace string, jobName string) *batch.Job { + + imageName := "registry.redhat.io/rhtas-tech-preview/createtree-rhel9@sha256:8a80def74e850f2b4c73690f86669a1fe52c1043c175610750abb4644e63d4ab" + + // Define a new Namespace object + return &batch.Job{ + ObjectMeta: metav1.ObjectMeta{ + Name: jobName, + Namespace: namespace, + Labels: map[string]string{ + "app.kubernetes.io/component": "server", + "app.kubernetes.io/instance": "trusted-artifact-signer", + "app.kubernetes.io/name": "rekor", + }, + }, + Spec: batch.JobSpec{ + Template: core.PodTemplateSpec{ + ObjectMeta: metav1.ObjectMeta{ + Labels: map[string]string{ + "app.kubernetes.io/component": "server", + "app.kubernetes.io/instance": "trusted-artifact-signer", + "app.kubernetes.io/name": "rekor", + }, + }, + Spec: core.PodSpec{ + ServiceAccountName: "sigstore-sa", + RestartPolicy: core.RestartPolicyNever, + Containers: []core.Container{ + { + Name: "trusted-artifact-signer-rekor-createtree", + Image: imageName, + Args: []string{ + "--namespace=$(NAMESPACE)", + "--configmap=rekor-config", + "--display_name=rekor-tree", + "--admin_server=trillian-logserver." + namespace + ":8091", + "--force=false", + }, + Env: []core.EnvVar{ + { + Name: "NAMESPACE", + ValueFrom: &core.EnvVarSource{ + FieldRef: &core.ObjectFieldSelector{ + FieldPath: "metadata.namespace", + }, + }, + }, + }, + Resources: core.ResourceRequirements{}, + }, + }, + }, + }, + }, + } +} diff --git a/controllers/redis_deployment.go b/controllers/rekor/utils/redis_deployment.go similarity index 71% rename from controllers/redis_deployment.go rename to controllers/rekor/utils/redis_deployment.go index a256d6645..977ed1317 100644 --- a/controllers/redis_deployment.go +++ b/controllers/rekor/utils/redis_deployment.go @@ -1,24 +1,15 @@ -package controllers +package utils import ( - "context" - - client "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/log" - - rhtasv1alpha1 "github.com/securesign/operator/api/v1alpha1" apps "k8s.io/api/apps/v1" core "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) -func (r *SecuresignReconciler) ensureRedisDeployment(ctx context.Context, m *rhtasv1alpha1.Securesign, namespace string, sA string, dpName string) (*apps.Deployment, - error) { - log := log.FromContext(ctx) - log.Info("ensuring deployment") +func CreateRedisDeployment(namespace string, dpName string) *apps.Deployment { replicas := int32(1) // Define a new Namespace object - dep := &apps.Deployment{ + return &apps.Deployment{ ObjectMeta: metav1.ObjectMeta{ Name: dpName, Namespace: namespace, @@ -46,7 +37,7 @@ func (r *SecuresignReconciler) ensureRedisDeployment(ctx context.Context, m *rht }, }, Spec: core.PodSpec{ - ServiceAccountName: sA, + ServiceAccountName: "sigstore-sa", Volumes: []core.Volume{ { Name: "storage", @@ -100,17 +91,4 @@ func (r *SecuresignReconciler) ensureRedisDeployment(ctx context.Context, m *rht }, }, } - - // Check if this Deployment already exists else create it - err := r.Get(ctx, client.ObjectKey{Name: dep.Name, Namespace: namespace}, dep) - // If the Deployment doesn't exist, create it but if it does, do nothing - if err != nil { - log.Info("Creating a new Deployment") - err = r.Create(ctx, dep) - if err != nil { - log.Error(err, "Failed to create new Deployment") - return nil, err - } - } - return dep, nil } diff --git a/controllers/rekor_deployment.go b/controllers/rekor/utils/rekor_deployment.go similarity index 78% rename from controllers/rekor_deployment.go rename to controllers/rekor/utils/rekor_deployment.go index d5969bae4..0b820bde4 100644 --- a/controllers/rekor_deployment.go +++ b/controllers/rekor/utils/rekor_deployment.go @@ -1,24 +1,14 @@ -package controllers +package utils import ( - "context" - - client "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/log" - - rhtasv1alpha1 "github.com/securesign/operator/api/v1alpha1" apps "k8s.io/api/apps/v1" core "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) -func (r *SecuresignReconciler) ensureRekorDeployment(ctx context.Context, m *rhtasv1alpha1.Securesign, namespace string, sA string, dpName string, trn string) (*apps.Deployment, - error) { - log := log.FromContext(ctx) - log.Info("ensuring deployment") +func CreateRekorDeployment(namespace string, dpName string, pvc string) *apps.Deployment { replicas := int32(1) - // Define a new Namespace object - dep := &apps.Deployment{ + return &apps.Deployment{ ObjectMeta: metav1.ObjectMeta{ Name: dpName, Namespace: namespace, @@ -46,7 +36,7 @@ func (r *SecuresignReconciler) ensureRekorDeployment(ctx context.Context, m *rht }, }, Spec: core.PodSpec{ - ServiceAccountName: sA, + ServiceAccountName: "sigstore-sa", Volumes: []core.Volume{ { Name: "rekor-sharding-config", @@ -62,7 +52,7 @@ func (r *SecuresignReconciler) ensureRekorDeployment(ctx context.Context, m *rht Name: "storage", VolumeSource: core.VolumeSource{ PersistentVolumeClaim: &core.PersistentVolumeClaimVolumeSource{ - ClaimName: "rekor-server", + ClaimName: pvc, }, }, }, @@ -119,7 +109,7 @@ func (r *SecuresignReconciler) ensureRekorDeployment(ctx context.Context, m *rht }, Args: []string{ "serve", - "--trillian_log_server.address=trillian-logserver." + trn, + "--trillian_log_server.address=trillian-logserver." + namespace, "--trillian_log_server.port=8091", "--trillian_log_server.sharding_config=/sharding/sharding-config.yaml", "--redis_server.address=rekor-redis", @@ -152,17 +142,4 @@ func (r *SecuresignReconciler) ensureRekorDeployment(ctx context.Context, m *rht }, }, } - - // Check if this Deployment already exists else create it - err := r.Get(ctx, client.ObjectKey{Name: dep.Name, Namespace: namespace}, dep) - // If the Deployment doesn't exist, create it but if it does, do nothing - if err != nil { - log.Info("Creating a new Deployment") - err = r.Create(ctx, dep) - if err != nil { - log.Error(err, "Failed to create new Deployment") - return nil, err - } - } - return dep, nil } diff --git a/controllers/rekor/wait.go b/controllers/rekor/wait.go new file mode 100644 index 000000000..1817f4f3e --- /dev/null +++ b/controllers/rekor/wait.go @@ -0,0 +1,44 @@ +package rekor + +import ( + "context" + + rhtasv1alpha1 "github.com/securesign/operator/api/v1alpha1" + "github.com/securesign/operator/controllers/common" + commonUtils "github.com/securesign/operator/controllers/common/utils" +) + +func NewWaitAction() Action { + return &waitAction{} +} + +type waitAction struct { + common.BaseAction +} + +func (i waitAction) Name() string { + return "wait" +} + +func (i waitAction) CanHandle(Rekor *rhtasv1alpha1.Rekor) bool { + return Rekor.Status.Phase == rhtasv1alpha1.PhaseInitialization +} + +func (i waitAction) Handle(ctx context.Context, instance *rhtasv1alpha1.Rekor) (*rhtasv1alpha1.Rekor, error) { + var ( + ok bool + err error + ) + for _, deployment := range []string{"rekor-server", "rekor-redis"} { + ok, err = commonUtils.DeploymentIsRunning(ctx, i.Client, instance.Namespace, deployment) + if err != nil { + instance.Status.Phase = rhtasv1alpha1.PhaseError + return instance, err + } + if !ok { + return instance, nil + } + } + instance.Status.Phase = rhtasv1alpha1.PhaseReady + return instance, nil +} diff --git a/controllers/rekor_cert_secret.go b/controllers/rekor_cert_secret.go deleted file mode 100644 index 0b9fed64a..000000000 --- a/controllers/rekor_cert_secret.go +++ /dev/null @@ -1,41 +0,0 @@ -package controllers - -import ( - "context" - - client "sigs.k8s.io/controller-runtime/pkg/client" - - rhtasv1alpha1 "github.com/securesign/operator/api/v1alpha1" - corev1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - ctrllog "sigs.k8s.io/controller-runtime/pkg/log" -) - -func (r *SecuresignReconciler) ensureRekorSecret(ctx context.Context, m *rhtasv1alpha1.Securesign, namespace string, secretName string) (*corev1.Secret, - error) { - log := ctrllog.FromContext(ctx) - log.Info("ensuring secret") - // Define a new Secret object - secret := &corev1.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Name: secretName, - Namespace: namespace, - }, - Type: "Opaque", - Data: map[string][]byte{ - "private": []byte(m.Spec.RekorPrivateKey), - }, - } - // Check if this Secret already exists else create it in the namespace - err := r.Get(ctx, client.ObjectKey{Name: secret.Name, Namespace: namespace}, secret) - // If the Secret doesn't exist, create it but if it does, do nothing - if err != nil { - log.Info("Creating a new Secret") - err = r.Create(ctx, secret) - if err != nil { - log.Error(err, "Failed to create new Secret") - return nil, err - } - } - return secret, nil -} diff --git a/controllers/role.go b/controllers/role.go deleted file mode 100644 index 8e22f56d1..000000000 --- a/controllers/role.go +++ /dev/null @@ -1,65 +0,0 @@ -package controllers - -import ( - "context" - - client "sigs.k8s.io/controller-runtime/pkg/client" - - rhtasv1alpha1 "github.com/securesign/operator/api/v1alpha1" - rbac "k8s.io/api/rbac/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - ctrllog "sigs.k8s.io/controller-runtime/pkg/log" -) - -func (r *SecuresignReconciler) ensureRole(ctx context.Context, securesign *rhtasv1alpha1.Securesign, namespace string, roleName string, component string) (*rbac.Role, error) { - log := ctrllog.FromContext(ctx) - - role := &rbac.Role{ - ObjectMeta: metav1.ObjectMeta{ - Name: roleName, - Namespace: namespace, - Labels: map[string]string{ - "app.kubernetes.io/name": component, - "app.kubernetes.io/instance": "trusted-artifact-signer", - }, - }, - Rules: []rbac.PolicyRule{ - { - APIGroups: []string{""}, - Resources: []string{"configmaps"}, - ResourceNames: []string{component + "-config"}, - Verbs: []string{"get", "update"}, - }, - }, - } - - // if roleNmae is ctlog-secret-operator add additional secret access - if roleName == "ctlog-secret-operator" { - role.Rules = append(role.Rules, rbac.PolicyRule{ - APIGroups: []string{""}, - Resources: []string{"secrets"}, - Verbs: []string{"create", "get", "update"}, - }) - } - - // if roleNmae is tuf replace the contents of the rule with secrets and create, get, update, delete - if roleName == "tuf" { - role.Rules = []rbac.PolicyRule{ - { - APIGroups: []string{""}, - Resources: []string{"secrets"}, - Verbs: []string{"create", "get", "update"}, - }, - } - } - err := r.Get(ctx, client.ObjectKey{Name: roleName, Namespace: namespace}, role) - if err != nil { - log.Info("Creating Role", "Role.Namespace", role.Namespace, "Role.Name", role.Name) - err = r.Create(ctx, role) - if err != nil { - log.Error(err, "Failed to create new Role", "Role.Namespace", role.Namespace, "Role.Name", role.Name) - return nil, err - } - } - return role, nil -} diff --git a/controllers/role_binding.go b/controllers/role_binding.go deleted file mode 100644 index 4ccccd460..000000000 --- a/controllers/role_binding.go +++ /dev/null @@ -1,59 +0,0 @@ -package controllers - -import ( - "context" - - client "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/log" - - rhtasv1alpha1 "github.com/securesign/operator/api/v1alpha1" - rbac "k8s.io/api/rbac/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -func (r *SecuresignReconciler) ensureRoleBinding(ctx context.Context, securesign *rhtasv1alpha1.Securesign, namespace string, bindingName string, roleName string, serviceAccount string, component string, tufNS string, ctNS string) (*rbac.RoleBinding, error) { - log := log.FromContext(ctx) - - roleBinding := &rbac.RoleBinding{ - ObjectMeta: metav1.ObjectMeta{ - Name: bindingName, - Namespace: namespace, - Labels: map[string]string{ - "app.kubernetes.io/name": component, - "app.kubernetes.io/instance": "trusted-artifact-signer", - }, - }, - Subjects: []rbac.Subject{ - { - Kind: "ServiceAccount", - Name: serviceAccount, - Namespace: namespace, - }, - }, - RoleRef: rbac.RoleRef{ - APIGroup: "rbac.authorization.k8s.io", - Kind: "Role", - Name: roleName, - }, - } - - // If the bindingName is tuf-secret-copy-job* then change the kind of Role to clusterrole - // The Namespace for the serviceAccount will be tuf-system - if bindingName == "tuf-secret-copy-job-fulcio-binding" || bindingName == "tuf-secret-copy-job-binding" || bindingName == "tuf-secret-copy-job-rekor-binding" || bindingName == "tuf-secret-copy-job-ctlog-binding" { - roleBinding.RoleRef.Kind = "ClusterRole" - roleBinding.Subjects[0].Namespace = tufNS - } - if bindingName == "trusted-artifact-signer-ctlog-createctconfig" { - roleBinding.Subjects[0].Namespace = ctNS - } - err := r.Get(ctx, client.ObjectKey{Name: bindingName, Namespace: namespace}, roleBinding) - if err != nil { - log.Info("Creating RoleBinding", "RoleBinding.Namespace", roleBinding.Namespace, "RoleBinding.Name", roleBinding.Name) - err = r.Create(ctx, roleBinding) - if err != nil { - log.Error(err, "Failed to create new RoleBinding", "RoleBinding.Namespace", roleBinding.Namespace, "RoleBinding.Name", roleBinding.Name) - return nil, err - } - } - return roleBinding, nil -} diff --git a/controllers/securesign_controller.go b/controllers/securesign_controller.go index 985171a90..f7e1c1c78 100644 --- a/controllers/securesign_controller.go +++ b/controllers/securesign_controller.go @@ -22,7 +22,9 @@ import ( "time" corev1 "k8s.io/api/core/v1" + rbac "k8s.io/api/rbac/v1" "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" @@ -67,7 +69,7 @@ func (r *SecuresignReconciler) Reconcile(ctx context.Context, req ctrl.Request) return ctrl.Result{}, fmt.Errorf("failed to ensure tas: %w", err) } - // Add finalizer for this CR + //Add finalizer for this CR if !controllerutil.ContainsFinalizer(instance, finalizer) { controllerutil.AddFinalizer(instance, finalizer) err = r.Update(ctx, instance) @@ -82,320 +84,75 @@ func (r *SecuresignReconciler) Reconcile(ctx context.Context, req ctrl.Request) return ctrl.Result{}, r.Update(ctx, instance) } - // Reconcile the tracked objects - err = r.createTrackedObjects(ctx, instance) - if err != nil { - log.Error(err, "failed to reconcile tas cluster") + if err := r.ensureSa(ctx, instance); err != nil { return failResult, err } - return ctrl.Result{Requeue: false}, nil -} -// createTrackedObjects Creates a mapping from client objects to their mutating functions. -func (r *SecuresignReconciler) createTrackedObjects( - ctx context.Context, - instance *rhtasv1alpha1.Securesign, -) error { - var err error - // ClusterRole - var copyRole = "tas-secret-copy-job-role" - - // REKOR - var rkn *corev1.Namespace - var rekorNamespace = "rekor-system" - var rrSA = "rekor-redis" - var rrsa *corev1.ServiceAccount - var rsSA = "rekor-server" - var rssa *corev1.ServiceAccount - var rtasCTSA = "trusted-artifact-signer-rekor-createtree" - var rtasctsa *corev1.ServiceAccount - - // FULCIO - var fun *corev1.Namespace - var fulcioNamespace = "fulcio-system" - var fSA = "fulcio-server" - var fsa *corev1.ServiceAccount - - // CTLOG - var ctn *corev1.Namespace - var ctlogNamespace = "ctlog-system" - var ctlogSA = "ctlog" - var ctsa *corev1.ServiceAccount - var ctCTSA = "ctlog-createtree" - var ctctsa *corev1.ServiceAccount - var ctlogTASCCSA = "trusted-artifact-signer-ctlog-createctconfig" - var ctctasccsa *corev1.ServiceAccount - - // TRILLIAN - var trn *corev1.Namespace - var trillianNamespace = "trillian-system" - var tlsSA = "trillian-logserver" - var tlssa *corev1.ServiceAccount - var tlsnrSA = "trillian-logsigner" - var tlsnrsa *corev1.ServiceAccount - var tDBSA = "trillian-mysql" - var tdbsa *corev1.ServiceAccount - var trilllogServ = "registry.redhat.io/rhtas-tech-preview/trillian-logserver-rhel9@sha256:43bfc6b7b8ed902592f19b830103d9030b59862f959c97c376cededba2ac3a03" - var trilllogSign = "registry.redhat.io/rhtas-tech-preview/trillian-logsigner-rhel9@sha256:fa2717c1d54400ca74cc3e9038bdf332fa834c0f5bc3215139c2d0e3579fc292" - var trillDb = "registry.redhat.io/rhtas-tech-preview/trillian-database-rhel9@sha256:fe4758ff57a9a6943a4655b21af63fb579384dc51838af85d0089c04290b4957" - var trillPVC *corev1.PersistentVolumeClaim - var dbSecret *corev1.Secret - - // TUF - var tun *corev1.Namespace - var tufNamespace = "tuf-system" - var tstufSA = "tuf" - var tstufsa *corev1.ServiceAccount - var tscjSA = "tuf-secret-copy-job" - var tscjsa *corev1.ServiceAccount - - // TRUSTED ARTIFACT SIGNER - var tascs *corev1.Namespace - var tasNamespace = "trusted-artifact-signer-clientserver" - var tascSA = "tas-clients" - var tascsa *corev1.ServiceAccount - - // Create clusterrole - if _, err = r.ensureClusterRole(ctx, instance, copyRole); err != nil { - return fmt.Errorf("could not ensure clusterrole: %w", err) - } - // Create the namespaces - if tun, err = r.ensureNamespace(ctx, instance, tufNamespace); err != nil { - return fmt.Errorf("could not ensure namespace tuf-system. %w", err) - } - if trn, err = r.ensureNamespace(ctx, instance, trillianNamespace); err != nil { - return fmt.Errorf("could not ensure namespace trillian-system. %w", err) - } - if rkn, err = r.ensureNamespace(ctx, instance, rekorNamespace); err != nil { - return fmt.Errorf("could not ensure namespace rekor-system. %w", err) - } - if fun, err = r.ensureNamespace(ctx, instance, fulcioNamespace); err != nil { - return fmt.Errorf("could not ensure namespace fulcio-system. %w", err) - } - if ctn, err = r.ensureNamespace(ctx, instance, ctlogNamespace); err != nil { - return fmt.Errorf("could not ensure namespace ctlog-system. %w", err) - } - if tascs, err = r.ensureNamespace(ctx, instance, tasNamespace); err != nil { - return fmt.Errorf("could not ensure namespace trusted-artifact-signer-clientserver. %w", err) - } - // Create roles - // CTLOG - if _, err = r.ensureRole(ctx, instance, ctn.Name, "ctlog-cm-operator", "ctlog"); err != nil { - return fmt.Errorf("could not ensure role: %w", err) - } - if _, err = r.ensureRole(ctx, instance, ctn.Name, "ctlog-secret-operator", "ctlog"); err != nil { - return fmt.Errorf("could not ensure role: %w", err) - } - // REKOR - if _, err = r.ensureRole(ctx, instance, rkn.Name, "rekor-cm-operator", "rekor"); err != nil { - return fmt.Errorf("could not ensure role: %w", err) - } - // TUF - if _, err = r.ensureRole(ctx, instance, tun.Name, "tuf", "tuf"); err != nil { - return fmt.Errorf("could not ensure role: %w", err) - } - // Create the service accounts - // CTLOG - if ctsa, err = r.ensureSA(ctx, instance, ctn.Name, ctlogSA); err != nil { - return fmt.Errorf("retrieved error while ensuring SA: %w", err) - } - if ctctsa, err = r.ensureSA(ctx, instance, ctn.Name, ctCTSA); err != nil { - return fmt.Errorf("retrieved error while ensuring SA: %w", err) - } - if ctctasccsa, err = r.ensureSA(ctx, instance, ctn.Name, ctlogTASCCSA); err != nil { - return fmt.Errorf("retrieved error while ensuring SA: %w", err) - } - // FULCIO - if fsa, err = r.ensureSA(ctx, instance, fun.Name, fSA); err != nil { - return fmt.Errorf("retrieved error while ensuring SA: %w", err) - } - // REKOR - if rrsa, err = r.ensureSA(ctx, instance, rkn.Name, rrSA); err != nil { - return fmt.Errorf("retrieved error while ensuring SA: %w", err) - } - if rssa, err = r.ensureSA(ctx, instance, rkn.Name, rsSA); err != nil { - return fmt.Errorf("retrieved error while ensuring SA: %w", err) - } - if rtasctsa, err = r.ensureSA(ctx, instance, rkn.Name, rtasCTSA); err != nil { - return fmt.Errorf("retrieved error while ensuring SA: %w", err) - } - // TRILLIAN - if tlssa, err = r.ensureSA(ctx, instance, trn.Name, tlsSA); err != nil { - return fmt.Errorf("retrieved error while ensuring SA: %w", err) - } - if tlsnrsa, err = r.ensureSA(ctx, instance, trn.Name, tlsnrSA); err != nil { - return fmt.Errorf("retrieved error while ensuring SA: %w", err) - } - if tdbsa, err = r.ensureSA(ctx, instance, trn.Name, tDBSA); err != nil { - return fmt.Errorf("retrieved error while ensuring SA: %w", err) - } - // TRUSTED ARTIFACT SIGNER - if tascsa, err = r.ensureSA(ctx, instance, tascs.Name, tascSA); err != nil { - return fmt.Errorf("retrieved error while ensuring SA: %w", err) - } - // TUF - if tstufsa, err = r.ensureSA(ctx, instance, tun.Name, tstufSA); err != nil { - return fmt.Errorf("retrieved error while ensuring SA: %w", err) - } - if tscjsa, err = r.ensureSA(ctx, instance, tun.Name, tscjSA); err != nil { - return fmt.Errorf("retrieved error while ensuring SA: %w", err) - } - // Create the rolebindings - // CTLOG - if _, err = r.ensureRoleBinding(ctx, instance, ctn.Name, "ctlog-secret-operator", "ctlog-secret-operator", ctctasccsa.Name, "ctlog", tun.Name, ctn.Name); err != nil { - return fmt.Errorf("could not ensure rolebinding: %w", err) - } - if _, err = r.ensureRoleBinding(ctx, instance, ctn.Name, "ctlog-cm-operator", "ctlog-cm-operator", ctctsa.Name, "ctlog", tun.Name, ctn.Name); err != nil { - return fmt.Errorf("could not ensure rolebinding: %w", err) - } - // REKOR - if _, err = r.ensureRoleBinding(ctx, instance, rkn.Name, "rekor-cm-operator", "rekor-cm-operator", rtasctsa.Name, "rekor", tun.Name, ctn.Name); err != nil { - return fmt.Errorf("could not ensure rolebinding: %w", err) - } - // TUF - if _, err = r.ensureRoleBinding(ctx, instance, tun.Name, "tuf", "tuf", tstufsa.Name, "tuf", tun.Name, ctn.Name); err != nil { - return fmt.Errorf("could not ensure rolebinding: %w", err) - } - if _, err = r.ensureRoleBinding(ctx, instance, rkn.Name, "tuf-secret-copy-job-rekor-binding", "tas-secret-copy-job-role", tscjsa.Name, "tuf", tun.Name, ctn.Name); err != nil { - return fmt.Errorf("could not ensure rolebinding: %w", err) - } - if _, err = r.ensureRoleBinding(ctx, instance, ctn.Name, "tuf-secret-copy-job-ctlog-binding", "tas-secret-copy-job-role", tscjsa.Name, "tuf", tun.Name, ctn.Name); err != nil { - return fmt.Errorf("could not ensure rolebinding: %w", err) - } - if _, err = r.ensureRoleBinding(ctx, instance, fun.Name, "tuf-secret-copy-job-fulcio-binding", "tas-secret-copy-job-role", tscjsa.Name, "tuf", tun.Name, ctn.Name); err != nil { - return fmt.Errorf("could not ensure rolebinding: %w", err) - } - if _, err = r.ensureRoleBinding(ctx, instance, tun.Name, "tuf-secret-copy-job-binding", "tas-secret-copy-job-role", tscjsa.Name, "tuf", tun.Name, ctn.Name); err != nil { - return fmt.Errorf("could not ensure rolebinding: %w", err) - } - // Create Job - if _, err = r.ensureTufCopyJob(ctx, instance, tun.Name, tscjsa.Name, "tuf-secret-copy-job", rkn.Name, fun.Name, ctn.Name); err != nil { - return fmt.Errorf("could not ensure job: %w", err) - } - if _, err = r.ensureCTJob(ctx, instance, rkn.Name, rtasctsa.Name, "rekor", "trusted-artifact-signer-rekor-createtree", trn.Name); err != nil { - return fmt.Errorf("could not ensure job: %w", err) - } - if _, err = r.ensureCreateCTJob(ctx, instance, ctn.Name, ctctasccsa.Name, "trusted-artifact-signer-ctlog-createctconfig", fun.Name, trn.Name); err != nil { - return fmt.Errorf("could not ensure job: %w", err) - } - if _, err = r.ensureCTJob(ctx, instance, ctn.Name, ctctsa.Name, "ctlog", "ctlog-createtree", trn.Name); err != nil { - return fmt.Errorf("could not ensure job: %w", err) - } - //if _, err = r.ensureCreateDbJob(ctx, instance, trn.Name, tlssa.Name, "trillian", "trusted-artifact-signer-trillian-createdb", dbSecret.Name); err != nil { - // return fmt.Errorf("could not ensure job: %w", err) - //} - // Create PVC - // Trillian - if trillPVC, err = r.ensurePVC(ctx, instance, trn.Name, "trillian-mysql"); err != nil { - return fmt.Errorf("could not ensure pvc: %w", err) - } - if _, err = r.ensurePVC(ctx, instance, rkn.Name, "rekor-server"); err != nil { - return fmt.Errorf("could not ensure pvc: %w", err) - } - // Create ConfigMap - // Rekor - if _, err = r.ensureConfigMap(ctx, instance, rkn.Name, "rekor-config", "rekor"); err != nil { - return fmt.Errorf("could not ensure configmap: %w", err) - } - if _, err = r.ensureConfigMap(ctx, instance, rkn.Name, "rekor-sharding-config", "rekor"); err != nil { - return fmt.Errorf("could not ensure configmap: %w", err) - } - // Ctlog - if _, err = r.ensureConfigMap(ctx, instance, ctn.Name, "ctlog-config", "ctlog"); err != nil { - return fmt.Errorf("could not ensure configmap: %w", err) - } - // Fulcio - if _, err = r.ensureOIDCConfigMap(ctx, instance, fun.Name, "fulcio-server-config", "fulcio"); err != nil { - return fmt.Errorf("could not ensure configmap: %w", err) + if err := r.ensureRole(ctx, instance); err != nil { + return failResult, err } - // Create Secret - // Trillian - if dbSecret, err = r.ensureDBSecret(ctx, instance, trn.Name, "trillian-mysql"); err != nil { - return fmt.Errorf("could not ensure secret: %w", err) - } - // Fulcio - // if _, err = r.ensureFulcioSecret(ctx, instance, fun.Name, "fulcio-secret-rh"); err != nil { - // return fmt.Errorf("could not ensure secret: %w", err) - // } - // Rekor - if _, err = r.ensureRekorSecret(ctx, instance, rkn.Name, "rekor-private-key"); err != nil { - return fmt.Errorf("could not ensure secret: %w", err) + if err := r.ensureRoleBinding(ctx, instance); err != nil { + return failResult, err } - // Create Service - // Trillian - if _, err = r.ensureService(ctx, instance, trn.Name, "trillian-mysql", "mysql", "trillian", 3306); err != nil { - return fmt.Errorf("could not ensure service: %w", err) - } - if _, err = r.ensureService(ctx, instance, trn.Name, "trillian-logserver", "trillian-logserver", "trillian", 8091); err != nil { - return fmt.Errorf("could not ensure service: %w", err) - } - if _, err = r.ensureService(ctx, instance, trn.Name, "trillian-logsigner", "trillian-logsigner", "trillian", 8091); err != nil { - return fmt.Errorf("could not ensure service: %w", err) - } - // Ctlog - if _, err = r.ensureService(ctx, instance, ctn.Name, "ctlog", "ctlog", "ctlog", 6963); err != nil { - return fmt.Errorf("could not ensure service: %w", err) - } - // Rekor - if _, err = r.ensureService(ctx, instance, rkn.Name, "rekor-server", "rekor-server", "rekor-server", 2112); err != nil { - return fmt.Errorf("could not ensure service: %w", err) - } - if _, err = r.ensureService(ctx, instance, rkn.Name, "rekor-redis", "redis", "rekor", 6379); err != nil { - return fmt.Errorf("could not ensure service: %w", err) - } - // Fulcio - if _, err = r.ensureService(ctx, instance, fun.Name, "fulcio-server", "fulcio-server", "fulcio", 2112); err != nil { - return fmt.Errorf("could not ensure service: %w", err) - } - // TUF - if _, err = r.ensureService(ctx, instance, tun.Name, "tuf", "tuf", "tuf", 80); err != nil { - return fmt.Errorf("could not ensure service: %w", err) - } - // Trusted Artifact Signer - if _, err = r.ensureService(ctx, instance, tascs.Name, "tas-clients", "tas-clients", "tas", 8080); err != nil { - return fmt.Errorf("could not ensure service: %w", err) + // Reconcile the tracked objects + var update bool + update, err = r.ensureTrillian(ctx, instance) + if err != nil { + log.Error(err, "failed to reconcile tas cluster") + return failResult, err } - - // Create the deployments - // Ctlog - if _, err = r.ensurectDeployment(ctx, instance, ctn.Name, "ctlog", ctsa.Name, "ctlog"); err != nil { - return fmt.Errorf("could not ensure deployment: %w", err) + if update { + r.Status().Update(ctx, instance) + return ctrl.Result{Requeue: true}, nil } - // Trillian - if _, err = r.ensureTrillDeployment(ctx, instance, trn.Name, tlssa.Name, "trillian-logserver", trilllogServ, dbSecret.Name); err != nil { - return fmt.Errorf("could not ensure deployment: %w", err) + update, err = r.ensureTuf(ctx, instance) + if err != nil { + log.Error(err, "failed to reconcile tas cluster") + return failResult, err } - if _, err = r.ensureTrillDeployment(ctx, instance, trn.Name, tlsnrsa.Name, "trillian-logsigner", trilllogSign, dbSecret.Name); err != nil { - return fmt.Errorf("could not ensure deployment: %w", err) + if update { + r.Status().Update(ctx, instance) + return ctrl.Result{Requeue: true}, nil } - if _, err = r.ensureTrillDb(ctx, instance, trn.Name, tdbsa.Name, "trillian-mysql", trillDb, trillPVC.Name, dbSecret.Name); err != nil { - return fmt.Errorf("could not ensure deployment: %w", err) + + update, err = r.ensureFulcio(ctx, instance) + if err != nil { + log.Error(err, "failed to reconcile tas cluster") + return failResult, err } - // Rekor - if _, err = r.ensureRekorDeployment(ctx, instance, rkn.Name, rssa.Name, "rekor-server", trn.Name); err != nil { - return fmt.Errorf("could not ensure deployment: %w", err) + if update { + r.Status().Update(ctx, instance) + return ctrl.Result{Requeue: true}, nil } - if _, err = r.ensureRedisDeployment(ctx, instance, rkn.Name, rrsa.Name, "rekor-redis"); err != nil { - return fmt.Errorf("could not ensure deployment: %w", err) + + update, err = r.ensureRekor(ctx, instance) + if err != nil { + log.Error(err, "failed to reconcile tas cluster") + return failResult, err } - // Fulcio - if _, err = r.ensureFulDeployment(ctx, instance, fun.Name, "fulcio-server", fsa.Name, "fulcio-server", "fulcio"); err != nil { - return fmt.Errorf("could not ensure deployment: %w", err) + if update { + r.Status().Update(ctx, instance) + return ctrl.Result{Requeue: true}, nil } - // TUF - if _, err = r.ensureTufDeployment(ctx, instance, tun.Name, tstufsa.Name, "tuf"); err != nil { - return fmt.Errorf("could not ensure deployment: %w", err) + + update, err = r.ensureCTlog(ctx, instance) + if err != nil { + log.Error(err, "failed to reconcile tas cluster") + return failResult, err } - // Trusted Artifact Signer - if _, err = r.ensureTasDeployment(ctx, instance, tascs.Name, tascsa.Name, "tas-clients"); err != nil { - return fmt.Errorf("could not ensure deployment: %w", err) + if update { + r.Status().Update(ctx, instance) + return ctrl.Result{Requeue: true}, nil } - return nil + + return ctrl.Result{}, nil } +// createTrackedObjects Creates a mapping from client objects to their mutating functions. + func (r *SecuresignReconciler) ensureSecureSign( ctx context.Context, req ctrl.Request, @@ -403,7 +160,7 @@ func (r *SecuresignReconciler) ensureSecureSign( var err error instance := &rhtasv1alpha1.Securesign{} if err = r.Get(ctx, req.NamespacedName, instance); err == nil { - return instance, nil + return instance.DeepCopy(), nil } if errors.IsNotFound(err) { // Request object not found, could have been deleted after reconcile request. @@ -415,6 +172,217 @@ func (r *SecuresignReconciler) ensureSecureSign( return nil, fmt.Errorf("failed to get SecureSign: %w", err) } +func (r *SecuresignReconciler) ensureTrillian( + ctx context.Context, + securesign *rhtasv1alpha1.Securesign, +) (bool, error) { + if securesign.Status.Trillian == "" { + instance := &rhtasv1alpha1.Trillian{} + instance.GenerateName = securesign.Name + instance.Namespace = securesign.Namespace + instance.Spec = securesign.Spec.Trillian + ctrl.SetControllerReference(securesign, instance, r.Scheme) + + if err := r.Create(ctx, instance); err != nil { + return false, err + } + securesign.Status.Trillian = instance.Name + return true, nil + } + return false, nil +} + +func (r *SecuresignReconciler) ensureCTlog( + ctx context.Context, + securesign *rhtasv1alpha1.Securesign, +) (bool, error) { + if securesign.Status.CTlog == "" { + instance := &rhtasv1alpha1.CTlog{} + instance.GenerateName = securesign.Name + instance.Namespace = securesign.Namespace + instance.Spec = securesign.Spec.Ctlog + ctrl.SetControllerReference(securesign, instance, r.Scheme) + + if err := r.Create(ctx, instance); err != nil { + return false, err + } + securesign.Status.CTlog = instance.Name + return true, nil + } + return false, nil +} + +func (r *SecuresignReconciler) ensureTuf( + ctx context.Context, + securesign *rhtasv1alpha1.Securesign, +) (bool, error) { + if securesign.Status.Tuf == "" { + instance := &rhtasv1alpha1.Tuf{} + instance.GenerateName = securesign.Name + instance.Namespace = securesign.Namespace + instance.Spec = securesign.Spec.Tuf + ctrl.SetControllerReference(securesign, instance, r.Scheme) + + if err := r.Create(ctx, instance); err != nil { + return false, err + } + securesign.Status.Tuf = instance.Name + return true, nil + } + return false, nil +} + +func (r *SecuresignReconciler) ensureFulcio( + ctx context.Context, + securesign *rhtasv1alpha1.Securesign, +) (bool, error) { + if securesign.Status.Fulcio == "" { + instance := &rhtasv1alpha1.Fulcio{} + + instance.GenerateName = securesign.Name + instance.Namespace = securesign.Namespace + ctrl.SetControllerReference(securesign, instance, r.Scheme) + + instance.Spec = securesign.Spec.Fulcio + if err := r.Create(ctx, instance); err != nil { + return false, err + } + securesign.Status.Fulcio = instance.Name + return true, nil + } + return false, nil +} + +func (r *SecuresignReconciler) ensureRekor( + ctx context.Context, + securesign *rhtasv1alpha1.Securesign, +) (bool, error) { + if securesign.Status.Rekor == "" { + instance := &rhtasv1alpha1.Rekor{} + + instance.GenerateName = securesign.Name + instance.Namespace = securesign.Namespace + ctrl.SetControllerReference(securesign, instance, r.Scheme) + + instance.Spec = securesign.Spec.Rekor + if err := r.Create(ctx, instance); err != nil { + return false, err + } + securesign.Status.Rekor = instance.Name + return true, nil + } + return false, nil +} + +func (r *SecuresignReconciler) ensureSa( + ctx context.Context, + securesign *rhtasv1alpha1.Securesign, +) error { + sa := &corev1.ServiceAccount{ + ObjectMeta: metav1.ObjectMeta{ + Name: "sigstore-sa", + Namespace: securesign.Namespace, + }, + ImagePullSecrets: []corev1.LocalObjectReference{ + { + Name: "pull-secret", + }, + }, + } + // Check if this service account already exists else create it in the namespace + err := r.Get(ctx, client.ObjectKey{Name: sa.Name, Namespace: securesign.Namespace}, sa) + // If the SA doesn't exist, create it but if it does, do nothing + if err != nil { + err = r.Create(ctx, sa) + if err != nil { + return err + } + } + return nil +} + +func (r *SecuresignReconciler) ensureRole( + ctx context.Context, + securesign *rhtasv1alpha1.Securesign, +) error { + name := "securesign" + role := &rbac.Role{ + ObjectMeta: metav1.ObjectMeta{ + Name: name, + Namespace: securesign.Namespace, + Labels: map[string]string{ + "app.kubernetes.io/name": "securesign", + "app.kubernetes.io/instance": "trusted-artifact-signer", + }, + }, + Rules: []rbac.PolicyRule{ + { + APIGroups: []string{""}, + Resources: []string{"configmaps"}, + Verbs: []string{"create", "get", "update"}, + }, + { + APIGroups: []string{""}, + Resources: []string{"secrets"}, + Verbs: []string{"create", "get", "update"}, + }, + }, + } + + err := r.Get(ctx, client.ObjectKey{Name: name, Namespace: securesign.Namespace}, role) + if err != nil { + err = r.Create(ctx, role) + if err != nil { + return err + } + } + return nil +} + +func (r *SecuresignReconciler) ensureRoleBinding( + ctx context.Context, + securesign *rhtasv1alpha1.Securesign, +) error { + + name := "securesign" + roleBinding := &rbac.RoleBinding{ + ObjectMeta: metav1.ObjectMeta{ + Name: name, + Namespace: securesign.Namespace, + Labels: map[string]string{ + "app.kubernetes.io/name": name, + "app.kubernetes.io/instance": "trusted-artifact-signer", + }, + }, + + // todo: remove hardcoded names + Subjects: []rbac.Subject{ + { + Kind: "ServiceAccount", + Name: "sigstore-sa", + Namespace: securesign.Namespace, + }, + }, + RoleRef: rbac.RoleRef{ + APIGroup: "rbac.authorization.k8s.io", + Kind: "Role", + Name: "securesign", + }, + } + + // If the bindingName is tuf-secret-copy-job* then change the kind of Role to clusterrole + // The Namespace for the serviceAccount will be tuf-system + + err := r.Get(ctx, client.ObjectKey{Name: name, Namespace: securesign.Namespace}, roleBinding) + if err != nil { + err = r.Create(ctx, roleBinding) + if err != nil { + return err + } + } + return nil +} + // SetupWithManager sets up the controller with the Manager. func (r *SecuresignReconciler) SetupWithManager(mgr ctrl.Manager) error { return ctrl.NewControllerManagedBy(mgr). diff --git a/controllers/service.go b/controllers/service.go deleted file mode 100644 index 0f0c790f9..000000000 --- a/controllers/service.go +++ /dev/null @@ -1,102 +0,0 @@ -package controllers - -import ( - "context" - - client "sigs.k8s.io/controller-runtime/pkg/client" - - corev1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - - rhtasv1alpha1 "github.com/securesign/operator/api/v1alpha1" - "k8s.io/apimachinery/pkg/util/intstr" - "sigs.k8s.io/controller-runtime/pkg/log" -) - -func (r *SecuresignReconciler) ensureService(ctx context.Context, m *rhtasv1alpha1.Securesign, namespace string, name string, component string, ssapp string, port int) (*corev1.Service, error) { - logger := log.FromContext(ctx) - svc := &corev1.Service{ - ObjectMeta: metav1.ObjectMeta{ - Name: name, - Namespace: namespace, - Labels: map[string]string{ - "app.kubernetes.io/component": component, - "app.kubernetes.io/name": ssapp, - "app.kubernetes.io/instance": "trusted-artifact-signer", - }, - }, - Spec: corev1.ServiceSpec{ - Selector: map[string]string{ - "app.kubernetes.io/component": component, - "app.kubernetes.io/name": ssapp, - "app.kubernetes.io/instance": "trusted-artifact-signer", - }, - Ports: []corev1.ServicePort{ - { - Name: name, - Protocol: corev1.ProtocolTCP, - Port: int32(port), - TargetPort: intstr.FromInt(port), - }, - }, - }, - } - - // if trillian-logsigner add an additional service port of 8090 - if component == "trillian-logserver" { - svc.Spec.Ports = append(svc.Spec.Ports, corev1.ServicePort{ - Name: "8090-tcp", - Protocol: corev1.ProtocolTCP, - Port: 8090, - TargetPort: intstr.FromInt(8090), - }) - } - // if rekor-server add an additional service port of 2112 - if component == "rekor-server" { - svc.Spec.Ports = append(svc.Spec.Ports, corev1.ServicePort{ - Name: "3000-tcp", - Protocol: corev1.ProtocolTCP, - Port: 80, - TargetPort: intstr.FromInt(3000), - }) - } - // if fulcio-system add an additional service port of 5554 2112 - if component == "fulcio-server" { - svc.Spec.Ports = append(svc.Spec.Ports, corev1.ServicePort{ - Name: "5554-tcp", - Protocol: corev1.ProtocolTCP, - Port: 5554, - TargetPort: intstr.FromInt(5554), - }) - svc.Spec.Ports = append(svc.Spec.Ports, corev1.ServicePort{ - Name: "80-tcp", - Protocol: corev1.ProtocolTCP, - Port: 80, - TargetPort: intstr.FromInt(5555), - }) - } - // if ctlog add an additional service port of 80 - if component == "ctlog" { - svc.Spec.Ports = append(svc.Spec.Ports, corev1.ServicePort{ - Name: "80-tcp", - Protocol: corev1.ProtocolTCP, - Port: 80, - TargetPort: intstr.FromInt(6962), - }) - } - // if tuf-server replace targetPort with 8080 instead of 80 - if component == "tuf-server" { - svc.Spec.Ports[0].TargetPort = intstr.FromInt(8080) - } - - err := r.Get(ctx, client.ObjectKey{Name: svc.Name, Namespace: namespace}, svc) - if err != nil { - logger.Info("Creating a new Service") - err = r.Create(ctx, svc) - if err != nil { - logger.Error(err, "Failed to create new Service") - return nil, err - } - } - return svc, nil -} diff --git a/controllers/serviceaccount.go b/controllers/serviceaccount.go deleted file mode 100644 index b04df555f..000000000 --- a/controllers/serviceaccount.go +++ /dev/null @@ -1,42 +0,0 @@ -package controllers - -import ( - "context" - - client "sigs.k8s.io/controller-runtime/pkg/client" - - rhtasv1alpha1 "github.com/securesign/operator/api/v1alpha1" - corev1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - ctrllog "sigs.k8s.io/controller-runtime/pkg/log" -) - -func (r *SecuresignReconciler) ensureSA(ctx context.Context, m *rhtasv1alpha1.Securesign, namespace string, svcAccount string) (*corev1.ServiceAccount, - error) { - log := ctrllog.FromContext(ctx) - log.Info("ensuring service account") - // Define a new Service Account object - sa := &corev1.ServiceAccount{ - ObjectMeta: metav1.ObjectMeta{ - Name: svcAccount, - Namespace: namespace, - }, - ImagePullSecrets: []corev1.LocalObjectReference{ - { - Name: "pull-secret", - }, - }, - } - // Check if this service account already exists else create it in the namespace - err := r.Get(ctx, client.ObjectKey{Name: sa.Name, Namespace: namespace}, sa) - // If the SA doesn't exist, create it but if it does, do nothing - if err != nil { - log.Info("Creating a new Service Account") - err = r.Create(ctx, sa) - if err != nil { - log.Error(err, "Failed to create new service account") - return nil, err - } - } - return sa, nil -} diff --git a/controllers/suite_test.go b/controllers/suite_test.go deleted file mode 100644 index 1a9a41e7a..000000000 --- a/controllers/suite_test.go +++ /dev/null @@ -1,80 +0,0 @@ -/* -Copyright 2023. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package controllers - -import ( - "path/filepath" - "testing" - - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" - - "k8s.io/client-go/kubernetes/scheme" - "k8s.io/client-go/rest" - "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/envtest" - logf "sigs.k8s.io/controller-runtime/pkg/log" - "sigs.k8s.io/controller-runtime/pkg/log/zap" - - rhtasv1alpha1 "github.com/securesign/operator/api/v1alpha1" - //+kubebuilder:scaffold:imports -) - -// These tests use Ginkgo (BDD-style Go testing framework). Refer to -// http://onsi.github.io/ginkgo/ to learn more about Ginkgo. - -var cfg *rest.Config -var k8sClient client.Client -var testEnv *envtest.Environment - -func TestAPIs(t *testing.T) { - RegisterFailHandler(Fail) - - RunSpecs(t, "Controller Suite") -} - -var _ = BeforeSuite(func() { - logf.SetLogger(zap.New(zap.WriteTo(GinkgoWriter), zap.UseDevMode(true))) - - By("bootstrapping test environment") - testEnv = &envtest.Environment{ - CRDDirectoryPaths: []string{filepath.Join("..", "config", "crd", "bases")}, - ErrorIfCRDPathMissing: true, - } - - var err error - // cfg is defined in this file globally. - cfg, err = testEnv.Start() - Expect(err).NotTo(HaveOccurred()) - Expect(cfg).NotTo(BeNil()) - - err = rhtasv1alpha1.AddToScheme(scheme.Scheme) - Expect(err).NotTo(HaveOccurred()) - - //+kubebuilder:scaffold:scheme - - k8sClient, err = client.New(cfg, client.Options{Scheme: scheme.Scheme}) - Expect(err).NotTo(HaveOccurred()) - Expect(k8sClient).NotTo(BeNil()) - -}) - -var _ = AfterSuite(func() { - By("tearing down the test environment") - err := testEnv.Stop() - Expect(err).NotTo(HaveOccurred()) -}) diff --git a/controllers/tas_deployment.go b/controllers/tas_deployment.go deleted file mode 100644 index cc722bba7..000000000 --- a/controllers/tas_deployment.go +++ /dev/null @@ -1,73 +0,0 @@ -package controllers - -import ( - "context" - - client "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/log" - - rhtasv1alpha1 "github.com/securesign/operator/api/v1alpha1" - apps "k8s.io/api/apps/v1" - core "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -func (r *SecuresignReconciler) ensureTasDeployment(ctx context.Context, m *rhtasv1alpha1.Securesign, namespace string, sA string, dpName string) (*apps.Deployment, - error) { - log := log.FromContext(ctx) - log.Info("ensuring deployment") - replicas := int32(1) - // Define a new Namespace object - dep := &apps.Deployment{ - ObjectMeta: metav1.ObjectMeta{ - Name: dpName, - Namespace: namespace, - Labels: map[string]string{ - "app.kubernetes.io/name": dpName, - }, - }, - Spec: apps.DeploymentSpec{ - Replicas: &replicas, - Selector: &metav1.LabelSelector{ - MatchLabels: map[string]string{ - "app.kubernetes.io/name": dpName, - }, - }, - Template: core.PodTemplateSpec{ - ObjectMeta: metav1.ObjectMeta{ - Labels: map[string]string{ - "app.kubernetes.io/name": dpName, - }, - }, - Spec: core.PodSpec{ - ServiceAccountName: sA, - Containers: []core.Container{ - { - Name: dpName, - Image: "registry.redhat.io/rhtas-tech-preview/client-server-rhel9@sha256:07b1c06290706873ee55e39bad5804ea1d7574b01909adf97d67495ad919f9a1", - Ports: []core.ContainerPort{ - { - Protocol: core.ProtocolTCP, - ContainerPort: 8080, - }, - }, - }, - }, - }, - }, - }, - } - - // Check if this Deployment already exists else create it - err := r.Get(ctx, client.ObjectKey{Name: dep.Name, Namespace: namespace}, dep) - // If the Deployment doesn't exist, create it but if it does, do nothing - if err != nil { - log.Info("Creating a new Deployment") - err = r.Create(ctx, dep) - if err != nil { - log.Error(err, "Failed to create new Deployment") - return nil, err - } - } - return dep, nil -} diff --git a/controllers/trillian/action.go b/controllers/trillian/action.go new file mode 100644 index 000000000..668f055ea --- /dev/null +++ b/controllers/trillian/action.go @@ -0,0 +1,23 @@ +package trillian + +import ( + "context" + + "github.com/securesign/operator/api/v1alpha1" + "k8s.io/client-go/tools/record" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +type Action interface { + InjectClient(client client.Client) + InjectRecorder(recorder record.EventRecorder) + + // a user friendly name for the action + Name() string + + // returns true if the action can handle the integration + CanHandle(trillian *v1alpha1.Trillian) bool + + // executes the handling function + Handle(ctx context.Context, trillian *v1alpha1.Trillian) (*v1alpha1.Trillian, error) +} diff --git a/controllers/trillian/init.go b/controllers/trillian/init.go new file mode 100644 index 000000000..83979080a --- /dev/null +++ b/controllers/trillian/init.go @@ -0,0 +1,126 @@ +package trillian + +import ( + "context" + "fmt" + + rhtasv1alpha1 "github.com/securesign/operator/api/v1alpha1" + "github.com/securesign/operator/controllers/common" + "github.com/securesign/operator/controllers/common/utils" + trillianUtils "github.com/securesign/operator/controllers/trillian/utils" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" +) + +const ( + dbDeploymentName = "trillian-db" + logserverDeploymentName = "trillian-logserver" + logsignerDeploymentName = "trillian-logsigner" +) + +func NewInitializeAction() Action { + return &initializeAction{} +} + +type initializeAction struct { + common.BaseAction +} + +func (i initializeAction) Name() string { + return "initialize" +} + +func (i initializeAction) CanHandle(trillian *rhtasv1alpha1.Trillian) bool { + return trillian.Status.Phase == rhtasv1alpha1.PhaseNone +} + +func (i initializeAction) Handle(ctx context.Context, instance *rhtasv1alpha1.Trillian) (*rhtasv1alpha1.Trillian, error) { + //log := ctrllog.FromContext(ctx) + var err error + + dbSecret := i.createDbSecret(instance.Namespace) + controllerutil.SetControllerReference(instance, dbSecret, i.Client.Scheme()) + if err = i.Client.Create(ctx, dbSecret); err != nil { + instance.Status.Phase = rhtasv1alpha1.PhaseError + return instance, fmt.Errorf("could not create secret: %w", err) + } + + var trillPVC string + if instance.Spec.PvcName == "" { + pvc := utils.CreatePVC(instance.Namespace, "trillian-mysql", "5Gi") + controllerutil.SetControllerReference(instance, pvc, i.Client.Scheme()) + if err = i.Client.Create(ctx, pvc); err != nil { + instance.Status.Phase = rhtasv1alpha1.PhaseError + return instance, fmt.Errorf("could not create pvc: %w", err) + } + trillPVC = pvc.Name + } else { + trillPVC = instance.Spec.PvcName + } + + db := trillianUtils.CreateTrillDb(instance.Namespace, instance.Spec.DbImage, dbDeploymentName, trillPVC, dbSecret.Name) + controllerutil.SetControllerReference(instance, db, i.Client.Scheme()) + if err = i.Client.Create(ctx, db); err != nil { + instance.Status.Phase = rhtasv1alpha1.PhaseError + return instance, fmt.Errorf("could not create trillian DB: %w", err) + } + + mysql := utils.CreateService(instance.Namespace, "trillian-mysql", "mysql", "trillian", 3306) + controllerutil.SetControllerReference(instance, mysql, i.Client.Scheme()) + if err = i.Client.Create(ctx, mysql); err != nil { + instance.Status.Phase = rhtasv1alpha1.PhaseError + return instance, fmt.Errorf("could not create service: %w", err) + } + + // Log Server + server := trillianUtils.CreateTrillDeployment(instance.Namespace, instance.Spec.ServerImage, logserverDeploymentName, dbSecret.Name) + controllerutil.SetControllerReference(instance, server, i.Client.Scheme()) + server.Spec.Template.Spec.Containers[0].Ports = append(server.Spec.Template.Spec.Containers[0].Ports, corev1.ContainerPort{ + Protocol: corev1.ProtocolTCP, + ContainerPort: 8090, + }) + if err = i.Client.Create(ctx, server); err != nil { + instance.Status.Phase = rhtasv1alpha1.PhaseError + return instance, fmt.Errorf("could not create job: %w", err) + } + + logserver := utils.CreateService(instance.Namespace, "trillian-logserver", "trillian-logserver", "trillian", 8091) + controllerutil.SetControllerReference(instance, logserver, i.Client.Scheme()) + if err = i.Client.Create(ctx, logserver); err != nil { + instance.Status.Phase = rhtasv1alpha1.PhaseError + return instance, fmt.Errorf("could not create service: %w", err) + } + + // Log Signer + signer := trillianUtils.CreateTrillDeployment(instance.Namespace, instance.Spec.LogSignerImage, logsignerDeploymentName, dbSecret.Name) + controllerutil.SetControllerReference(instance, signer, i.Client.Scheme()) + signer.Spec.Template.Spec.Containers[0].Args = append(signer.Spec.Template.Spec.Containers[0].Args, "--force_master=true") + if err = i.Client.Create(ctx, signer); err != nil { + instance.Status.Phase = rhtasv1alpha1.PhaseError + return instance, fmt.Errorf("could not create job: %w", err) + } + + instance.Status.Phase = rhtasv1alpha1.PhaseInitialization + return instance, nil + +} + +func (i initializeAction) createDbSecret(namespace string) *corev1.Secret { + // Define a new Secret object + return &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + GenerateName: "rhtas", + Namespace: namespace, + }, + Type: "Opaque", + Data: map[string][]byte{ + // generate a random password for the mysql root user and the mysql password + // TODO - use a random password generator + "mysql-root-password": []byte("password"), + "mysql-password": []byte("password"), + "mysql-database": []byte("trillian"), + "mysql-user": []byte("mysql"), + }, + } +} diff --git a/controllers/trillian/trillian_controller.go b/controllers/trillian/trillian_controller.go new file mode 100644 index 000000000..fa5dc4448 --- /dev/null +++ b/controllers/trillian/trillian_controller.go @@ -0,0 +1,101 @@ +/* +Copyright 2023. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package trillian + +import ( + "context" + + v1 "k8s.io/api/apps/v1" + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/runtime" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/reconcile" + + rhtasv1alpha1 "github.com/securesign/operator/api/v1alpha1" +) + +// TrillianReconciler reconciles a Trillian object +type TrillianReconciler struct { + client.Client + Scheme *runtime.Scheme +} + +//+kubebuilder:rbac:groups=rhtas.redhat.com,resources=trillians,verbs=get;list;watch;create;update;patch;delete +//+kubebuilder:rbac:groups=rhtas.redhat.com,resources=trillians/status,verbs=get;update;patch +//+kubebuilder:rbac:groups=rhtas.redhat.com,resources=trillians/finalizers,verbs=update + +// Reconcile is part of the main kubernetes reconciliation loop which aims to +// move the current state of the cluster closer to the desired state. +// TODO(user): Modify the Reconcile function to compare the state specified by +// the Trillian object against the actual cluster state, and then +// perform operations to make the cluster state reflect the state specified by +// the user. +// +// For more details, check Reconcile and its Result here: +// - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.14.1/pkg/reconcile +func (r *TrillianReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { + + // Fetch the Trillian instance + var instance rhtasv1alpha1.Trillian + + if err := r.Client.Get(ctx, req.NamespacedName, &instance); err != nil { + if errors.IsNotFound(err) { + // Request object not found, could have been deleted after reconcile request. + // Owned objects are automatically garbage collected. For additional cleanup logic use finalizers. + // Return and don't requeue + return reconcile.Result{}, nil + } + // Error reading the object - requeue the request. + return reconcile.Result{}, err + } + target := instance.DeepCopy() + actions := []Action{ + NewInitializeAction(), + NewWaitAction(), + } + + for _, a := range actions { + a.InjectClient(r.Client) + + if a.CanHandle(target) { + newTarget, err := a.Handle(ctx, target) + if err != nil { + if newTarget != nil { + _ = r.Status().Update(ctx, newTarget) + } + return reconcile.Result{}, err + } + + if newTarget != nil { + if err := r.Status().Update(ctx, newTarget); err != nil { + return reconcile.Result{}, err + } + } + break + } + } + return reconcile.Result{}, nil +} + +// SetupWithManager sets up the controller with the Manager. +func (r *TrillianReconciler) SetupWithManager(mgr ctrl.Manager) error { + return ctrl.NewControllerManagedBy(mgr). + For(&rhtasv1alpha1.Trillian{}). + Owns(&v1.Deployment{}). + Complete(r) +} diff --git a/controllers/trillian-db.go b/controllers/trillian/utils/trillian-db.go similarity index 75% rename from controllers/trillian-db.go rename to controllers/trillian/utils/trillian-db.go index f6e4ec2c0..464d73cc1 100644 --- a/controllers/trillian-db.go +++ b/controllers/trillian/utils/trillian-db.go @@ -1,24 +1,14 @@ -package controllers +package utils import ( - "context" - - client "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/log" - - rhtasv1alpha1 "github.com/securesign/operator/api/v1alpha1" apps "k8s.io/api/apps/v1" core "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) -func (r *SecuresignReconciler) ensureTrillDb(ctx context.Context, m *rhtasv1alpha1.Securesign, namespace string, sA string, dpName string, image string, pvcName string, dbsecret string) (*apps.Deployment, - error) { - log := log.FromContext(ctx) - log.Info("ensuring deployment") +func CreateTrillDb(namespace string, image string, dpName string, pvcName string, dbsecret string) *apps.Deployment { replicas := int32(1) - // Define a new Namespace object - dep := &apps.Deployment{ + return &apps.Deployment{ ObjectMeta: metav1.ObjectMeta{ Name: dpName, Namespace: namespace, @@ -46,7 +36,7 @@ func (r *SecuresignReconciler) ensureTrillDb(ctx context.Context, m *rhtasv1alph }, }, Spec: core.PodSpec{ - ServiceAccountName: sA, + ServiceAccountName: "sigstore-sa", Volumes: []core.Volume{ { Name: "storage", @@ -131,17 +121,4 @@ func (r *SecuresignReconciler) ensureTrillDb(ctx context.Context, m *rhtasv1alph }, }, } - - // Check if this Deployment already exists else create it - err := r.Get(ctx, client.ObjectKey{Name: dep.Name, Namespace: namespace}, dep) - // If the Deployment doesn't exist, create it but if it does, do nothing - if err != nil { - log.Info("Creating a new Deployment") - err = r.Create(ctx, dep) - if err != nil { - log.Error(err, "Failed to create new Deployment") - return nil, err - } - } - return dep, nil } diff --git a/controllers/trillian-deployment.go b/controllers/trillian/utils/trillian-deployment.go similarity index 64% rename from controllers/trillian-deployment.go rename to controllers/trillian/utils/trillian-deployment.go index 011ca7dd0..f5106c131 100644 --- a/controllers/trillian-deployment.go +++ b/controllers/trillian/utils/trillian-deployment.go @@ -1,12 +1,6 @@ -package controllers +package utils import ( - "context" - - client "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/log" - - rhtasv1alpha1 "github.com/securesign/operator/api/v1alpha1" apps "k8s.io/api/apps/v1" core "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -16,13 +10,9 @@ const ( netcat = "registry.redhat.io/rhtas-tech-preview/trillian-netcat-rhel9@sha256:b9fa895af8967cceb7a05ed7c9f2b80df047682ed11c87249ca2edba86492f6e" ) -func (r *SecuresignReconciler) ensureTrillDeployment(ctx context.Context, m *rhtasv1alpha1.Securesign, namespace string, sA string, dpName string, image string, dbsecret string) (*apps.Deployment, - error) { - log := log.FromContext(ctx) - log.Info("ensuring deployment") +func CreateTrillDeployment(namespace string, image string, dpName string, dbsecret string) *apps.Deployment { replicas := int32(1) - // Define a new Namespace object - dep := &apps.Deployment{ + return &apps.Deployment{ ObjectMeta: metav1.ObjectMeta{ Name: dpName, Namespace: namespace, @@ -50,7 +40,7 @@ func (r *SecuresignReconciler) ensureTrillDeployment(ctx context.Context, m *rht }, }, Spec: core.PodSpec{ - ServiceAccountName: sA, + ServiceAccountName: "sigstore-sa", InitContainers: []core.Container{ { Name: "wait-for-trillian-db", @@ -116,30 +106,4 @@ func (r *SecuresignReconciler) ensureTrillDeployment(ctx context.Context, m *rht }, }, } - - // If the deployment name is trillian-logserver then add additional port 8090 - if dpName == "trillian-logserver" { - dep.Spec.Template.Spec.Containers[0].Ports = append(dep.Spec.Template.Spec.Containers[0].Ports, core.ContainerPort{ - Protocol: core.ProtocolTCP, - ContainerPort: 8090, - }) - } - - // Add --force_master=true to args for the trillian-logsigner deployment - if dpName == "trillian-logsigner" { - dep.Spec.Template.Spec.Containers[0].Args = append(dep.Spec.Template.Spec.Containers[0].Args, "--force_master=true") - } - - // Check if this Deployment already exists else create it - err := r.Get(ctx, client.ObjectKey{Name: dep.Name, Namespace: namespace}, dep) - // If the Deployment doesn't exist, create it but if it does, do nothing - if err != nil { - log.Info("Creating a new Deployment") - err = r.Create(ctx, dep) - if err != nil { - log.Error(err, "Failed to create new Deployment") - return nil, err - } - } - return dep, nil } diff --git a/controllers/trillian/wait.go b/controllers/trillian/wait.go new file mode 100644 index 000000000..98cb9d07d --- /dev/null +++ b/controllers/trillian/wait.go @@ -0,0 +1,44 @@ +package trillian + +import ( + "context" + + rhtasv1alpha1 "github.com/securesign/operator/api/v1alpha1" + "github.com/securesign/operator/controllers/common" + commonUtils "github.com/securesign/operator/controllers/common/utils" +) + +func NewWaitAction() Action { + return &waitAction{} +} + +type waitAction struct { + common.BaseAction +} + +func (i waitAction) Name() string { + return "wait" +} + +func (i waitAction) CanHandle(trillian *rhtasv1alpha1.Trillian) bool { + return trillian.Status.Phase == rhtasv1alpha1.PhaseInitialization +} + +func (i waitAction) Handle(ctx context.Context, instance *rhtasv1alpha1.Trillian) (*rhtasv1alpha1.Trillian, error) { + var ( + ok bool + err error + ) + for _, deployment := range []string{logserverDeploymentName, dbDeploymentName, logsignerDeploymentName} { + ok, err = commonUtils.DeploymentIsRunning(ctx, i.Client, instance.Namespace, deployment) + if err != nil { + instance.Status.Phase = rhtasv1alpha1.PhaseError + return instance, err + } + if !ok { + return instance, nil + } + } + instance.Status.Phase = rhtasv1alpha1.PhaseReady + return instance, nil +} diff --git a/controllers/tuf/action.go b/controllers/tuf/action.go new file mode 100644 index 000000000..01c6cb3c1 --- /dev/null +++ b/controllers/tuf/action.go @@ -0,0 +1,36 @@ +package tuf + +import ( + "context" + + "github.com/securesign/operator/api/v1alpha1" + "k8s.io/client-go/tools/record" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +type Action interface { + InjectClient(client client.Client) + InjectRecorder(recorder record.EventRecorder) + + // a user friendly name for the action + Name() string + + // returns true if the action can handle the integration + CanHandle(*v1alpha1.Tuf) bool + + // executes the handling function + Handle(context.Context, *v1alpha1.Tuf) (*v1alpha1.Tuf, error) +} + +type BaseAction struct { + Client client.Client + Recorder record.EventRecorder +} + +func (action *BaseAction) InjectClient(client client.Client) { + action.Client = client +} + +func (action *BaseAction) InjectRecorder(recorder record.EventRecorder) { + action.Recorder = recorder +} diff --git a/controllers/tuf/init.go b/controllers/tuf/init.go new file mode 100644 index 000000000..530e404b3 --- /dev/null +++ b/controllers/tuf/init.go @@ -0,0 +1,61 @@ +package tuf + +import ( + "context" + "fmt" + + rhtasv1alpha1 "github.com/securesign/operator/api/v1alpha1" + "github.com/securesign/operator/controllers/common" + "github.com/securesign/operator/controllers/common/utils" + tufutils "github.com/securesign/operator/controllers/tuf/utils" + "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" +) + +const tufDeploymentName = "tuf" + +func NewInitializeAction() Action { + return &initializeAction{} +} + +type initializeAction struct { + common.BaseAction +} + +func (i initializeAction) Name() string { + return "initialize" +} + +func (i initializeAction) CanHandle(tuf *rhtasv1alpha1.Tuf) bool { + return tuf.Status.Phase == rhtasv1alpha1.PhaseInitialization +} + +func (i initializeAction) Handle(ctx context.Context, instance *rhtasv1alpha1.Tuf) (*rhtasv1alpha1.Tuf, error) { + //log := ctrllog.FromContext(ctx) + + var err error + + // TODO: migrate code to the operator + copyJob := tufutils.InitTufCopyJob(instance.Namespace, "tuf-secret-copy-job") + if err = i.Client.Create(ctx, copyJob); err != nil { + instance.Status.Phase = rhtasv1alpha1.PhaseError + return instance, fmt.Errorf("could not create copy job: %w", err) + } + + db := tufutils.CreateTufDeployment(instance.Namespace, instance.Spec.Image, tufDeploymentName) + controllerutil.SetControllerReference(instance, db, i.Client.Scheme()) + if err = i.Client.Create(ctx, db); err != nil { + instance.Status.Phase = rhtasv1alpha1.PhaseError + return instance, fmt.Errorf("could not create TUF: %w", err) + } + + tuf := utils.CreateService(instance.Namespace, "tuf", "tuf", "tuf", 8080) + //patch the pregenerated service + tuf.Spec.Ports[0].Port = 80 + controllerutil.SetControllerReference(instance, tuf, i.Client.Scheme()) + if err = i.Client.Create(ctx, tuf); err != nil { + instance.Status.Phase = rhtasv1alpha1.PhaseError + return instance, fmt.Errorf("could not create service: %w", err) + } + instance.Status.Phase = rhtasv1alpha1.PhaseInitialization + return instance, nil +} diff --git a/controllers/tuf/pending.go b/controllers/tuf/pending.go new file mode 100644 index 000000000..f19d93f15 --- /dev/null +++ b/controllers/tuf/pending.go @@ -0,0 +1,44 @@ +package tuf + +import ( + "context" + + rhtasv1alpha1 "github.com/securesign/operator/api/v1alpha1" + "github.com/securesign/operator/controllers/common" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +func NewPendingAction() Action { + return &pendingAction{} +} + +type pendingAction struct { + common.BaseAction +} + +func (i pendingAction) Name() string { + return "pending" +} + +func (i pendingAction) CanHandle(tuf *rhtasv1alpha1.Tuf) bool { + return tuf.Status.Phase == rhtasv1alpha1.PhaseNone || tuf.Status.Phase == rhtasv1alpha1.PhasePending +} + +func (i pendingAction) Handle(ctx context.Context, instance *rhtasv1alpha1.Tuf) (*rhtasv1alpha1.Tuf, error) { + if instance.Status.Phase == rhtasv1alpha1.PhaseNone { + instance.Status.Phase = rhtasv1alpha1.PhasePending + } + + // TODO: get rekor instance from parent reference + rekorList := &rhtasv1alpha1.RekorList{} + err := i.Client.List(ctx, rekorList, client.InNamespace(instance.Namespace)) + if err != nil { + return instance, err + } + if len(rekorList.Items) == 0 || rekorList.Items[0].Status.Phase != rhtasv1alpha1.PhaseReady { + return instance, nil + } + + instance.Status.Phase = rhtasv1alpha1.PhaseInitialization + return instance, err +} diff --git a/controllers/tuf/tuf_controller.go b/controllers/tuf/tuf_controller.go new file mode 100644 index 000000000..f792e0c20 --- /dev/null +++ b/controllers/tuf/tuf_controller.go @@ -0,0 +1,109 @@ +/* +Copyright 2023. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package tuf + +import ( + "context" + + rhtasv1alpha1 "github.com/securesign/operator/api/v1alpha1" + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/types" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/handler" + "sigs.k8s.io/controller-runtime/pkg/reconcile" +) + +// TufReconciler reconciles a Tuf object +type TufReconciler struct { + client.Client + Scheme *runtime.Scheme +} + +//+kubebuilder:rbac:groups=rhtas.redhat.com,resources=tufs,verbs=get;list;watch;create;update;patch;delete +//+kubebuilder:rbac:groups=rhtas.redhat.com,resources=tufs/status,verbs=get;update;patch +//+kubebuilder:rbac:groups=rhtas.redhat.com,resources=tufs/finalizers,verbs=update + +// Reconcile is part of the main kubernetes reconciliation loop which aims to +// move the current state of the cluster closer to the desired state. +// TODO(user): Modify the Reconcile function to compare the state specified by +// the Tuf object against the actual cluster state, and then +// perform operations to make the cluster state reflect the state specified by +// the user. +// +// For more details, check Reconcile and its Result here: +// - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.14.1/pkg/reconcile +func (r *TufReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { + + var instance rhtasv1alpha1.Tuf + + if err := r.Client.Get(ctx, req.NamespacedName, &instance); err != nil { + if errors.IsNotFound(err) { + // Request object not found, could have been deleted after reconcile request. + // Owned objects are automatically garbage collected. For additional cleanup logic use finalizers. + // Return and don't requeue + + // TODO: HACK - redefine APIe + owner := rhtasv1alpha1.Securesign{} + r.Client.Get(ctx, req.NamespacedName, &owner) + if owner.Status.Tuf != "" { + r.Client.Get(ctx, types.NamespacedName{Name: owner.Status.Tuf, Namespace: req.Namespace}, &instance) + } + } else { + // Error reading the object - requeue the request. + return reconcile.Result{}, err + } + } + target := instance.DeepCopy() + actions := []Action{ + NewPendingAction(), + NewInitializeAction(), + NewWaitAction(), + } + + for _, a := range actions { + a.InjectClient(r.Client) + + if a.CanHandle(target) { + newTarget, err := a.Handle(ctx, target) + if err != nil { + if newTarget != nil { + _ = r.Status().Update(ctx, newTarget) + } + return reconcile.Result{}, err + } + + if newTarget != nil { + if err := r.Status().Update(ctx, newTarget); err != nil { + return reconcile.Result{}, err + } + } + break + } + } + return reconcile.Result{}, nil +} + +// SetupWithManager sets up the controller with the Manager. +func (r *TufReconciler) SetupWithManager(mgr ctrl.Manager) error { + return ctrl.NewControllerManagedBy(mgr). + For(&rhtasv1alpha1.Tuf{}). + // TODO: redefine API - we need to watch Rekor changes as well + Watches(&rhtasv1alpha1.Rekor{}, handler.EnqueueRequestForOwner(mgr.GetScheme(), mgr.GetRESTMapper(), &rhtasv1alpha1.Securesign{})). + Complete(r) +} diff --git a/controllers/tuf/utils/tuf_copy_job.go b/controllers/tuf/utils/tuf_copy_job.go new file mode 100644 index 000000000..03f32903e --- /dev/null +++ b/controllers/tuf/utils/tuf_copy_job.go @@ -0,0 +1,46 @@ +package utils + +import ( + batch "k8s.io/api/batch/v1" + core "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +func InitTufCopyJob(namespace string, jobName string) *batch.Job { + + imageName := "registry.redhat.io/openshift4/ose-cli:latest" + return &batch.Job{ + ObjectMeta: metav1.ObjectMeta{ + Name: jobName, + Namespace: namespace, + Labels: map[string]string{ + "app.kubernetes.io/component": jobName, + "app.kubernetes.io/instance": "trusted-artifact-signer", + "app.kubernetes.io/name": "tuf-secret-copy", + }, + }, + Spec: batch.JobSpec{ + Template: core.PodTemplateSpec{ + ObjectMeta: metav1.ObjectMeta{ + Labels: map[string]string{ + "app.kubernetes.io/component": jobName, + "app.kubernetes.io/instance": "trusted-artifact-signer", + "app.kubernetes.io/name": "tuf-secret-copy", + }, + }, + Spec: core.PodSpec{ + ServiceAccountName: "sigstore-sa", + RestartPolicy: core.RestartPolicyOnFailure, + Containers: []core.Container{ + { + Name: "copy-rekor-secret", + Image: imageName, + Command: []string{"/bin/sh"}, + Args: []string{ + "-c", + "curl rekor-server." + namespace + ".svc.cluster.local/api/v1/log/publicKey -o /tmp/key -v && kubectl create secret generic rekor-public-key --from-file=key=/tmp/key", + }, + }, + }}}}, + } +} diff --git a/controllers/tuf_deployment.go b/controllers/tuf/utils/tuf_deployment.go similarity index 72% rename from controllers/tuf_deployment.go rename to controllers/tuf/utils/tuf_deployment.go index 4cfe073a0..471162042 100644 --- a/controllers/tuf_deployment.go +++ b/controllers/tuf/utils/tuf_deployment.go @@ -1,24 +1,14 @@ -package controllers +package utils import ( - "context" - - client "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/log" - - rhtasv1alpha1 "github.com/securesign/operator/api/v1alpha1" apps "k8s.io/api/apps/v1" core "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) -func (r *SecuresignReconciler) ensureTufDeployment(ctx context.Context, m *rhtasv1alpha1.Securesign, namespace string, sA string, dpName string) (*apps.Deployment, - error) { - log := log.FromContext(ctx) - log.Info("ensuring deployment") +func CreateTufDeployment(namespace string, image string, dpName string) *apps.Deployment { replicas := int32(1) - // Define a new Namespace object - dep := &apps.Deployment{ + return &apps.Deployment{ ObjectMeta: metav1.ObjectMeta{ Name: dpName, Namespace: namespace, @@ -46,7 +36,7 @@ func (r *SecuresignReconciler) ensureTufDeployment(ctx context.Context, m *rhtas }, }, Spec: core.PodSpec{ - ServiceAccountName: sA, + ServiceAccountName: "sigstore-sa", Volumes: []core.Volume{ { Name: "tuf-secrets", @@ -100,7 +90,7 @@ func (r *SecuresignReconciler) ensureTufDeployment(ctx context.Context, m *rhtas Containers: []core.Container{ { Name: dpName, - Image: "registry.redhat.io/rhtas-tech-preview/tuf-server-rhel9@sha256:413e361de99f09e617084438b2fc3c9c477f4a8e2cd65bd5f48271e66d57a9d9", + Image: image, Ports: []core.ContainerPort{ { Protocol: core.ProtocolTCP, @@ -125,16 +115,4 @@ func (r *SecuresignReconciler) ensureTufDeployment(ctx context.Context, m *rhtas }, }, } - // Check if this Deployment already exists else create it - err := r.Get(ctx, client.ObjectKey{Name: dep.Name, Namespace: namespace}, dep) - // If the Deployment doesn't exist, create it but if it does, do nothing - if err != nil { - log.Info("Creating a new Deployment") - err = r.Create(ctx, dep) - if err != nil { - log.Error(err, "Failed to create new Deployment") - return nil, err - } - } - return dep, nil } diff --git a/controllers/tuf/wait.go b/controllers/tuf/wait.go new file mode 100644 index 000000000..1c51a9134 --- /dev/null +++ b/controllers/tuf/wait.go @@ -0,0 +1,44 @@ +package tuf + +import ( + "context" + + rhtasv1alpha1 "github.com/securesign/operator/api/v1alpha1" + "github.com/securesign/operator/controllers/common" + commonUtils "github.com/securesign/operator/controllers/common/utils" +) + +func NewWaitAction() Action { + return &waitAction{} +} + +type waitAction struct { + common.BaseAction +} + +func (i waitAction) Name() string { + return "wait" +} + +func (i waitAction) CanHandle(tuf *rhtasv1alpha1.Tuf) bool { + return tuf.Status.Phase == rhtasv1alpha1.PhaseInitialization +} + +func (i waitAction) Handle(ctx context.Context, instance *rhtasv1alpha1.Tuf) (*rhtasv1alpha1.Tuf, error) { + var ( + ok bool + err error + ) + for _, deployment := range []string{"tuf"} { + ok, err = commonUtils.DeploymentIsRunning(ctx, i.Client, instance.Namespace, deployment) + if err != nil { + instance.Status.Phase = rhtasv1alpha1.PhaseError + return instance, err + } + if !ok { + return instance, nil + } + } + instance.Status.Phase = rhtasv1alpha1.PhaseReady + return instance, nil +} diff --git a/controllers/tuf_copy_job.go b/controllers/tuf_copy_job.go deleted file mode 100644 index dddb89eb1..000000000 --- a/controllers/tuf_copy_job.go +++ /dev/null @@ -1,118 +0,0 @@ -package controllers - -import ( - "context" - - client "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/log" - - rhtasv1alpha1 "github.com/securesign/operator/api/v1alpha1" - batch "k8s.io/api/batch/v1" - core "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -func (r *SecuresignReconciler) ensureTufCopyJob(ctx context.Context, m *rhtasv1alpha1.Securesign, namespace string, sA string, jobName string, rkn string, fun string, ctn string) (*batch.Job, - error) { - log := log.FromContext(ctx) - imageName := "registry.redhat.io/openshift4/ose-cli:latest" - log.Info("ensuring job") - // Define a new Namespace object - job := &batch.Job{ - ObjectMeta: metav1.ObjectMeta{ - Name: jobName, - Namespace: namespace, - Labels: map[string]string{ - "app.kubernetes.io/component": jobName, - "app.kubernetes.io/instance": "trusted-artifact-signer", - "app.kubernetes.io/name": "tuf-secret-copy", - }, - }, - Spec: batch.JobSpec{ - Template: core.PodTemplateSpec{ - ObjectMeta: metav1.ObjectMeta{ - Labels: map[string]string{ - "app.kubernetes.io/component": jobName, - "app.kubernetes.io/instance": "trusted-artifact-signer", - "app.kubernetes.io/name": "tuf-secret-copy", - }, - }, - Spec: core.PodSpec{ - ServiceAccountName: sA, - RestartPolicy: core.RestartPolicyOnFailure, - InitContainers: []core.Container{ - { - Name: "wait-for-rekor-deployment-readiness", - Image: imageName, - Command: []string{"/bin/sh"}, - Args: []string{ - "-c", - "kubectl rollout status deployment rekor-server --timeout=120s -n " + rkn, - }, - }, - { - Name: "wait-for-fulcio-deployment-readiness", - Image: imageName, - Command: []string{"/bin/sh"}, - Args: []string{ - "-c", - "kubectl rollout status deployment fulcio-server --timeout=120s -n " + fun, - }, - }, - { - Name: "wait-for-ctlog-deployment-readiness", - Image: imageName, - Command: []string{"/bin/sh"}, - Args: []string{ - "-c", - "kubectl rollout status deployment ctlog --timeout=120s -n " + ctn, - }, - }, - }, - Containers: []core.Container{ - { - Name: "copy-rekor-secret", - Image: imageName, - Command: []string{"/bin/sh"}, - Args: []string{ - "-c", - "curl rekor-server.rekor-system.svc.cluster.local/api/v1/log/publicKey -o /tmp/key -v && kubectl create secret generic rekor-public-key --from-file=key=/tmp/key", - }, - }, - { - Name: "copy-fulcio-secret", - Image: imageName, - Command: []string{"/bin/sh"}, - Args: []string{ - "-c", - "kubectl -n fulcio-system get secrets fulcio-secret-rh -oyaml | sed 's/namespace: .*/namespace: tuf-system/' | kubectl apply -f -", - }, - }, - { - Name: "copy-ctlog-secret", - Image: imageName, - Command: []string{"/bin/sh"}, - Args: []string{ - "-c", - "kubectl -n ctlog-system get secrets ctlog-public-key -oyaml | sed 's/namespace: .*/namespace: tuf-system/' | kubectl apply -f -", - }, - }, - }, - }, - }, - }, - } - - // Check if this Job already exists else create it - err := r.Get(ctx, client.ObjectKey{Name: job.Name, Namespace: namespace}, job) - // If the Job doesn't exist, create it but if it does, do nothing - if err != nil { - log.Info("Creating a new Job") - err = r.Create(ctx, job) - if err != nil { - log.Error(err, "Failed to create new Job") - return nil, err - } - } - return job, nil -} diff --git a/go.mod b/go.mod index 6deb54642..3049f4b60 100644 --- a/go.mod +++ b/go.mod @@ -3,68 +3,67 @@ module github.com/securesign/operator go 1.19 require ( - github.com/onsi/ginkgo/v2 v2.6.0 - github.com/onsi/gomega v1.24.1 - k8s.io/apimachinery v0.26.0 - k8s.io/client-go v0.26.0 - sigs.k8s.io/controller-runtime v0.14.1 + github.com/openshift/api v0.0.0-20231118005202-0f638a8a4705 + k8s.io/api v0.27.2 + k8s.io/apimachinery v0.27.2 + k8s.io/client-go v0.27.2 + sigs.k8s.io/controller-runtime v0.15.2 ) require ( github.com/beorn7/perks v1.0.1 // indirect - github.com/cespare/xxhash/v2 v2.1.2 // indirect + github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/emicklei/go-restful/v3 v3.9.0 // indirect github.com/evanphx/json-patch/v5 v5.6.0 // indirect github.com/fsnotify/fsnotify v1.6.0 // indirect - github.com/go-logr/logr v1.2.3 // indirect - github.com/go-logr/zapr v1.2.3 // indirect - github.com/go-openapi/jsonpointer v0.19.5 // indirect - github.com/go-openapi/jsonreference v0.20.0 // indirect - github.com/go-openapi/swag v0.19.14 // indirect + github.com/go-logr/logr v1.2.4 // indirect + github.com/go-logr/zapr v1.2.4 // indirect + github.com/go-openapi/jsonpointer v0.19.6 // indirect + github.com/go-openapi/jsonreference v0.20.1 // indirect + github.com/go-openapi/swag v0.22.3 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect - github.com/golang/protobuf v1.5.2 // indirect + github.com/golang/protobuf v1.5.3 // indirect github.com/google/gnostic v0.5.7-v3refs // indirect github.com/google/go-cmp v0.5.9 // indirect github.com/google/gofuzz v1.1.0 // indirect - github.com/google/uuid v1.1.2 // indirect + github.com/google/uuid v1.3.0 // indirect github.com/imdario/mergo v0.3.6 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect - github.com/mailru/easyjson v0.7.6 // indirect - github.com/matttproud/golang_protobuf_extensions v1.0.2 // indirect + github.com/mailru/easyjson v0.7.7 // indirect + github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/pkg/errors v0.9.1 // indirect - github.com/prometheus/client_golang v1.14.0 // indirect - github.com/prometheus/client_model v0.3.0 // indirect - github.com/prometheus/common v0.37.0 // indirect - github.com/prometheus/procfs v0.8.0 // indirect + github.com/prometheus/client_golang v1.15.1 // indirect + github.com/prometheus/client_model v0.4.0 // indirect + github.com/prometheus/common v0.42.0 // indirect + github.com/prometheus/procfs v0.9.0 // indirect github.com/spf13/pflag v1.0.5 // indirect go.uber.org/atomic v1.7.0 // indirect go.uber.org/multierr v1.6.0 // indirect go.uber.org/zap v1.24.0 // indirect - golang.org/x/net v0.3.1-0.20221206200815-1e63c2f08a10 // indirect - golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b // indirect - golang.org/x/sys v0.3.0 // indirect - golang.org/x/term v0.3.0 // indirect - golang.org/x/text v0.5.0 // indirect + golang.org/x/net v0.10.0 // indirect + golang.org/x/oauth2 v0.5.0 // indirect + golang.org/x/sys v0.8.0 // indirect + golang.org/x/term v0.8.0 // indirect + golang.org/x/text v0.9.0 // indirect golang.org/x/time v0.3.0 // indirect - gomodules.xyz/jsonpatch/v2 v2.2.0 // indirect + gomodules.xyz/jsonpatch/v2 v2.3.0 // indirect google.golang.org/appengine v1.6.7 // indirect - google.golang.org/protobuf v1.28.1 // indirect + google.golang.org/protobuf v1.30.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - k8s.io/api v0.26.0 // indirect - k8s.io/apiextensions-apiserver v0.26.0 // indirect - k8s.io/component-base v0.26.0 // indirect - k8s.io/klog/v2 v2.80.1 // indirect - k8s.io/kube-openapi v0.0.0-20221012153701-172d655c2280 // indirect - k8s.io/utils v0.0.0-20221128185143-99ec85e7a448 // indirect - sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2 // indirect + k8s.io/apiextensions-apiserver v0.27.2 // indirect + k8s.io/component-base v0.27.2 // indirect + k8s.io/klog/v2 v2.90.1 // indirect + k8s.io/kube-openapi v0.0.0-20230501164219-8b0f38b5fd1f // indirect + k8s.io/utils v0.0.0-20230209194617-a36077c30491 // indirect + sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect sigs.k8s.io/yaml v1.3.0 // indirect ) diff --git a/go.sum b/go.sum index 5e84df87f..b30c49c93 100644 --- a/go.sum +++ b/go.sum @@ -1,58 +1,13 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= -cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= -cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= -cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= -cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= -cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= -cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= -cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= -cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= -cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= -cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= -cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= -cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= -cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= -cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= -cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= -cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= -cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= -cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= -cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= -cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= -cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= -cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= -cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= -cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= -cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= -cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= -cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= -cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= -cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= -dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= -github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= -github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= -github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= -github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= -github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= -github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= -github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE= -github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= -github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= -github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= +github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= @@ -60,555 +15,259 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= github.com/emicklei/go-restful/v3 v3.9.0 h1:XwGDlfxEnQZzuopoqxwSEllNcCOM9DhhFyhFIIGKwxE= github.com/emicklei/go-restful/v3 v3.9.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= -github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= -github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/evanphx/json-patch v0.5.2/go.mod h1:ZWS5hhDbVDyob71nXKNL0+PWn6ToqBHMikGIFbs31qQ= github.com/evanphx/json-patch v4.12.0+incompatible h1:4onqiflcdA9EOZ4RxV643DvftH5pOlLGNtQ5lPWQu84= github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww= github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= -github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= -github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= -github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= -github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= -github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= -github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= -github.com/go-kit/log v0.2.0/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= -github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= -github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= -github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= -github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0= -github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/zapr v1.2.3 h1:a9vnzlIBPQBBkeaR9IuMUfmVOrQlkoC4YfPoFkX3T7A= -github.com/go-logr/zapr v1.2.3/go.mod h1:eIauM6P8qSvTw5o2ez6UEAfGjQKrxQTl5EoK+Qa2oG4= -github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= -github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY= -github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= -github.com/go-openapi/jsonreference v0.20.0 h1:MYlu0sBgChmCfJxxUKZ8g1cPWFOB37YSZqewK7OKeyA= -github.com/go-openapi/jsonreference v0.20.0/go.mod h1:Ag74Ico3lPc+zR+qjn4XBUmXymS4zJbYVCZmcgkasdo= -github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= -github.com/go-openapi/swag v0.19.14 h1:gm3vOOXfiuw5i9p5N9xJvfjvuofpyvLA9Wr6QfK5Fng= -github.com/go-openapi/swag v0.19.14/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= -github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= +github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/zapr v1.2.4 h1:QHVo+6stLbfJmYGkQ7uGHUCu5hnAFAj6mDe6Ea0SeOo= +github.com/go-logr/zapr v1.2.4/go.mod h1:FyHWQIzQORZ0QVE1BtVHv3cKtNLuXsbNLtpuhNapBOA= +github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE= +github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs= +github.com/go-openapi/jsonreference v0.20.1 h1:FBLnyygC4/IZZr893oiomc9XaghoveYTrLC1F86HID8= +github.com/go-openapi/jsonreference v0.20.1/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k= +github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/g= +github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= +github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= -github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= -github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= -github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= -github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= +github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/google/gnostic v0.5.7-v3refs h1:FhTMOKj2VhjpouxvWJAV1TL304uMlb9zcDqkl6cEI54= github.com/google/gnostic v0.5.7-v3refs/go.mod h1:73MKFl6jIHelAJNaBGFzt3SPtZULs9dYrGFt8OiIsHQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.1.0 h1:Hsa8mG0dQ46ij8Sl2AYJDUv1oA9/d6Vk+3LG99Oe02g= github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= -github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= -github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= -github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y= -github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= -github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= -github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 h1:K6RDEckDVWvDI9JAJYCmNdQXq6neHJOYx3V6jnqNEec= +github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/imdario/mergo v0.3.6 h1:xTNEAn+kxVO7dTZGu0CegyqKZmoWFI0rF8UxjlB2d28= github.com/imdario/mergo v0.3.6/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= -github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= -github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= -github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= -github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= -github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= -github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= -github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= -github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= -github.com/mailru/easyjson v0.7.6 h1:8yTIVnZgCoiM1TgqoeTl+LfU5Jg6/xL3QhGQnimLYnA= -github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= -github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= -github.com/matttproud/golang_protobuf_extensions v1.0.2 h1:hAHbPm5IJGijwng3PWk09JkG9WeqChjprR5s9bBZ+OM= -github.com/matttproud/golang_protobuf_extensions v1.0.2/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= +github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= +github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= +github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= -github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= -github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= -github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= -github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= -github.com/onsi/ginkgo/v2 v2.6.0 h1:9t9b9vRUbFq3C4qKFCGkVuq/fIHji802N1nrtkh1mNc= -github.com/onsi/ginkgo/v2 v2.6.0/go.mod h1:63DOGlLAH8+REH8jUGdL3YpCpu7JODesutUjdENfUAc= -github.com/onsi/gomega v1.24.1 h1:KORJXNNTzJXzu4ScJWssJfJMnJ+2QJqhoQSRwNlze9E= -github.com/onsi/gomega v1.24.1/go.mod h1:3AOiACssS3/MajrniINInwbfOOtfZvplPzuRSmvt1jM= -github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/onsi/ginkgo/v2 v2.9.5 h1:+6Hr4uxzP4XIUyAkg61dWBw8lb/gc4/X5luuxN/EC+Q= +github.com/onsi/gomega v1.27.7 h1:fVih9JD6ogIiHUN6ePK7HJidyEDpWGVB5mzM7cWNXoU= +github.com/openshift/api v0.0.0-20231118005202-0f638a8a4705 h1:GwpCt0VhL9GjVGJhdF+96RoUkGTf/d+7ICL/3jKWRkA= +github.com/openshift/api v0.0.0-20231118005202-0f638a8a4705/go.mod h1:ctXNyWanKEjGj8sss1KjjHQ3ENKFm33FFnS5BKaIPh4= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= -github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= -github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= -github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= -github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= -github.com/prometheus/client_golang v1.14.0 h1:nJdhIvne2eSX/XRAFV9PcvFFRbrjbcTUj0VP62TMhnw= -github.com/prometheus/client_golang v1.14.0/go.mod h1:8vpkKitgIVNcqrRBWh1C4TIUQgYNtG/XQE4E/Zae36Y= -github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= -github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_golang v1.15.1 h1:8tXpTmJbyH5lydzFPoxSIJ0J46jdh3tylbvM1xCv0LI= +github.com/prometheus/client_golang v1.15.1/go.mod h1:e9yaBhRPU2pPNsZwE+JdQl0KEt1N9XgF6zxWmaC0xOk= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4= -github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w= -github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= -github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= -github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= -github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= -github.com/prometheus/common v0.37.0 h1:ccBbHCgIiT9uSoFY0vX8H3zsNR5eLt17/RQLUvn8pXE= -github.com/prometheus/common v0.37.0/go.mod h1:phzohg0JFMnBEFGxTDbfu3QyL5GI8gTQJFhYO5B3mfA= -github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= -github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= -github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= -github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= -github.com/prometheus/procfs v0.8.0 h1:ODq8ZFEaYeCaZOJlZZdJA2AbQR98dSHSM1KW/You5mo= -github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4= -github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= -github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= -github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= +github.com/prometheus/client_model v0.4.0 h1:5lQXD3cAg1OXBf4Wq03gTrXHeaV0TQvGfUooCfx1yqY= +github.com/prometheus/client_model v0.4.0/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU= +github.com/prometheus/common v0.42.0 h1:EKsfXEYo4JpWMHH5cg+KOUWeuJSov1Id8zGR8eeI1YM= +github.com/prometheus/common v0.42.0/go.mod h1:xBwqVerjNdUDjgODMpudtOMwlOwf2SaTr1yjz4b7Zbc= +github.com/prometheus/procfs v0.9.0 h1:wzCHvIvM5SxWqYvwgVL7yJY8Lz3PKn49KQtpgMYJfhI= +github.com/prometheus/procfs v0.9.0/go.mod h1:+pB4zwohETzFnmlpe6yd2lSc+0/46IYZRB/chUwxUZY= +github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= -github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= -github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= -go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= -go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= -go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= -go.uber.org/goleak v1.2.0 h1:xqgm/S+aQvhWFTtR0XK3Jvg7z8kGV8P4X14IzwN3Eqk= +go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= +go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A= go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= -go.uber.org/zap v1.19.0/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI= go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60= go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg= -golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= -golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= -golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= -golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= -golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= -golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= -golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= -golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= -golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= -golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= -golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= -golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= -golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= -golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= -golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.3.1-0.20221206200815-1e63c2f08a10 h1:Frnccbp+ok2GkUS2tC84yAq/U9Vg+0sIO7aRL3T4Xnc= -golang.org/x/net v0.3.1-0.20221206200815-1e63c2f08a10/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M= +golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b h1:clP8eMhB30EHdc0bd2Twtq6kgU7yl5ub2cQLSdrv1Dg= -golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= +golang.org/x/oauth2 v0.5.0 h1:HuArIo48skDwlrvM3sEdHXElYslAMsf3KwRkkW4MC4s= +golang.org/x/oauth2 v0.5.0/go.mod h1:9/XBHVqLaWO3/BRHs5jbpYCnOZVjj5V0ndyaAM7KB4I= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.3.0 h1:w8ZOecv6NaNa/zC8944JTU3vz4u6Lagfk4RPQxv92NQ= -golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= +golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.3.0 h1:qoo4akIqOcDME5bhc/NgxUdovd6BSS2uMsVjB56q1xI= -golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA= -golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/term v0.8.0 h1:n5xxQn2i3PC0yLAbjTpNT85q/Kgzcr2gIoX9OrJUols= +golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.5.0 h1:OLmvp0KP+FVG99Ct/qFiL/Fhk4zp4QQnZ7b2U+5piUM= -golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= -golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= -golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= -golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.9.1 h1:8WMNJAz3zrtPmnYC7ISf5dEn3MT0gY7jBJfw27yrrLo= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -gomodules.xyz/jsonpatch/v2 v2.2.0 h1:4pT439QV83L+G9FkcCriY6EkpcK6r6bK+A5FBUMI7qY= -gomodules.xyz/jsonpatch/v2 v2.2.0/go.mod h1:WXp+iVDkoLQqPudfQ9GBlwB2eZ5DKOnjQZCYdOS8GPY= -google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= -google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= -google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= -google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= -google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= -google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= -google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= -google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= +gomodules.xyz/jsonpatch/v2 v2.3.0 h1:8NFhfS6gzxNqjLIYnZxg319wZ5Qjnx4m/CcX+Klzazc= +gomodules.xyz/jsonpatch/v2 v2.3.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= -google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= -google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= -google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= -google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= -google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201019141844-1ed22bb0c154/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= -google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= -google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= -google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= -google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= -google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= -google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= -google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= -google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= +google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= -gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= -gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= -honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -k8s.io/api v0.26.0 h1:IpPlZnxBpV1xl7TGk/X6lFtpgjgntCg8PJ+qrPHAC7I= -k8s.io/api v0.26.0/go.mod h1:k6HDTaIFC8yn1i6pSClSqIwLABIcLV9l5Q4EcngKnQg= -k8s.io/apiextensions-apiserver v0.26.0 h1:Gy93Xo1eg2ZIkNX/8vy5xviVSxwQulsnUdQ00nEdpDo= -k8s.io/apiextensions-apiserver v0.26.0/go.mod h1:7ez0LTiyW5nq3vADtK6C3kMESxadD51Bh6uz3JOlqWQ= -k8s.io/apimachinery v0.26.0 h1:1feANjElT7MvPqp0JT6F3Ss6TWDwmcjLypwoPpEf7zg= -k8s.io/apimachinery v0.26.0/go.mod h1:tnPmbONNJ7ByJNz9+n9kMjNP8ON+1qoAIIC70lztu74= -k8s.io/client-go v0.26.0 h1:lT1D3OfO+wIi9UFolCrifbjUUgu7CpLca0AD8ghRLI8= -k8s.io/client-go v0.26.0/go.mod h1:I2Sh57A79EQsDmn7F7ASpmru1cceh3ocVT9KlX2jEZg= -k8s.io/component-base v0.26.0 h1:0IkChOCohtDHttmKuz+EP3j3+qKmV55rM9gIFTXA7Vs= -k8s.io/component-base v0.26.0/go.mod h1:lqHwlfV1/haa14F/Z5Zizk5QmzaVf23nQzCwVOQpfC8= -k8s.io/klog/v2 v2.80.1 h1:atnLQ121W371wYYFawwYx1aEY2eUfs4l3J72wtgAwV4= -k8s.io/klog/v2 v2.80.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= -k8s.io/kube-openapi v0.0.0-20221012153701-172d655c2280 h1:+70TFaan3hfJzs+7VK2o+OGxg8HsuBr/5f6tVAjDu6E= -k8s.io/kube-openapi v0.0.0-20221012153701-172d655c2280/go.mod h1:+Axhij7bCpeqhklhUTe3xmOn6bWxolyZEeyaFpjGtl4= -k8s.io/utils v0.0.0-20221128185143-99ec85e7a448 h1:KTgPnR10d5zhztWptI952TNtt/4u5h3IzDXkdIMuo2Y= -k8s.io/utils v0.0.0-20221128185143-99ec85e7a448/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= -rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= -rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= -rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= -sigs.k8s.io/controller-runtime v0.14.1 h1:vThDes9pzg0Y+UbCPY3Wj34CGIYPgdmspPm2GIpxpzM= -sigs.k8s.io/controller-runtime v0.14.1/go.mod h1:GaRkrY8a7UZF0kqFFbUKG7n9ICiTY5T55P1RiE3UZlU= -sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2 h1:iXTIw73aPyC+oRdyqqvVJuloN1p0AC/kzH07hu3NE+k= -sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= +k8s.io/api v0.27.2 h1:+H17AJpUMvl+clT+BPnKf0E3ksMAzoBBg7CntpSuADo= +k8s.io/api v0.27.2/go.mod h1:ENmbocXfBT2ADujUXcBhHV55RIT31IIEvkntP6vZKS4= +k8s.io/apiextensions-apiserver v0.27.2 h1:iwhyoeS4xj9Y7v8YExhUwbVuBhMr3Q4bd/laClBV6Bo= +k8s.io/apiextensions-apiserver v0.27.2/go.mod h1:Oz9UdvGguL3ULgRdY9QMUzL2RZImotgxvGjdWRq6ZXQ= +k8s.io/apimachinery v0.27.2 h1:vBjGaKKieaIreI+oQwELalVG4d8f3YAMNpWLzDXkxeg= +k8s.io/apimachinery v0.27.2/go.mod h1:XNfZ6xklnMCOGGFNqXG7bUrQCoR04dh/E7FprV6pb+E= +k8s.io/client-go v0.27.2 h1:vDLSeuYvCHKeoQRhCXjxXO45nHVv2Ip4Fe0MfioMrhE= +k8s.io/client-go v0.27.2/go.mod h1:tY0gVmUsHrAmjzHX9zs7eCjxcBsf8IiNe7KQ52biTcQ= +k8s.io/component-base v0.27.2 h1:neju+7s/r5O4x4/txeUONNTS9r1HsPbyoPBAtHsDCpo= +k8s.io/component-base v0.27.2/go.mod h1:5UPk7EjfgrfgRIuDBFtsEFAe4DAvP3U+M8RTzoSJkpo= +k8s.io/klog/v2 v2.90.1 h1:m4bYOKall2MmOiRaR1J+We67Do7vm9KiQVlT96lnHUw= +k8s.io/klog/v2 v2.90.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= +k8s.io/kube-openapi v0.0.0-20230501164219-8b0f38b5fd1f h1:2kWPakN3i/k81b0gvD5C5FJ2kxm1WrQFanWchyKuqGg= +k8s.io/kube-openapi v0.0.0-20230501164219-8b0f38b5fd1f/go.mod h1:byini6yhqGC14c3ebc/QwanvYwhuMWF6yz2F8uwW8eg= +k8s.io/utils v0.0.0-20230209194617-a36077c30491 h1:r0BAOLElQnnFhE/ApUsg3iHdVYYPBjNSSOMowRZxxsY= +k8s.io/utils v0.0.0-20230209194617-a36077c30491/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +sigs.k8s.io/controller-runtime v0.15.2 h1:9V7b7SDQSJ08IIsJ6CY1CE85Okhp87dyTMNDG0FS7f4= +sigs.k8s.io/controller-runtime v0.15.2/go.mod h1:7ngYvp1MLT+9GeZ+6lH3LOlcHkp/+tzA/fmHa4iq9kk= +sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= +sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= sigs.k8s.io/structured-merge-diff/v4 v4.2.3 h1:PRbqxJClWWYMNV1dhaG4NsibJbArud9kFxnAMREiWFE= sigs.k8s.io/structured-merge-diff/v4 v4.2.3/go.mod h1:qjx8mGObPmV2aSZepjQjbmb2ihdVs8cGKBraizNC69E= sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo= diff --git a/main.go b/main.go index 6921212cd..d8eae74ca 100644 --- a/main.go +++ b/main.go @@ -20,6 +20,13 @@ import ( "flag" "os" + client2 "github.com/securesign/operator/client" + "github.com/securesign/operator/controllers/ctlog" + "github.com/securesign/operator/controllers/fulcio" + "github.com/securesign/operator/controllers/rekor" + "github.com/securesign/operator/controllers/trillian" + "github.com/securesign/operator/controllers/tuf" + // Import all Kubernetes client auth plugins (e.g. Azure, GCP, OIDC, etc.) // to ensure that exec-entrypoint and run can make use of them. _ "k8s.io/client-go/plugin/pkg/client/auth" @@ -89,11 +96,51 @@ func main() { os.Exit(1) } + client, err := client2.NewClientWithScheme(scheme) + if err != nil { + setupLog.Error(err, "unable to initialize k8s client") + os.Exit(1) + } if err = (&controllers.SecuresignReconciler{ + Client: client, + Scheme: client.Scheme(), + }).SetupWithManager(mgr); err != nil { + setupLog.Error(err, "unable to create controller", "controller", "Securesign") + os.Exit(1) + } + if err = (&fulcio.FulcioReconciler{ + Client: client, + Scheme: client.Scheme(), + }).SetupWithManager(mgr); err != nil { + setupLog.Error(err, "unable to create controller", "controller", "Fulcio") + os.Exit(1) + } + if err = (&trillian.TrillianReconciler{ + Client: client, + Scheme: mgr.GetScheme(), + }).SetupWithManager(mgr); err != nil { + setupLog.Error(err, "unable to create controller", "controller", "Trillian") + os.Exit(1) + } + if err = (&rekor.RekorReconciler{ Client: mgr.GetClient(), Scheme: mgr.GetScheme(), }).SetupWithManager(mgr); err != nil { - setupLog.Error(err, "unable to create controller", "controller", "Securesign") + setupLog.Error(err, "unable to create controller", "controller", "Rekor") + os.Exit(1) + } + if err = (&tuf.TufReconciler{ + Client: mgr.GetClient(), + Scheme: mgr.GetScheme(), + }).SetupWithManager(mgr); err != nil { + setupLog.Error(err, "unable to create controller", "controller", "Tuf") + os.Exit(1) + } + if err = (&ctlog.CTlogReconciler{ + Client: mgr.GetClient(), + Scheme: mgr.GetScheme(), + }).SetupWithManager(mgr); err != nil { + setupLog.Error(err, "unable to create controller", "controller", "CTlog") os.Exit(1) } //+kubebuilder:scaffold:builder