diff --git a/README.md b/README.md index 3c0601ac24f3012e311a425ea5eea80408ea3306..d0cced502746a3a42e09e32c4973b20fb224bd25 100644 --- a/README.md +++ b/README.md @@ -24,12 +24,27 @@ spec: alwaysOnline: true minify: css: true - dnsRecords: - - type: "A" - name: "domainname.io" - content: "1.1.1.1" - proxied: true - ttl: 3600 +--- +apiVersion: crds.kubeflare.io/v1alpha1 +kind: DNSRecord +metadata: + name: www.domainname.io +spec: + zone: domainname.io + record: + type: "A" + name: "www" + content: "1.1.1.1" + proxied: true + ttl: 3600 +--- +apiVersion: crds.kubeflare.io/v1alpha1 +kind: DNSRecord +metadata: + name: mx-records +spec: + zone: domainname.io + records: - type: "MX" name: "domainname.io" content: "aspmx.l.google.com" diff --git a/config/crds/v1/crds.kubeflare.io_dnsrecords.yaml b/config/crds/v1/crds.kubeflare.io_dnsrecords.yaml new file mode 100644 index 0000000000000000000000000000000000000000..810d81ac77d7925c1215a39682254f0ec49495d3 --- /dev/null +++ b/config/crds/v1/crds.kubeflare.io_dnsrecords.yaml @@ -0,0 +1,97 @@ + +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.2.8 + creationTimestamp: null + name: dnsrecords.crds.kubeflare.io +spec: + group: crds.kubeflare.io + names: + kind: DNSRecord + listKind: DNSRecordList + plural: dnsrecords + singular: dnsrecord + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: DNSRecord is the Schema for the dnsrecords 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: DNSRecordSpec defines the desired state of DNSRecord + properties: + record: + properties: + content: + type: string + name: + type: string + priority: + type: integer + proxied: + type: boolean + ttl: + type: integer + type: + type: string + required: + - content + - name + - type + type: object + records: + items: + properties: + content: + type: string + name: + type: string + priority: + type: integer + proxied: + type: boolean + ttl: + type: integer + type: + type: string + required: + - content + - name + - type + type: object + type: array + zone: + type: string + required: + - zone + type: object + status: + description: DNSRecordStatus defines the observed state of DNSRecord + type: object + type: object + served: true + storage: true + subresources: + status: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: [] + storedVersions: [] diff --git a/config/crds/v1/crds.kubeflare.io_zones.yaml b/config/crds/v1/crds.kubeflare.io_zones.yaml index 0333b8ab07f6e477891fced93f4c600e3d350b68..57debde07db00e5b0b06eff16a3076dd636be83c 100644 --- a/config/crds/v1/crds.kubeflare.io_zones.yaml +++ b/config/crds/v1/crds.kubeflare.io_zones.yaml @@ -38,27 +38,6 @@ spec: properties: apiToken: type: string - dnsRecords: - items: - properties: - content: - type: string - name: - type: string - priority: - type: integer - proxied: - type: boolean - ttl: - type: integer - type: - type: string - required: - - content - - name - - type - type: object - type: array settings: properties: advancedDDOS: diff --git a/config/crds/v1beta1/crds.kubeflare.io_dnsrecords.yaml b/config/crds/v1beta1/crds.kubeflare.io_dnsrecords.yaml new file mode 100644 index 0000000000000000000000000000000000000000..d9f8dd821a80e2bc53ba4deba8cbaa97cb2596c6 --- /dev/null +++ b/config/crds/v1beta1/crds.kubeflare.io_dnsrecords.yaml @@ -0,0 +1,98 @@ + +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.2.8 + creationTimestamp: null + name: dnsrecords.crds.kubeflare.io +spec: + group: crds.kubeflare.io + names: + kind: DNSRecord + listKind: DNSRecordList + plural: dnsrecords + singular: dnsrecord + scope: Namespaced + subresources: + status: {} + validation: + openAPIV3Schema: + description: DNSRecord is the Schema for the dnsrecords 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: DNSRecordSpec defines the desired state of DNSRecord + properties: + record: + properties: + content: + type: string + name: + type: string + priority: + type: integer + proxied: + type: boolean + ttl: + type: integer + type: + type: string + required: + - content + - name + - type + type: object + records: + items: + properties: + content: + type: string + name: + type: string + priority: + type: integer + proxied: + type: boolean + ttl: + type: integer + type: + type: string + required: + - content + - name + - type + type: object + type: array + zone: + type: string + required: + - zone + type: object + status: + description: DNSRecordStatus defines the observed state of DNSRecord + type: object + type: object + version: v1alpha1 + versions: + - name: v1alpha1 + served: true + storage: true +status: + acceptedNames: + kind: "" + plural: "" + conditions: [] + storedVersions: [] diff --git a/config/crds/v1beta1/crds.kubeflare.io_zones.yaml b/config/crds/v1beta1/crds.kubeflare.io_zones.yaml index d2488013e61ba581287eebb62fa9d9159e0058e6..22c00f4e1b388a6f80c4fe1cf6566abbfd545713 100644 --- a/config/crds/v1beta1/crds.kubeflare.io_zones.yaml +++ b/config/crds/v1beta1/crds.kubeflare.io_zones.yaml @@ -38,27 +38,6 @@ spec: properties: apiToken: type: string - dnsRecords: - items: - properties: - content: - type: string - name: - type: string - priority: - type: integer - proxied: - type: boolean - ttl: - type: integer - type: - type: string - required: - - content - - name - - type - type: object - type: array settings: properties: advancedDDOS: diff --git a/pkg/apis/crds/v1alpha1/dnsrecord_types.go b/pkg/apis/crds/v1alpha1/dnsrecord_types.go new file mode 100644 index 0000000000000000000000000000000000000000..3afba86f2485b90bd5d6d03728090d1fe4c664f5 --- /dev/null +++ b/pkg/apis/crds/v1alpha1/dnsrecord_types.go @@ -0,0 +1,68 @@ +/* +Copyright 2019 Replicated, Inc. + +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" +) + +type Record struct { + Type string `json:"type"` + Name string `json:"name"` + Content string `json:"content"` + TTL *int `json:"ttl,omitempty"` + Priority *int `json:"priority,omitempty"` + Proxied *bool `json:"proxied,omitempty"` +} + +// DNSRecordSpec defines the desired state of DNSRecord +type DNSRecordSpec struct { + Zone string `json:"zone"` + Record *Record `json:"record,omitempty"` + Records []*Record `json:"records,omitempty"` +} + +// DNSRecordStatus defines the observed state of DNSRecord +type DNSRecordStatus struct { +} + +// +genclient +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// DNSRecord is the Schema for the dnsrecords API +// +k8s:openapi-gen=true +// +kubebuilder:subresource:status +type DNSRecord struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec DNSRecordSpec `json:"spec,omitempty"` + Status DNSRecordStatus `json:"status,omitempty"` +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// DNSRecordList contains a list of DNSRecord +type DNSRecordList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []DNSRecord `json:"items"` +} + +func init() { + SchemeBuilder.Register(&DNSRecord{}, &DNSRecordList{}) +} diff --git a/pkg/apis/crds/v1alpha1/zone_types.go b/pkg/apis/crds/v1alpha1/zone_types.go index af9170b1a5f40a68f9e5361cb672926c744f22cb..fb878ec08e66a88e49d758fdc2c8bb73b9f7b4c5 100644 --- a/pkg/apis/crds/v1alpha1/zone_types.go +++ b/pkg/apis/crds/v1alpha1/zone_types.go @@ -20,15 +20,6 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) -type DNSRecord struct { - Type string `json:"type"` - Name string `json:"name"` - Content string `json:"content"` - TTL *int `json:"ttl,omitempty"` - Priority *int `json:"priority,omitempty"` - Proxied *bool `json:"proxied,omitempty"` -} - type MobileRedirect struct { Status *bool `json:"status,omi2tempty"` MobileSubdomain *string `json:"mobileSubdomain,omitempty"` @@ -72,9 +63,8 @@ type ZoneSettings struct { // ZoneSpec defines the desired state of Zone type ZoneSpec struct { - APIToken string `json:"apiToken"` - Settings *ZoneSettings `json:"settings,omitempty"` - DNSRecords []*DNSRecord `json:"dnsRecords,omitempty"` + APIToken string `json:"apiToken"` + Settings *ZoneSettings `json:"settings,omitempty"` } // ZoneStatus defines the observed state of Zone diff --git a/pkg/apis/crds/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/crds/v1alpha1/zz_generated.deepcopy.go index aa16c5470aa44a1a13b5c568b20c0db35de680ed..de3145b85348bb26dccce2a2b7e40ee4714394a7 100644 --- a/pkg/apis/crds/v1alpha1/zz_generated.deepcopy.go +++ b/pkg/apis/crds/v1alpha1/zz_generated.deepcopy.go @@ -122,21 +122,10 @@ func (in *APITokenStatus) DeepCopy() *APITokenStatus { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *DNSRecord) DeepCopyInto(out *DNSRecord) { *out = *in - if in.TTL != nil { - in, out := &in.TTL, &out.TTL - *out = new(int) - **out = **in - } - if in.Priority != nil { - in, out := &in.Priority, &out.Priority - *out = new(int) - **out = **in - } - if in.Proxied != nil { - in, out := &in.Proxied, &out.Proxied - *out = new(bool) - **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 DNSRecord. @@ -149,6 +138,92 @@ func (in *DNSRecord) DeepCopy() *DNSRecord { return out } +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *DNSRecord) 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 *DNSRecordList) DeepCopyInto(out *DNSRecordList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]DNSRecord, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DNSRecordList. +func (in *DNSRecordList) DeepCopy() *DNSRecordList { + if in == nil { + return nil + } + out := new(DNSRecordList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *DNSRecordList) 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 *DNSRecordSpec) DeepCopyInto(out *DNSRecordSpec) { + *out = *in + if in.Record != nil { + in, out := &in.Record, &out.Record + *out = new(Record) + (*in).DeepCopyInto(*out) + } + if in.Records != nil { + in, out := &in.Records, &out.Records + *out = make([]*Record, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = new(Record) + (*in).DeepCopyInto(*out) + } + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DNSRecordSpec. +func (in *DNSRecordSpec) DeepCopy() *DNSRecordSpec { + if in == nil { + return nil + } + out := new(DNSRecordSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *DNSRecordStatus) DeepCopyInto(out *DNSRecordStatus) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DNSRecordStatus. +func (in *DNSRecordStatus) DeepCopy() *DNSRecordStatus { + if in == nil { + return nil + } + out := new(DNSRecordStatus) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *MinifySetting) DeepCopyInto(out *MinifySetting) { *out = *in @@ -209,6 +284,36 @@ func (in *MobileRedirect) DeepCopy() *MobileRedirect { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Record) DeepCopyInto(out *Record) { + *out = *in + if in.TTL != nil { + in, out := &in.TTL, &out.TTL + *out = new(int) + **out = **in + } + if in.Priority != nil { + in, out := &in.Priority, &out.Priority + *out = new(int) + **out = **in + } + if in.Proxied != nil { + in, out := &in.Proxied, &out.Proxied + *out = new(bool) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Record. +func (in *Record) DeepCopy() *Record { + if in == nil { + return nil + } + out := new(Record) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ValueFrom) DeepCopyInto(out *ValueFrom) { *out = *in @@ -441,17 +546,6 @@ func (in *ZoneSpec) DeepCopyInto(out *ZoneSpec) { *out = new(ZoneSettings) (*in).DeepCopyInto(*out) } - if in.DNSRecords != nil { - in, out := &in.DNSRecords, &out.DNSRecords - *out = make([]*DNSRecord, len(*in)) - for i := range *in { - if (*in)[i] != nil { - in, out := &(*in)[i], &(*out)[i] - *out = new(DNSRecord) - (*in).DeepCopyInto(*out) - } - } - } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ZoneSpec. diff --git a/pkg/client/kubeflareclientset/typed/crds/v1alpha1/crds_client.go b/pkg/client/kubeflareclientset/typed/crds/v1alpha1/crds_client.go index 07c2a6eb201600be239a57dcfb9214e79d7aa00f..ddacc9020fb61252d5030b31413136a841c95346 100644 --- a/pkg/client/kubeflareclientset/typed/crds/v1alpha1/crds_client.go +++ b/pkg/client/kubeflareclientset/typed/crds/v1alpha1/crds_client.go @@ -27,6 +27,7 @@ import ( type CrdsV1alpha1Interface interface { RESTClient() rest.Interface APITokensGetter + DNSRecordsGetter ZonesGetter } @@ -39,6 +40,10 @@ func (c *CrdsV1alpha1Client) APITokens(namespace string) APITokenInterface { return newAPITokens(c, namespace) } +func (c *CrdsV1alpha1Client) DNSRecords(namespace string) DNSRecordInterface { + return newDNSRecords(c, namespace) +} + func (c *CrdsV1alpha1Client) Zones(namespace string) ZoneInterface { return newZones(c, namespace) } diff --git a/pkg/client/kubeflareclientset/typed/crds/v1alpha1/dnsrecord.go b/pkg/client/kubeflareclientset/typed/crds/v1alpha1/dnsrecord.go new file mode 100644 index 0000000000000000000000000000000000000000..0f642aead3dfa3e03d3507cb16b72bef4bb3235e --- /dev/null +++ b/pkg/client/kubeflareclientset/typed/crds/v1alpha1/dnsrecord.go @@ -0,0 +1,195 @@ +/* +Copyright 2020 Replicated, Inc. + +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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + "context" + "time" + + v1alpha1 "github.com/replicatedhq/kubeflare/pkg/apis/crds/v1alpha1" + scheme "github.com/replicatedhq/kubeflare/pkg/client/kubeflareclientset/scheme" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + rest "k8s.io/client-go/rest" +) + +// DNSRecordsGetter has a method to return a DNSRecordInterface. +// A group's client should implement this interface. +type DNSRecordsGetter interface { + DNSRecords(namespace string) DNSRecordInterface +} + +// DNSRecordInterface has methods to work with DNSRecord resources. +type DNSRecordInterface interface { + Create(ctx context.Context, dNSRecord *v1alpha1.DNSRecord, opts v1.CreateOptions) (*v1alpha1.DNSRecord, error) + Update(ctx context.Context, dNSRecord *v1alpha1.DNSRecord, opts v1.UpdateOptions) (*v1alpha1.DNSRecord, error) + UpdateStatus(ctx context.Context, dNSRecord *v1alpha1.DNSRecord, opts v1.UpdateOptions) (*v1alpha1.DNSRecord, error) + Delete(ctx context.Context, name string, opts v1.DeleteOptions) error + DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error + Get(ctx context.Context, name string, opts v1.GetOptions) (*v1alpha1.DNSRecord, error) + List(ctx context.Context, opts v1.ListOptions) (*v1alpha1.DNSRecordList, error) + Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) + Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.DNSRecord, err error) + DNSRecordExpansion +} + +// dNSRecords implements DNSRecordInterface +type dNSRecords struct { + client rest.Interface + ns string +} + +// newDNSRecords returns a DNSRecords +func newDNSRecords(c *CrdsV1alpha1Client, namespace string) *dNSRecords { + return &dNSRecords{ + client: c.RESTClient(), + ns: namespace, + } +} + +// Get takes name of the dNSRecord, and returns the corresponding dNSRecord object, and an error if there is any. +func (c *dNSRecords) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.DNSRecord, err error) { + result = &v1alpha1.DNSRecord{} + err = c.client.Get(). + Namespace(c.ns). + Resource("dnsrecords"). + Name(name). + VersionedParams(&options, scheme.ParameterCodec). + Do(ctx). + Into(result) + return +} + +// List takes label and field selectors, and returns the list of DNSRecords that match those selectors. +func (c *dNSRecords) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.DNSRecordList, err error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + result = &v1alpha1.DNSRecordList{} + err = c.client.Get(). + Namespace(c.ns). + Resource("dnsrecords"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Do(ctx). + Into(result) + return +} + +// Watch returns a watch.Interface that watches the requested dNSRecords. +func (c *dNSRecords) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + opts.Watch = true + return c.client.Get(). + Namespace(c.ns). + Resource("dnsrecords"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Watch(ctx) +} + +// Create takes the representation of a dNSRecord and creates it. Returns the server's representation of the dNSRecord, and an error, if there is any. +func (c *dNSRecords) Create(ctx context.Context, dNSRecord *v1alpha1.DNSRecord, opts v1.CreateOptions) (result *v1alpha1.DNSRecord, err error) { + result = &v1alpha1.DNSRecord{} + err = c.client.Post(). + Namespace(c.ns). + Resource("dnsrecords"). + VersionedParams(&opts, scheme.ParameterCodec). + Body(dNSRecord). + Do(ctx). + Into(result) + return +} + +// Update takes the representation of a dNSRecord and updates it. Returns the server's representation of the dNSRecord, and an error, if there is any. +func (c *dNSRecords) Update(ctx context.Context, dNSRecord *v1alpha1.DNSRecord, opts v1.UpdateOptions) (result *v1alpha1.DNSRecord, err error) { + result = &v1alpha1.DNSRecord{} + err = c.client.Put(). + Namespace(c.ns). + Resource("dnsrecords"). + Name(dNSRecord.Name). + VersionedParams(&opts, scheme.ParameterCodec). + Body(dNSRecord). + Do(ctx). + Into(result) + return +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +func (c *dNSRecords) UpdateStatus(ctx context.Context, dNSRecord *v1alpha1.DNSRecord, opts v1.UpdateOptions) (result *v1alpha1.DNSRecord, err error) { + result = &v1alpha1.DNSRecord{} + err = c.client.Put(). + Namespace(c.ns). + Resource("dnsrecords"). + Name(dNSRecord.Name). + SubResource("status"). + VersionedParams(&opts, scheme.ParameterCodec). + Body(dNSRecord). + Do(ctx). + Into(result) + return +} + +// Delete takes name of the dNSRecord and deletes it. Returns an error if one occurs. +func (c *dNSRecords) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + return c.client.Delete(). + Namespace(c.ns). + Resource("dnsrecords"). + Name(name). + Body(&opts). + Do(ctx). + Error() +} + +// DeleteCollection deletes a collection of objects. +func (c *dNSRecords) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + var timeout time.Duration + if listOpts.TimeoutSeconds != nil { + timeout = time.Duration(*listOpts.TimeoutSeconds) * time.Second + } + return c.client.Delete(). + Namespace(c.ns). + Resource("dnsrecords"). + VersionedParams(&listOpts, scheme.ParameterCodec). + Timeout(timeout). + Body(&opts). + Do(ctx). + Error() +} + +// Patch applies the patch and returns the patched dNSRecord. +func (c *dNSRecords) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.DNSRecord, err error) { + result = &v1alpha1.DNSRecord{} + err = c.client.Patch(pt). + Namespace(c.ns). + Resource("dnsrecords"). + Name(name). + SubResource(subresources...). + VersionedParams(&opts, scheme.ParameterCodec). + Body(data). + Do(ctx). + Into(result) + return +} diff --git a/pkg/client/kubeflareclientset/typed/crds/v1alpha1/fake/fake_crds_client.go b/pkg/client/kubeflareclientset/typed/crds/v1alpha1/fake/fake_crds_client.go index 5bb4b4a5079796f6146b4fe86ee79f01786797f0..5360f0839761ad68496867c0b2a3def7d319beae 100644 --- a/pkg/client/kubeflareclientset/typed/crds/v1alpha1/fake/fake_crds_client.go +++ b/pkg/client/kubeflareclientset/typed/crds/v1alpha1/fake/fake_crds_client.go @@ -32,6 +32,10 @@ func (c *FakeCrdsV1alpha1) APITokens(namespace string) v1alpha1.APITokenInterfac return &FakeAPITokens{c, namespace} } +func (c *FakeCrdsV1alpha1) DNSRecords(namespace string) v1alpha1.DNSRecordInterface { + return &FakeDNSRecords{c, namespace} +} + func (c *FakeCrdsV1alpha1) Zones(namespace string) v1alpha1.ZoneInterface { return &FakeZones{c, namespace} } diff --git a/pkg/client/kubeflareclientset/typed/crds/v1alpha1/fake/fake_dnsrecord.go b/pkg/client/kubeflareclientset/typed/crds/v1alpha1/fake/fake_dnsrecord.go new file mode 100644 index 0000000000000000000000000000000000000000..a743e92fca7defe4fb54d0ea4ca466868ca08941 --- /dev/null +++ b/pkg/client/kubeflareclientset/typed/crds/v1alpha1/fake/fake_dnsrecord.go @@ -0,0 +1,142 @@ +/* +Copyright 2020 Replicated, Inc. + +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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + + v1alpha1 "github.com/replicatedhq/kubeflare/pkg/apis/crds/v1alpha1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + testing "k8s.io/client-go/testing" +) + +// FakeDNSRecords implements DNSRecordInterface +type FakeDNSRecords struct { + Fake *FakeCrdsV1alpha1 + ns string +} + +var dnsrecordsResource = schema.GroupVersionResource{Group: "crds.kubeflare.io", Version: "v1alpha1", Resource: "dnsrecords"} + +var dnsrecordsKind = schema.GroupVersionKind{Group: "crds.kubeflare.io", Version: "v1alpha1", Kind: "DNSRecord"} + +// Get takes name of the dNSRecord, and returns the corresponding dNSRecord object, and an error if there is any. +func (c *FakeDNSRecords) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.DNSRecord, err error) { + obj, err := c.Fake. + Invokes(testing.NewGetAction(dnsrecordsResource, c.ns, name), &v1alpha1.DNSRecord{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.DNSRecord), err +} + +// List takes label and field selectors, and returns the list of DNSRecords that match those selectors. +func (c *FakeDNSRecords) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.DNSRecordList, err error) { + obj, err := c.Fake. + Invokes(testing.NewListAction(dnsrecordsResource, dnsrecordsKind, c.ns, opts), &v1alpha1.DNSRecordList{}) + + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v1alpha1.DNSRecordList{ListMeta: obj.(*v1alpha1.DNSRecordList).ListMeta} + for _, item := range obj.(*v1alpha1.DNSRecordList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested dNSRecords. +func (c *FakeDNSRecords) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewWatchAction(dnsrecordsResource, c.ns, opts)) + +} + +// Create takes the representation of a dNSRecord and creates it. Returns the server's representation of the dNSRecord, and an error, if there is any. +func (c *FakeDNSRecords) Create(ctx context.Context, dNSRecord *v1alpha1.DNSRecord, opts v1.CreateOptions) (result *v1alpha1.DNSRecord, err error) { + obj, err := c.Fake. + Invokes(testing.NewCreateAction(dnsrecordsResource, c.ns, dNSRecord), &v1alpha1.DNSRecord{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.DNSRecord), err +} + +// Update takes the representation of a dNSRecord and updates it. Returns the server's representation of the dNSRecord, and an error, if there is any. +func (c *FakeDNSRecords) Update(ctx context.Context, dNSRecord *v1alpha1.DNSRecord, opts v1.UpdateOptions) (result *v1alpha1.DNSRecord, err error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateAction(dnsrecordsResource, c.ns, dNSRecord), &v1alpha1.DNSRecord{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.DNSRecord), err +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +func (c *FakeDNSRecords) UpdateStatus(ctx context.Context, dNSRecord *v1alpha1.DNSRecord, opts v1.UpdateOptions) (*v1alpha1.DNSRecord, error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateSubresourceAction(dnsrecordsResource, "status", c.ns, dNSRecord), &v1alpha1.DNSRecord{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.DNSRecord), err +} + +// Delete takes name of the dNSRecord and deletes it. Returns an error if one occurs. +func (c *FakeDNSRecords) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewDeleteAction(dnsrecordsResource, c.ns, name), &v1alpha1.DNSRecord{}) + + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeDNSRecords) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewDeleteCollectionAction(dnsrecordsResource, c.ns, listOpts) + + _, err := c.Fake.Invokes(action, &v1alpha1.DNSRecordList{}) + return err +} + +// Patch applies the patch and returns the patched dNSRecord. +func (c *FakeDNSRecords) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.DNSRecord, err error) { + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(dnsrecordsResource, c.ns, name, pt, data, subresources...), &v1alpha1.DNSRecord{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.DNSRecord), err +} diff --git a/pkg/client/kubeflareclientset/typed/crds/v1alpha1/generated_expansion.go b/pkg/client/kubeflareclientset/typed/crds/v1alpha1/generated_expansion.go index 22a3a39f5bd0f66130a657e5c8f019435fe1d378..8e703fb86304ac24f845129fbdd4396ec7ad646d 100644 --- a/pkg/client/kubeflareclientset/typed/crds/v1alpha1/generated_expansion.go +++ b/pkg/client/kubeflareclientset/typed/crds/v1alpha1/generated_expansion.go @@ -20,4 +20,6 @@ package v1alpha1 type APITokenExpansion interface{} +type DNSRecordExpansion interface{} + type ZoneExpansion interface{} diff --git a/pkg/controller/zone/dns_records.go b/pkg/controller/dnsrecord/dns_records.go similarity index 79% rename from pkg/controller/zone/dns_records.go rename to pkg/controller/dnsrecord/dns_records.go index 6cb5eb191cd2444ce5c5244d371550c707b01cc7..a1352c90a08423d1d1c3bd706cc1234d70e44c6f 100644 --- a/pkg/controller/zone/dns_records.go +++ b/pkg/controller/dnsrecord/dns_records.go @@ -1,4 +1,4 @@ -package zone +package dnsrecord import ( "context" @@ -7,34 +7,36 @@ import ( "github.com/pkg/errors" crdsv1alpha1 "github.com/replicatedhq/kubeflare/pkg/apis/crds/v1alpha1" "github.com/replicatedhq/kubeflare/pkg/logger" - "go.uber.org/zap" ) -func (r *ReconcileZone) reconcileDNSRecords(ctx context.Context, instance crdsv1alpha1.Zone) error { - logger.Debug("reconcileDNSRecords for zone", zap.String("zoneName", instance.Name)) +func ReconcileDNSRecords(ctx context.Context, instance crdsv1alpha1.DNSRecord, zone *crdsv1alpha1.Zone, cf *cloudflare.API) error { + logger.Debug("reconcileDNSRecords for zone") - api, err := r.getCloudflareAPI(ctx, instance) - if err != nil { - return errors.Wrap(err, "failed to get cloudflare api") - } - - zoneID, err := api.ZoneIDByName(instance.Name) + zoneID, err := cf.ZoneIDByName(zone.Name) if err != nil { return errors.Wrap(err, "failed to get zone id") } - existingRecords, err := api.DNSRecords(zoneID, cloudflare.DNSRecord{}) + existingRecords, err := cf.DNSRecords(zoneID, cloudflare.DNSRecord{}) if err != nil { return errors.Wrap(err, "failed to list dns records") } + desiredRecords := []*crdsv1alpha1.Record{} + if instance.Spec.Record != nil { + desiredRecords = append(desiredRecords, instance.Spec.Record) + } + if instance.Spec.Records != nil { + desiredRecords = append(desiredRecords, instance.Spec.Records...) + } + recordsToCreate := []cloudflare.DNSRecord{} recordsToUpdate := []cloudflare.DNSRecord{} // recordsToDelete := []cloudflare.DNSRecord{} for _, existingRecord := range existingRecords { found := false - for _, desiredRecord := range instance.Spec.DNSRecords { + for _, desiredRecord := range desiredRecords { if desiredRecord.Name == existingRecord.Name && desiredRecord.Type == existingRecord.Type { found = true isChanged := false @@ -75,7 +77,7 @@ func (r *ReconcileZone) reconcileDNSRecords(ctx context.Context, instance crdsv1 } } - for _, desiredRecord := range instance.Spec.DNSRecords { + for _, desiredRecord := range desiredRecords { found := false for _, existingRecord := range existingRecords { if existingRecord.Type == desiredRecord.Type && existingRecord.Name == desiredRecord.Name { @@ -107,7 +109,7 @@ func (r *ReconcileZone) reconcileDNSRecords(ctx context.Context, instance crdsv1 } for _, recordToCreate := range recordsToCreate { - response, err := api.CreateDNSRecord(zoneID, recordToCreate) + response, err := cf.CreateDNSRecord(zoneID, recordToCreate) if err != nil { return errors.Wrap(err, "failed to create dns record") } @@ -126,7 +128,7 @@ func (r *ReconcileZone) reconcileDNSRecords(ctx context.Context, instance crdsv1 Proxied: recordToUpdate.Proxied, } - err := api.UpdateDNSRecord(zoneID, recordToUpdate.ID, rr) + err := cf.UpdateDNSRecord(zoneID, recordToUpdate.ID, rr) if err != nil { return errors.Wrap(err, "failed to update dns record") } diff --git a/pkg/controller/dnsrecord/dnsrecord_controller.go b/pkg/controller/dnsrecord/dnsrecord_controller.go new file mode 100644 index 0000000000000000000000000000000000000000..9e56ececa2156590256efa2c80b515b469240931 --- /dev/null +++ b/pkg/controller/dnsrecord/dnsrecord_controller.go @@ -0,0 +1,123 @@ +/* +Copyright 2019 Replicated, Inc. + +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 dnsrecord + +import ( + "context" + "time" + + "github.com/pkg/errors" + crdsv1alpha1 "github.com/replicatedhq/kubeflare/pkg/apis/crds/v1alpha1" + "github.com/replicatedhq/kubeflare/pkg/controller/shared" + "github.com/replicatedhq/kubeflare/pkg/logger" + "k8s.io/apimachinery/pkg/runtime" + kubeinformers "k8s.io/client-go/informers" + "k8s.io/client-go/kubernetes" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/controller" + "sigs.k8s.io/controller-runtime/pkg/handler" + "sigs.k8s.io/controller-runtime/pkg/manager" + "sigs.k8s.io/controller-runtime/pkg/reconcile" + "sigs.k8s.io/controller-runtime/pkg/source" +) + +// Add creates a new DNSRecord Controller and adds it to the Manager with default RBAC. The Manager will set fields on the Controller +// and Start it when the Manager is Started. +func Add(mgr manager.Manager) error { + return add(mgr, newReconciler(mgr)) +} + +// newReconciler returns a new reconcile.Reconciler +func newReconciler(mgr manager.Manager) reconcile.Reconciler { + return &ReconcileDNSRecord{ + Client: mgr.GetClient(), + scheme: mgr.GetScheme(), + } +} + +// add adds a new Controller to mgr with r as the reconcile.Reconciler +func add(mgr manager.Manager, r reconcile.Reconciler) error { + // Create a new controller + c, err := controller.New("dnsrecord-controller", mgr, controller.Options{Reconciler: r}) + if err != nil { + return err + } + + // Watch for changes to DNSRecord + err = c.Watch(&source.Kind{ + Type: &crdsv1alpha1.DNSRecord{}, + }, &handler.EnqueueRequestForObject{}) + if err != nil { + return errors.Wrap(err, "failed to start watch on dnsrecords") + } + + generatedClient := kubernetes.NewForConfigOrDie(mgr.GetConfig()) + generatedInformers := kubeinformers.NewSharedInformerFactory(generatedClient, time.Minute) + err = mgr.Add(manager.RunnableFunc(func(s <-chan struct{}) error { + generatedInformers.Start(s) + <-s + return nil + })) + if err != nil { + return err + } + + return nil +} + +var _ reconcile.Reconciler = &ReconcileDNSRecord{} + +// ReconcileDNSRecord reconciles a DNSRecord object +type ReconcileDNSRecord struct { + client.Client + scheme *runtime.Scheme +} + +// Reconcile reads that state of the cluster for a ReconcileDNSRecord object and makes changes based on the state read +// and what is in the Zone.Spec +// +kubebuilder:rbac:groups=crds.kubeflare.io,resources=dnsrecords,verbs=get;list;watch;create;update;patch;delete +// +kubebuilder:rbac:groups=crds.kubeflare.io,resources=dnsrecords/status,verbs=get;update;patch +func (r *ReconcileDNSRecord) Reconcile(request reconcile.Request) (reconcile.Result, error) { + // This reconcile loop will be called for all ReconcileDNSRecord objects + // because of the informer that we have set up + ctx := context.Background() + instance := crdsv1alpha1.DNSRecord{} + err := r.Get(ctx, request.NamespacedName, &instance) + if err != nil { + logger.Error(err) + return reconcile.Result{}, err + } + + zone, err := shared.GetZone(ctx, instance.Namespace, instance.Spec.Zone) + if err != nil { + logger.Error(err) + return reconcile.Result{}, err + } + + cf, err := shared.GetCloudflareAPI(ctx, instance.Namespace, zone.Spec.APIToken) + if err != nil { + logger.Error(err) + return reconcile.Result{}, err + } + + if err := ReconcileDNSRecords(ctx, instance, zone, cf); err != nil { + logger.Error(err) + return reconcile.Result{}, err + } + + return reconcile.Result{}, nil +} diff --git a/pkg/controller/zone/api.go b/pkg/controller/shared/cloudflare.go similarity index 78% rename from pkg/controller/zone/api.go rename to pkg/controller/shared/cloudflare.go index 6cc98ec917d2e4004f0cbe03222bea06df99e3d2..7ab7a3bf634d9d6f40c2d0972b63010710f92b08 100644 --- a/pkg/controller/zone/api.go +++ b/pkg/controller/shared/cloudflare.go @@ -1,11 +1,10 @@ -package zone +package shared import ( "context" "github.com/cloudflare/cloudflare-go" "github.com/pkg/errors" - crdsv1alpha1 "github.com/replicatedhq/kubeflare/pkg/apis/crds/v1alpha1" crdsclientv1alpha1 "github.com/replicatedhq/kubeflare/pkg/client/kubeflareclientset/typed/crds/v1alpha1" "github.com/replicatedhq/kubeflare/pkg/logger" "go.uber.org/zap" @@ -13,7 +12,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client/config" ) -func (r *ReconcileZone) getCloudflareAPI(ctx context.Context, instance crdsv1alpha1.Zone) (*cloudflare.API, error) { +func GetCloudflareAPI(ctx context.Context, namespace string, apiTokenName string) (*cloudflare.API, error) { cfg, err := config.GetConfig() if err != nil { return nil, errors.Wrap(err, "failed to get config") @@ -24,7 +23,7 @@ func (r *ReconcileZone) getCloudflareAPI(ctx context.Context, instance crdsv1alp return nil, errors.Wrap(err, "failed to create crds client") } - apiToken, err := crdsClient.APITokens(instance.Namespace).Get(ctx, instance.Spec.APIToken, metav1.GetOptions{}) + apiToken, err := crdsClient.APITokens(namespace).Get(ctx, apiTokenName, metav1.GetOptions{}) if err != nil { return nil, errors.Wrap(err, "failed to get api token") } diff --git a/pkg/controller/shared/zone.go b/pkg/controller/shared/zone.go new file mode 100644 index 0000000000000000000000000000000000000000..68b0f733a98201da3e8d7dc527c55bea13bb0417 --- /dev/null +++ b/pkg/controller/shared/zone.go @@ -0,0 +1,30 @@ +package shared + +import ( + "context" + + "github.com/pkg/errors" + crdsv1alpha1 "github.com/replicatedhq/kubeflare/pkg/apis/crds/v1alpha1" + crdsclientv1alpha1 "github.com/replicatedhq/kubeflare/pkg/client/kubeflareclientset/typed/crds/v1alpha1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "sigs.k8s.io/controller-runtime/pkg/client/config" +) + +func GetZone(ctx context.Context, namespace string, zoneName string) (*crdsv1alpha1.Zone, error) { + cfg, err := config.GetConfig() + if err != nil { + return nil, errors.Wrap(err, "failed to get config") + } + + crdsClient, err := crdsclientv1alpha1.NewForConfig(cfg) + if err != nil { + return nil, errors.Wrap(err, "failed to create crds client") + } + + zone, err := crdsClient.Zones(namespace).Get(ctx, zoneName, metav1.GetOptions{}) + if err != nil { + return nil, errors.Wrap(err, "failed to get zone") + } + + return zone, nil +} diff --git a/pkg/controller/zone/zone_controller.go b/pkg/controller/zone/zone_controller.go index 68b749dc3faf81549258ca5aa086a459341febad..54088afd1c6ec4c325f9eec103397f83d60c3c70 100644 --- a/pkg/controller/zone/zone_controller.go +++ b/pkg/controller/zone/zone_controller.go @@ -22,6 +22,7 @@ import ( "github.com/pkg/errors" crdsv1alpha1 "github.com/replicatedhq/kubeflare/pkg/apis/crds/v1alpha1" + "github.com/replicatedhq/kubeflare/pkg/controller/shared" "github.com/replicatedhq/kubeflare/pkg/logger" "k8s.io/apimachinery/pkg/runtime" kubeinformers "k8s.io/client-go/informers" @@ -101,7 +102,7 @@ func (r *ReconcileZone) Reconcile(request reconcile.Request) (reconcile.Result, return reconcile.Result{}, err } - cf, err := r.getCloudflareAPI(ctx, instance) + cf, err := shared.GetCloudflareAPI(ctx, instance.Namespace, instance.Spec.APIToken) if err != nil { logger.Error(err) return reconcile.Result{}, err @@ -112,10 +113,5 @@ func (r *ReconcileZone) Reconcile(request reconcile.Request) (reconcile.Result, return reconcile.Result{}, err } - if err := r.reconcileDNSRecords(ctx, instance); err != nil { - logger.Error(err) - return reconcile.Result{}, err - } - return reconcile.Result{}, nil }