From b22fa07ba3dc373501a300184a9d3c951c38ecf6 Mon Sep 17 00:00:00 2001 From: Frank Mai Date: Sun, 17 May 2020 10:13:33 +0800 Subject: [PATCH] refactor: add dummy protocol device --- README.md | 3 +- adaptors/dummy/README.md | 80 ++++++ .../api/v1alpha1/dummyprotocoldevice_types.go | 130 ++++++++++ .../api/v1alpha1/zz_generated.deepcopy.go | 227 +++++++++++++++++ adaptors/dummy/deploy/e2e/all_in_one.yaml | 176 +++++++++++++ .../dummy/deploy/e2e/dl_protocoldevice.yaml | 42 ++++ ...s.edge.cattle.io_dummyprotocoldevices.yaml | 150 +++++++++++ .../deploy/manifests/crd/kustomization.yaml | 1 + .../dummy/deploy/manifests/rbac/role.yaml | 20 ++ adaptors/dummy/pkg/adaptor/service.go | 40 +++ adaptors/dummy/pkg/dummy/dummy.go | 2 + .../dummy/pkg/physical/device_protocol.go | 234 ++++++++++++++++++ adaptors/dummy/pkg/physical/handler.go | 3 + .../dummy/pkg/physical/random_generator.go | 53 ++++ .../integration/adaptor/connection_test.go | 31 ++- 15 files changed, 1190 insertions(+), 2 deletions(-) create mode 100644 adaptors/dummy/api/v1alpha1/dummyprotocoldevice_types.go create mode 100644 adaptors/dummy/deploy/e2e/dl_protocoldevice.yaml create mode 100644 adaptors/dummy/deploy/manifests/crd/base/devices.edge.cattle.io_dummyprotocoldevices.yaml create mode 100644 adaptors/dummy/pkg/physical/device_protocol.go create mode 100644 adaptors/dummy/pkg/physical/random_generator.go diff --git a/README.md b/README.md index 5ac8f4aa..6393a9cf 100644 --- a/README.md +++ b/README.md @@ -213,6 +213,7 @@ The dummy adaptor installer YAML file is under the [`adaptors/dummy/deploy/e2e`] ```shell script $ kubectl apply -f https://raw.githubusercontent.com/cnrancher/octopus/master/adaptors/dummy/deploy/e2e/all_in_one.yaml customresourcedefinition.apiextensions.k8s.io/dummyspecialdevices.devices.edge.cattle.io created +customresourcedefinition.apiextensions.k8s.io/dummyprotocoldevices.devices.edge.cattle.io created clusterrole.rbac.authorization.k8s.io/octopus-adaptor-dummy-manager-role created clusterrolebinding.rbac.authorization.k8s.io/octopus-adaptor-dummy-manager-rolebinding created daemonset.apps/octopus-adaptor-dummy-adaptor created @@ -245,7 +246,7 @@ replicaset.apps/octopus-brain-65fdb4ff99 1 1 1 2m27s ``` -It is worth noting that we have granted the permission to Octopus for managing `DummySpecialDevice`: +It is worth noting that we have granted the permission to Octopus for managing `DummySpecialDevice`/`DummyProtocolDevice`: ```shell script $ kubectl get clusterrolebinding | grep octopus diff --git a/adaptors/dummy/README.md b/adaptors/dummy/README.md index 6d775147..f154eef8 100644 --- a/adaptors/dummy/README.md +++ b/adaptors/dummy/README.md @@ -11,6 +11,13 @@ This is for experience or testing. + [DummySpecialDeviceStatus](#dummyspecialdevicestatus) + [DummySpecialDeviceProtocol](#dummyspecialdeviceprotocol) + [DummySpecialDeviceGear](#dummyspecialdevicegear) + + [DummyProtocolDevice](#dummyprotocoldevice) + + [DummyProtocolDeviceSpec](#dummyprotocoldevicespec) + + [DummyProtocolDeviceStatus](#dummyprotocoldevicestatus) + + [DummyProtocolDeviceProtocol](#dummyprotocoldeviceprotocol) + + [DummyProtocolDeviceSpecProps](#dummyprotocoldevicespecprops) + + [DummyProtocolDevicesStatusProps](#dummyprotocoldevicestatusprops) + + [DummyProtocolDevicePropertyType](#dummyprotocoldevicepropertytype) - [Support Platform](#support-platform) - [Usage](#Usage) - [Authority](#authority) @@ -28,6 +35,7 @@ This is for experience or testing. | Kind | Group | Version | Available | |:---:|:---:|:---:|:---:| | [`DummySpecialDevice`](#dummyspecialdevice) | `devices.edge.cattle.io` | `v1alpha1` | * | +| [`DummyProtocolDevice`](#dummyprotocoldevice) | `devices.edge.cattle.io` | `v1alpha1` | * | ### DummySpecialDevice @@ -70,6 +78,76 @@ DummySpecialDeviceGear defines how fast the dummy special device should be. | middle | Starts from 100 and increases every two seconds until 200. | string | false | | fast | Starts from 200 and increases every one second until 300. | string | false | +### DummyProtocolDevice + +The `DummyProtocolDevice` can be considered as a chaos protocol robot, it will change its attribute values every two seconds. + +| Field | Description | Schema | Required | +|:---|:---|:---|:---:| +| metadata | | [metav1.ObjectMeta](https://github.com/kubernetes/apimachinery/blob/master/pkg/apis/meta/v1/types.go#L110) | false | +| spec | Defines the desired state of DummyProtocolDevice. | [DummyProtocolDeviceSpec](#dummyprotocoldevicespec) | true | +| status | Defines the observed state of DummyProtocolDevice. | [DummyProtocolDeviceStatus](#dummyprotocoldevicestatus) | false | + +#### DummyProtocolDeviceSpec + +| Field | Description | Schema | Required | +|:---|:---|:---|:---:| +| protocol | Protocol for accessing the dummy protocol device. | [DummyProtocolDeviceProtocol](#dummyprotocoldeviceprotocol) | true | +| props | Describes the desired properties. | map[string][DummyProtocolDeviceSpecProps](#dummyprotocoldevicespecprops) | false | + +#### DummyProtocolDeviceStatus + +| Field | Description | Schema | Required | +|:---|:---|:---|:---:| +| props | Reports the observed value of the desired properties. | map[string][DummyProtocolDeviceStatusProps](#dummyprotocoldevicestatusprops) | false | + +#### DummyProtocolDeviceProtocol + +| Field | Description | Schema | Required | +|:---|:---|:---|:---:| +| ip | Specifies where to connect the dummy protocol device. | string | true | + +#### DummyProtocolDeviceSpecProps + +> `DummyProtocolDeviceSpecObjectOrArrayProps` is the same as `DummyProtocolDeviceSpecProps`. +> The existence of `DummyProtocolDeviceSpecObjectOrArrayProps` is to combat the object circular reference. + +| Field | Description | Schema | Required | +|:---|:---|:---|:---:| +| type | Describes the type of property. | [DummyProtocolDevicePropertyType](#dummyprotocoldevicepropertytype) | true | +| description | Outlines the property. | string | false | +| readOnly | Configures the property is readOnly or not. | bool | false | +| arrayProps | Describes item properties of the array type. | *[DummyProtocolDeviceSpecObjectOrArrayProps](#dummyprotocoldevicespecprops) | false | +| objectProps | Describes properties of the object type. | map[string][DummyProtocolDeviceSpecObjectOrArrayProps](#dummyprotocoldevicespecprops) | false | + +#### DummyProtocolDeviceStatusProps + +> `DummyProtocolDeviceStatusObjectOrArrayProps` is the same as `DummyProtocolDeviceStatusProps`. +> The existence of `DummyProtocolDeviceStatusObjectOrArrayProps` is to combat the object circular reference. + +| Field | Description | Schema | Required | +|:---|:---|:---|:---:| +| type | Reports the type of property. | [DummyProtocolDevicePropertyType](#dummyprotocoldevicepropertytype) | true | +| intValue | Reports the value of int type. | *int | false | +| stringValue | Reports the value of string type. | *string | false | +| floatValue | Reports the value of float type. | *[resource.Quantity](https://github.com/kubernetes/apimachinery/blob/master/pkg/api/resource/quantity.go) [kubernetes-sigs/controller-tools/issues#245](https://github.com/kubernetes-sigs/controller-tools/issues/245#issuecomment-550030238) | false | +| booleanValue | Reports the value of bool type. | *bool | false | +| arrayValue | Reports the value of array type. | [][DummyProtocolDeviceStatusObjectOrArrayProps](#dummyprotocoldevicestatusprops) | false | +| objectValue | Reports the value of object type. | map[string][DummyProtocolDeviceStatusObjectOrArrayProps](#dummyprotocoldevicestatusprops) | false | + +#### DummyProtocolDevicePropertyType + +DummyProtocolDevicePropertyType describes the type of property. + +| Field | Description | Schema | Required | +|:---|:---|:---|:---:| +| string | | string | false | +| int | | string | false | +| float | | string | false | +| boolean | | string | false | +| array | | string | false | +| object | | string | false | + ## Support Platform | OS | Arch | @@ -91,7 +169,9 @@ Grant permissions to Octopus as below: ```text Resources Non-Resource URLs Resource Names Verbs --------- ----------------- -------------- ----- + dummyprotocoldevices.devices.edge.cattle.io [] [] [create delete get list patch update watch] dummyspecialdevices.devices.edge.cattle.io [] [] [create delete get list patch update watch] + dummyprotocoldevices.devices.edge.cattle.io/status [] [] [get patch update] dummyspecialdevices.devices.edge.cattle.io/status [] [] [get patch update] ``` diff --git a/adaptors/dummy/api/v1alpha1/dummyprotocoldevice_types.go b/adaptors/dummy/api/v1alpha1/dummyprotocoldevice_types.go new file mode 100644 index 00000000..603e48dd --- /dev/null +++ b/adaptors/dummy/api/v1alpha1/dummyprotocoldevice_types.go @@ -0,0 +1,130 @@ +package v1alpha1 + +import ( + "k8s.io/apimachinery/pkg/api/resource" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// DummyProtocolDevicePropertyType describes the type of property. +// +kubebuilder:validation:Enum=string;int;float;boolean;array;object +type DummyProtocolDevicePropertyType string + +const ( + DummyProtocolDevicePropertyTypeString DummyProtocolDevicePropertyType = "string" + DummyProtocolDevicePropertyTypeInt DummyProtocolDevicePropertyType = "int" + DummyProtocolDevicePropertyTypeFloat DummyProtocolDevicePropertyType = "float" + DummyProtocolDevicePropertyTypeBoolean DummyProtocolDevicePropertyType = "boolean" + DummyProtocolDevicePropertyTypeArray DummyProtocolDevicePropertyType = "array" + DummyProtocolDevicePropertyTypeObject DummyProtocolDevicePropertyType = "object" +) + +type DummyProtocolDeviceSpecObjectOrArrayProps struct { + // +kubebuilder:validation:XPreserveUnknownFields + DummyProtocolDeviceSpecProps `json:",inline"` +} + +// DummyProtocolDeviceSpecProps defines the property of DummyProtocolDeviceSpec. +type DummyProtocolDeviceSpecProps struct { + // Describes the type of property. + // +kubebuilder:validation:Required + Type DummyProtocolDevicePropertyType `json:"type"` + + // Outlines the property. + // +optional + Description string `json:"description,omitempty"` + + // Configures the property is readOnly or not. + // +optional + ReadOnly bool `json:"readOnly,omitempty"` + + // Describes item properties of the array type. + // +optional + ArrayProps *DummyProtocolDeviceSpecObjectOrArrayProps `json:"arrayProps,omitempty"` + + // Describes properties of the object type. + // +optional + ObjectProps map[string]DummyProtocolDeviceSpecObjectOrArrayProps `json:"objectProps,omitempty"` +} + +// DummyProtocolDeviceProtocol describes the accessing protocol for dummy protocol device. +type DummyProtocolDeviceProtocol struct { + // Specifies where to connect the dummy protocol device. + IP string `json:"ip"` +} + +// DummyProtocolDeviceSpec defines the desired state of DummyProtocolDevice. +type DummyProtocolDeviceSpec struct { + // Protocol for accessing the dummy protocol device. + // +kubebuilder:validation:Required + Protocol DummyProtocolDeviceProtocol `json:"protocol"` + + // Describe the desired properties. + // +optional + Props map[string]DummyProtocolDeviceSpecProps `json:"props,omitempty"` +} + +type DummyProtocolDeviceStatusObjectOrArrayProps struct { + // +kubebuilder:validation:XPreserveUnknownFields + DummyProtocolDeviceStatusProps `json:",inline"` +} + +// DummyProtocolDeviceStatusProps defines the property of DummyProtocolDeviceStatus. +type DummyProtocolDeviceStatusProps struct { + // Reports the type of property. + Type DummyProtocolDevicePropertyType `json:"type"` + + // Reports the value of int type. + // +optional + IntValue *int `json:"intValue,omitempty"` + + // Reports the value of string type. + // +optional + StringValue *string `json:"stringValue,omitempty"` + + // Reports the value of float type. + // +optional + FloatValue *resource.Quantity `json:"floatValue,omitempty"` + + // Reports the value of boolean type. + // +optional + BooleanValue *bool `json:"booleanValue,omitempty"` + + // Reports the value of array type. + // +optional + ArrayValue []DummyProtocolDeviceStatusObjectOrArrayProps `json:"arrayValue,omitempty"` + + // Reports the value of object type. + // +optional + ObjectValue map[string]DummyProtocolDeviceStatusObjectOrArrayProps `json:"objectValue,omitempty"` +} + +// DummyProtocolDeviceStatus defines the observed state of DummyProtocolDevice. +type DummyProtocolDeviceStatus struct { + // Reports the observed value of the desired properties. + // +optional + Props map[string]DummyProtocolDeviceStatusProps `json:"props,omitempty"` +} + +// +kubebuilder:object:root=true +// +k8s:openapi-gen=true +// +kubebuilder:subresource:status +// DummyProtocolDevice is the Schema for the dummy protocol device API. +type DummyProtocolDevice struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec DummyProtocolDeviceSpec `json:"spec,omitempty"` + Status DummyProtocolDeviceStatus `json:"status,omitempty"` +} + +// +kubebuilder:object:root=true +// DummyProtocolDeviceList contains a list of DummyProtocolDevice +type DummyProtocolDeviceList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []DummyProtocolDevice `json:"items"` +} + +func init() { + SchemeBuilder.Register(&DummyProtocolDevice{}, &DummyProtocolDeviceList{}) +} diff --git a/adaptors/dummy/api/v1alpha1/zz_generated.deepcopy.go b/adaptors/dummy/api/v1alpha1/zz_generated.deepcopy.go index 17dbfda8..e2e7440d 100644 --- a/adaptors/dummy/api/v1alpha1/zz_generated.deepcopy.go +++ b/adaptors/dummy/api/v1alpha1/zz_generated.deepcopy.go @@ -23,6 +23,233 @@ import ( runtime "k8s.io/apimachinery/pkg/runtime" ) +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *DummyProtocolDevice) DeepCopyInto(out *DummyProtocolDevice) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DummyProtocolDevice. +func (in *DummyProtocolDevice) DeepCopy() *DummyProtocolDevice { + if in == nil { + return nil + } + out := new(DummyProtocolDevice) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *DummyProtocolDevice) 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 *DummyProtocolDeviceList) DeepCopyInto(out *DummyProtocolDeviceList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]DummyProtocolDevice, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DummyProtocolDeviceList. +func (in *DummyProtocolDeviceList) DeepCopy() *DummyProtocolDeviceList { + if in == nil { + return nil + } + out := new(DummyProtocolDeviceList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *DummyProtocolDeviceList) 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 *DummyProtocolDeviceProtocol) DeepCopyInto(out *DummyProtocolDeviceProtocol) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DummyProtocolDeviceProtocol. +func (in *DummyProtocolDeviceProtocol) DeepCopy() *DummyProtocolDeviceProtocol { + if in == nil { + return nil + } + out := new(DummyProtocolDeviceProtocol) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *DummyProtocolDeviceSpec) DeepCopyInto(out *DummyProtocolDeviceSpec) { + *out = *in + out.Protocol = in.Protocol + if in.Props != nil { + in, out := &in.Props, &out.Props + *out = make(map[string]DummyProtocolDeviceSpecProps, len(*in)) + for key, val := range *in { + (*out)[key] = *val.DeepCopy() + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DummyProtocolDeviceSpec. +func (in *DummyProtocolDeviceSpec) DeepCopy() *DummyProtocolDeviceSpec { + if in == nil { + return nil + } + out := new(DummyProtocolDeviceSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *DummyProtocolDeviceSpecObjectOrArrayProps) DeepCopyInto(out *DummyProtocolDeviceSpecObjectOrArrayProps) { + *out = *in + in.DummyProtocolDeviceSpecProps.DeepCopyInto(&out.DummyProtocolDeviceSpecProps) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DummyProtocolDeviceSpecObjectOrArrayProps. +func (in *DummyProtocolDeviceSpecObjectOrArrayProps) DeepCopy() *DummyProtocolDeviceSpecObjectOrArrayProps { + if in == nil { + return nil + } + out := new(DummyProtocolDeviceSpecObjectOrArrayProps) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *DummyProtocolDeviceSpecProps) DeepCopyInto(out *DummyProtocolDeviceSpecProps) { + *out = *in + if in.ArrayProps != nil { + in, out := &in.ArrayProps, &out.ArrayProps + *out = new(DummyProtocolDeviceSpecObjectOrArrayProps) + (*in).DeepCopyInto(*out) + } + if in.ObjectProps != nil { + in, out := &in.ObjectProps, &out.ObjectProps + *out = make(map[string]DummyProtocolDeviceSpecObjectOrArrayProps, len(*in)) + for key, val := range *in { + (*out)[key] = *val.DeepCopy() + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DummyProtocolDeviceSpecProps. +func (in *DummyProtocolDeviceSpecProps) DeepCopy() *DummyProtocolDeviceSpecProps { + if in == nil { + return nil + } + out := new(DummyProtocolDeviceSpecProps) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *DummyProtocolDeviceStatus) DeepCopyInto(out *DummyProtocolDeviceStatus) { + *out = *in + if in.Props != nil { + in, out := &in.Props, &out.Props + *out = make(map[string]DummyProtocolDeviceStatusProps, len(*in)) + for key, val := range *in { + (*out)[key] = *val.DeepCopy() + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DummyProtocolDeviceStatus. +func (in *DummyProtocolDeviceStatus) DeepCopy() *DummyProtocolDeviceStatus { + if in == nil { + return nil + } + out := new(DummyProtocolDeviceStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *DummyProtocolDeviceStatusObjectOrArrayProps) DeepCopyInto(out *DummyProtocolDeviceStatusObjectOrArrayProps) { + *out = *in + in.DummyProtocolDeviceStatusProps.DeepCopyInto(&out.DummyProtocolDeviceStatusProps) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DummyProtocolDeviceStatusObjectOrArrayProps. +func (in *DummyProtocolDeviceStatusObjectOrArrayProps) DeepCopy() *DummyProtocolDeviceStatusObjectOrArrayProps { + if in == nil { + return nil + } + out := new(DummyProtocolDeviceStatusObjectOrArrayProps) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *DummyProtocolDeviceStatusProps) DeepCopyInto(out *DummyProtocolDeviceStatusProps) { + *out = *in + if in.IntValue != nil { + in, out := &in.IntValue, &out.IntValue + *out = new(int) + **out = **in + } + if in.StringValue != nil { + in, out := &in.StringValue, &out.StringValue + *out = new(string) + **out = **in + } + if in.FloatValue != nil { + in, out := &in.FloatValue, &out.FloatValue + x := (*in).DeepCopy() + *out = &x + } + if in.BooleanValue != nil { + in, out := &in.BooleanValue, &out.BooleanValue + *out = new(bool) + **out = **in + } + if in.ArrayValue != nil { + in, out := &in.ArrayValue, &out.ArrayValue + *out = make([]DummyProtocolDeviceStatusObjectOrArrayProps, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.ObjectValue != nil { + in, out := &in.ObjectValue, &out.ObjectValue + *out = make(map[string]DummyProtocolDeviceStatusObjectOrArrayProps, len(*in)) + for key, val := range *in { + (*out)[key] = *val.DeepCopy() + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DummyProtocolDeviceStatusProps. +func (in *DummyProtocolDeviceStatusProps) DeepCopy() *DummyProtocolDeviceStatusProps { + if in == nil { + return nil + } + out := new(DummyProtocolDeviceStatusProps) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *DummySpecialDevice) DeepCopyInto(out *DummySpecialDevice) { *out = *in diff --git a/adaptors/dummy/deploy/e2e/all_in_one.yaml b/adaptors/dummy/deploy/e2e/all_in_one.yaml index 1ba587d0..f407a451 100644 --- a/adaptors/dummy/deploy/e2e/all_in_one.yaml +++ b/adaptors/dummy/deploy/e2e/all_in_one.yaml @@ -1,5 +1,161 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.2.5 + devices.edge.cattle.io/description: dummy device description + devices.edge.cattle.io/device-property: "" + devices.edge.cattle.io/enable: "true" + devices.edge.cattle.io/icon: "" + creationTimestamp: null + labels: + app.kubernetes.io/name: octopus-adaptor-dummy + app.kubernetes.io/version: master + name: dummyprotocoldevices.devices.edge.cattle.io +spec: + group: devices.edge.cattle.io + names: + kind: DummyProtocolDevice + listKind: DummyProtocolDeviceList + plural: dummyprotocoldevices + singular: dummyprotocoldevice + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: DummyProtocolDevice is the Schema for the dummy protocol device + 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: DummyProtocolDeviceSpec defines the desired state of DummyProtocolDevice. + properties: + props: + additionalProperties: + description: DummyProtocolDeviceSpecProps defines the property of + DummyProtocolDeviceSpec. + properties: + arrayProps: + description: Describes item properties of the array type. + type: object + x-kubernetes-preserve-unknown-fields: true + description: + description: Outlines the property. + type: string + objectProps: + additionalProperties: + type: object + x-kubernetes-preserve-unknown-fields: true + description: Describes properties of the object type. + type: object + readOnly: + description: Configures the property is readOnly or not. + type: boolean + type: + description: Describes the type of property. + enum: + - string + - int + - float + - boolean + - array + - object + type: string + required: + - type + type: object + description: Describe the desired properties. + type: object + protocol: + description: Protocol for accessing the dummy protocol device. + properties: + ip: + description: Specifies where to connect the dummy protocol device. + type: string + required: + - ip + type: object + required: + - protocol + type: object + status: + description: DummyProtocolDeviceStatus defines the observed state of DummyProtocolDevice. + properties: + props: + additionalProperties: + description: DummyProtocolDeviceStatusProps defines the property + of DummyProtocolDeviceStatus. + properties: + arrayValue: + description: Reports the value of array type. + items: + type: object + x-kubernetes-preserve-unknown-fields: true + type: array + booleanValue: + description: Reports the value of boolean type. + type: boolean + floatValue: + anyOf: + - type: integer + - type: string + description: Reports the value of float type. + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + intValue: + description: Reports the value of int type. + type: integer + objectValue: + additionalProperties: + type: object + x-kubernetes-preserve-unknown-fields: true + description: Reports the value of object type. + type: object + stringValue: + description: Reports the value of string type. + type: string + type: + description: Reports the type of property. + enum: + - string + - int + - float + - boolean + - array + - object + type: string + required: + - type + type: object + description: Reports the observed value of the desired properties. + type: object + type: object + type: object + served: true + storage: true + subresources: + status: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: [] + storedVersions: [] +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition metadata: annotations: controller-gen.kubebuilder.io/version: v0.2.5 @@ -113,6 +269,26 @@ metadata: app.kubernetes.io/version: master name: octopus-adaptor-dummy-manager-role rules: +- apiGroups: + - devices.edge.cattle.io + resources: + - dummyprotocoldevices + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - devices.edge.cattle.io + resources: + - dummyprotocoldevices/status + verbs: + - get + - patch + - update - apiGroups: - devices.edge.cattle.io resources: diff --git a/adaptors/dummy/deploy/e2e/dl_protocoldevice.yaml b/adaptors/dummy/deploy/e2e/dl_protocoldevice.yaml new file mode 100644 index 00000000..eee53d0e --- /dev/null +++ b/adaptors/dummy/deploy/e2e/dl_protocoldevice.yaml @@ -0,0 +1,42 @@ +apiVersion: edge.cattle.io/v1alpha1 +kind: DeviceLink +metadata: + name: localhost-robot +spec: + adaptor: + node: edge-worker + name: adaptors.edge.cattle.io/dummy + model: + apiVersion: "devices.edge.cattle.io/v1alpha1" + kind: "DummyProtocolDevice" + template: + metadata: + labels: + device: localhost-robot + spec: + protocol: + ip: "127.0.0.1" + props: + name: + type: string + description: "The name (unique identifier) of the robot." + readOnly: true + gender: + type: object + description: "The gender of the robot." + objectProps: + name: + type: string + description: "The name of the gender." + code: + type: int + description: "The code of the gender." + friends: + type: array + description: "The name list of the robot's friends." + arrayProps: + type: string + description: "The name of the friend." + power: + type: float + description: "The power of the robot." diff --git a/adaptors/dummy/deploy/manifests/crd/base/devices.edge.cattle.io_dummyprotocoldevices.yaml b/adaptors/dummy/deploy/manifests/crd/base/devices.edge.cattle.io_dummyprotocoldevices.yaml new file mode 100644 index 00000000..1a569a10 --- /dev/null +++ b/adaptors/dummy/deploy/manifests/crd/base/devices.edge.cattle.io_dummyprotocoldevices.yaml @@ -0,0 +1,150 @@ + +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.2.5 + creationTimestamp: null + name: dummyprotocoldevices.devices.edge.cattle.io +spec: + group: devices.edge.cattle.io + names: + kind: DummyProtocolDevice + listKind: DummyProtocolDeviceList + plural: dummyprotocoldevices + singular: dummyprotocoldevice + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: DummyProtocolDevice is the Schema for the dummy protocol device + 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: DummyProtocolDeviceSpec defines the desired state of DummyProtocolDevice. + properties: + props: + additionalProperties: + description: DummyProtocolDeviceSpecProps defines the property of + DummyProtocolDeviceSpec. + properties: + arrayProps: + description: Describes item properties of the array type. + type: object + x-kubernetes-preserve-unknown-fields: true + description: + description: Outlines the property. + type: string + objectProps: + additionalProperties: + type: object + x-kubernetes-preserve-unknown-fields: true + description: Describes properties of the object type. + type: object + readOnly: + description: Configures the property is readOnly or not. + type: boolean + type: + description: Describes the type of property. + enum: + - string + - int + - float + - boolean + - array + - object + type: string + required: + - type + type: object + description: Describe the desired properties. + type: object + protocol: + description: Protocol for accessing the dummy protocol device. + properties: + ip: + description: Specifies where to connect the dummy protocol device. + type: string + required: + - ip + type: object + required: + - protocol + type: object + status: + description: DummyProtocolDeviceStatus defines the observed state of DummyProtocolDevice. + properties: + props: + additionalProperties: + description: DummyProtocolDeviceStatusProps defines the property + of DummyProtocolDeviceStatus. + properties: + arrayValue: + description: Reports the value of array type. + items: + type: object + x-kubernetes-preserve-unknown-fields: true + type: array + booleanValue: + description: Reports the value of boolean type. + type: boolean + floatValue: + anyOf: + - type: integer + - type: string + description: Reports the value of float type. + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + intValue: + description: Reports the value of int type. + type: integer + objectValue: + additionalProperties: + type: object + x-kubernetes-preserve-unknown-fields: true + description: Reports the value of object type. + type: object + stringValue: + description: Reports the value of string type. + type: string + type: + description: Reports the type of property. + enum: + - string + - int + - float + - boolean + - array + - object + type: string + required: + - type + type: object + description: Reports the observed value of the desired properties. + type: object + type: object + type: object + served: true + storage: true + subresources: + status: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: [] + storedVersions: [] diff --git a/adaptors/dummy/deploy/manifests/crd/kustomization.yaml b/adaptors/dummy/deploy/manifests/crd/kustomization.yaml index f2648cbe..31d45c5b 100644 --- a/adaptors/dummy/deploy/manifests/crd/kustomization.yaml +++ b/adaptors/dummy/deploy/manifests/crd/kustomization.yaml @@ -6,3 +6,4 @@ commonAnnotations: resources: - base/devices.edge.cattle.io_dummyspecialdevices.yaml + - base/devices.edge.cattle.io_dummyprotocoldevices.yaml diff --git a/adaptors/dummy/deploy/manifests/rbac/role.yaml b/adaptors/dummy/deploy/manifests/rbac/role.yaml index 8f735294..02446e0d 100644 --- a/adaptors/dummy/deploy/manifests/rbac/role.yaml +++ b/adaptors/dummy/deploy/manifests/rbac/role.yaml @@ -6,6 +6,26 @@ metadata: creationTimestamp: null name: manager-role rules: +- apiGroups: + - devices.edge.cattle.io + resources: + - dummyprotocoldevices + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - devices.edge.cattle.io + resources: + - dummyprotocoldevices/status + verbs: + - get + - patch + - update - apiGroups: - devices.edge.cattle.io resources: diff --git a/adaptors/dummy/pkg/adaptor/service.go b/adaptors/dummy/pkg/adaptor/service.go index 0bca3664..aa7586f9 100644 --- a/adaptors/dummy/pkg/adaptor/service.go +++ b/adaptors/dummy/pkg/adaptor/service.go @@ -125,6 +125,46 @@ func (s *Service) Connect(server api.Connection_ConnectServer) error { return status.Errorf(codes.InvalidArgument, "failed to configure the device: %v", err) } + case "DummyProtocolDevice": + // get device spec + var device v1alpha1.DummyProtocolDevice + if err := jsoniter.Unmarshal(req.GetDevice(), &device); err != nil { + return status.Errorf(codes.InvalidArgument, "failed to unmarshal device: %v", err) + } + + // create device handler + if holder == nil { + // get device NamespacedName + var deviceName = object.GetNamespacedName(&device) + if deviceName.Namespace == "" || deviceName.Name == "" { + return status.Error(codes.InvalidArgument, "failed to recognize the empty device as the namespace/name is blank") + } + + // create handler for sync to limb + var toLimb = func(in *v1alpha1.DummyProtocolDevice) { + // convert device to json bytes + var respBytes = s.toJSON(in) + + // send device to limb + if err := server.Send(&api.ConnectResponse{Device: respBytes}); err != nil { + if !connection.IsClosed(err) { + log.Error(err, "Failed to send response to connection", "device", deviceName) + } + } + } + + holder = physical.NewProtocolDevice( + log.WithValues("device", deviceName), + &device, + toLimb, + ) + } + + // configure device + if err := holder.Configure(device.Spec); err != nil { + return status.Errorf(codes.InvalidArgument, "failed to configure the device: %v", err) + } + default: return status.Errorf(codes.InvalidArgument, "invalid model kind: %s", modelGVK.Kind) } diff --git a/adaptors/dummy/pkg/dummy/dummy.go b/adaptors/dummy/pkg/dummy/dummy.go index 5bc6fc43..194592a1 100644 --- a/adaptors/dummy/pkg/dummy/dummy.go +++ b/adaptors/dummy/pkg/dummy/dummy.go @@ -19,6 +19,8 @@ const ( // +kubebuilder:rbac:groups=devices.edge.cattle.io,resources=dummyspecialdevices,verbs=get;list;watch;create;update;patch;delete // +kubebuilder:rbac:groups=devices.edge.cattle.io,resources=dummyspecialdevices/status,verbs=get;update;patch +// +kubebuilder:rbac:groups=devices.edge.cattle.io,resources=dummyprotocoldevices,verbs=get;list;watch;create;update;patch;delete +// +kubebuilder:rbac:groups=devices.edge.cattle.io,resources=dummyprotocoldevices/status,verbs=get;update;patch func Run() error { var stop = ctrl.SetupSignalHandler() diff --git a/adaptors/dummy/pkg/physical/device_protocol.go b/adaptors/dummy/pkg/physical/device_protocol.go new file mode 100644 index 00000000..84bb04f5 --- /dev/null +++ b/adaptors/dummy/pkg/physical/device_protocol.go @@ -0,0 +1,234 @@ +package physical + +import ( + "sync" + "time" + + "github.com/go-logr/logr" + "github.com/pkg/errors" + + "github.com/rancher/octopus/adaptors/dummy/api/v1alpha1" +) + +func NewProtocolDevice(log logr.Logger, instance *v1alpha1.DummyProtocolDevice, toLimb ProtocolDeviceSyncer) Device { + return &protocolDevice{ + log: log, + instance: instance, + toLimb: toLimb, + } +} + +type protocolDevice struct { + sync.Once + sync.Mutex + + stop chan struct{} + log logr.Logger + + instance *v1alpha1.DummyProtocolDevice + toLimb ProtocolDeviceSyncer +} + +func (d *protocolDevice) Configure(configuration interface{}) error { + var spec, ok = configuration.(v1alpha1.DummyProtocolDeviceSpec) + if !ok { + d.log.Error(errors.New("invalidate configuration type"), "Failed to configure") + return nil + } + + d.Lock() + defer d.Unlock() + + d.instance.Spec = spec + shuffleStatus(d.instance) + d.toLimb(d.instance.DeepCopy()) + + d.Do(func() { + d.stop = make(chan struct{}) + go d.mockPhysicalWatching(d.stop) + }) + + return nil +} + +func (d *protocolDevice) Shutdown() { + d.Lock() + defer d.Unlock() + + if d.stop != nil { + close(d.stop) + d.stop = nil + } + + d.log.Info("Closed connection") +} + +// mockPhysicalWatching is used to simulate real device state changes +// and synchronize the changed values back to the limb. +func (d *protocolDevice) mockPhysicalWatching(stop <-chan struct{}) { + d.log.Info("Mocking started") + defer func() { + d.log.Info("Mocking finished") + }() + + var ticker = time.NewTicker(2 * time.Second) + defer ticker.Stop() + + for { + select { + case <-stop: + return + case <-ticker.C: + } + + d.Lock() + + func() { + defer d.Unlock() + + shuffleStatus(d.instance) + d.toLimb(d.instance.DeepCopy()) + }() + + select { + case <-stop: + return + default: + } + } +} + +// Randomly generate some observed properties according to the desired properties. +func shuffleStatus(instance *v1alpha1.DummyProtocolDevice) { + var statusProps = instance.Status.Props + if len(statusProps) == 0 { + statusProps = make(map[string]v1alpha1.DummyProtocolDeviceStatusProps, len(instance.Spec.Props)) + } + + fillStatusObject(instance.Spec.Props, statusProps) + instance.Status.Props = statusProps +} + +func fillStatusArray(source v1alpha1.DummyProtocolDeviceSpecProps, length int) []v1alpha1.DummyProtocolDeviceStatusProps { + var target []v1alpha1.DummyProtocolDeviceStatusProps + var sourceProp = source + for i := 0; i < length; i++ { + switch sourceProp.Type { + case v1alpha1.DummyProtocolDevicePropertyTypeBoolean: + target = append(target, v1alpha1.DummyProtocolDeviceStatusProps{ + Type: v1alpha1.DummyProtocolDevicePropertyTypeBoolean, + BooleanValue: randomBoolean(), + }) + case v1alpha1.DummyProtocolDevicePropertyTypeFloat: + target = append(target, v1alpha1.DummyProtocolDeviceStatusProps{ + Type: v1alpha1.DummyProtocolDevicePropertyTypeFloat, + FloatValue: randomFloat(), + }) + case v1alpha1.DummyProtocolDevicePropertyTypeInt: + target = append(target, v1alpha1.DummyProtocolDeviceStatusProps{ + Type: v1alpha1.DummyProtocolDevicePropertyTypeInt, + IntValue: randomInt(1000), + }) + case v1alpha1.DummyProtocolDevicePropertyTypeString: + target = append(target, v1alpha1.DummyProtocolDeviceStatusProps{ + Type: v1alpha1.DummyProtocolDevicePropertyTypeString, + StringValue: randomString(10), + }) + case v1alpha1.DummyProtocolDevicePropertyTypeArray: + if sourceProp.ArrayProps != nil { + var items = fillStatusArray(sourceProp.ArrayProps.DummyProtocolDeviceSpecProps, *randomInt(10)) + target = append(target, v1alpha1.DummyProtocolDeviceStatusProps{ + Type: v1alpha1.DummyProtocolDevicePropertyTypeArray, + ArrayValue: toStatusObjectOrArrayPropsArray(items), + }) + } + case v1alpha1.DummyProtocolDevicePropertyTypeObject: + if len(sourceProp.ObjectProps) != 0 { + var object = make(map[string]v1alpha1.DummyProtocolDeviceStatusProps, len(sourceProp.ObjectProps)) + fillStatusObject(toSpecPropsObject(sourceProp.ObjectProps), object) + target = append(target, v1alpha1.DummyProtocolDeviceStatusProps{ + Type: v1alpha1.DummyProtocolDevicePropertyTypeObject, + ObjectValue: toStatusObjectOrArrayPropsObject(object), + }) + } + } + } + + return target +} + +func fillStatusObject(source map[string]v1alpha1.DummyProtocolDeviceSpecProps, target map[string]v1alpha1.DummyProtocolDeviceStatusProps) { + for sourcePropName, sourceProp := range source { + if _, exist := target[sourcePropName]; exist && sourceProp.ReadOnly { + continue + } + + switch sourceProp.Type { + case v1alpha1.DummyProtocolDevicePropertyTypeBoolean: + target[sourcePropName] = v1alpha1.DummyProtocolDeviceStatusProps{ + Type: v1alpha1.DummyProtocolDevicePropertyTypeBoolean, + BooleanValue: randomBoolean(), + } + case v1alpha1.DummyProtocolDevicePropertyTypeFloat: + target[sourcePropName] = v1alpha1.DummyProtocolDeviceStatusProps{ + Type: v1alpha1.DummyProtocolDevicePropertyTypeFloat, + FloatValue: randomFloat(), + } + case v1alpha1.DummyProtocolDevicePropertyTypeInt: + target[sourcePropName] = v1alpha1.DummyProtocolDeviceStatusProps{ + Type: v1alpha1.DummyProtocolDevicePropertyTypeInt, + IntValue: randomInt(1000), + } + case v1alpha1.DummyProtocolDevicePropertyTypeString: + target[sourcePropName] = v1alpha1.DummyProtocolDeviceStatusProps{ + Type: v1alpha1.DummyProtocolDevicePropertyTypeString, + StringValue: randomString(10), + } + case v1alpha1.DummyProtocolDevicePropertyTypeArray: + if sourceProp.ArrayProps != nil { + var items = fillStatusArray(sourceProp.ArrayProps.DummyProtocolDeviceSpecProps, *randomInt(10)) + target[sourcePropName] = v1alpha1.DummyProtocolDeviceStatusProps{ + Type: v1alpha1.DummyProtocolDevicePropertyTypeArray, + ArrayValue: toStatusObjectOrArrayPropsArray(items), + } + } + case v1alpha1.DummyProtocolDevicePropertyTypeObject: + if len(sourceProp.ObjectProps) != 0 { + var object = make(map[string]v1alpha1.DummyProtocolDeviceStatusProps, len(sourceProp.ObjectProps)) + fillStatusObject(toSpecPropsObject(sourceProp.ObjectProps), object) + target[sourcePropName] = v1alpha1.DummyProtocolDeviceStatusProps{ + Type: v1alpha1.DummyProtocolDevicePropertyTypeObject, + ObjectValue: toStatusObjectOrArrayPropsObject(object), + } + } + } + } +} + +func toStatusObjectOrArrayPropsArray(props []v1alpha1.DummyProtocolDeviceStatusProps) []v1alpha1.DummyProtocolDeviceStatusObjectOrArrayProps { + var ret = make([]v1alpha1.DummyProtocolDeviceStatusObjectOrArrayProps, 0, len(props)) + for _, prop := range props { + ret = append(ret, v1alpha1.DummyProtocolDeviceStatusObjectOrArrayProps{ + DummyProtocolDeviceStatusProps: prop, + }) + } + return ret +} + +func toStatusObjectOrArrayPropsObject(props map[string]v1alpha1.DummyProtocolDeviceStatusProps) map[string]v1alpha1.DummyProtocolDeviceStatusObjectOrArrayProps { + var ret = make(map[string]v1alpha1.DummyProtocolDeviceStatusObjectOrArrayProps, len(props)) + for propName, prop := range props { + ret[propName] = v1alpha1.DummyProtocolDeviceStatusObjectOrArrayProps{ + DummyProtocolDeviceStatusProps: prop, + } + } + return ret +} + +func toSpecPropsObject(props map[string]v1alpha1.DummyProtocolDeviceSpecObjectOrArrayProps) map[string]v1alpha1.DummyProtocolDeviceSpecProps { + var ret = make(map[string]v1alpha1.DummyProtocolDeviceSpecProps, len(props)) + for propName, prop := range props { + ret[propName] = prop.DummyProtocolDeviceSpecProps + } + return ret +} diff --git a/adaptors/dummy/pkg/physical/handler.go b/adaptors/dummy/pkg/physical/handler.go index c85ade50..4abeb072 100644 --- a/adaptors/dummy/pkg/physical/handler.go +++ b/adaptors/dummy/pkg/physical/handler.go @@ -6,3 +6,6 @@ import ( // SpecialDeviceSyncer is used to sync physical special device. type SpecialDeviceSyncer func(in *v1alpha1.DummySpecialDevice) + +// ProtocolDeviceSyncer is used to sync physical special device. +type ProtocolDeviceSyncer func(in *v1alpha1.DummyProtocolDevice) diff --git a/adaptors/dummy/pkg/physical/random_generator.go b/adaptors/dummy/pkg/physical/random_generator.go new file mode 100644 index 00000000..019737a2 --- /dev/null +++ b/adaptors/dummy/pkg/physical/random_generator.go @@ -0,0 +1,53 @@ +package physical + +import ( + "fmt" + "math/rand" + "time" + + "k8s.io/apimachinery/pkg/api/resource" +) + +var rndSrc = rand.NewSource(time.Now().UnixNano()) +var rnd = rand.New(rndSrc) + +const letterBytes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" +const ( + letterIdxBits = 6 // 6 bits to represent a letter index + letterIdxMask = 1<= 0; { + if remain == 0 { + cache, remain = rndSrc.Int63(), letterIdxMax + } + if idx := int(cache & letterIdxMask); idx < len(letterBytes) { + b[i] = letterBytes[idx] + i-- + } + cache >>= letterIdxBits + remain-- + } + + var ret = string(b) + return &ret +} + +func randomInt(n int) *int { + var ret = rnd.Intn(n) + return &ret +} + +func randomFloat() *resource.Quantity { + var ret = resource.MustParse(fmt.Sprintf("%f", rnd.Float64())) + return &ret +} + +func randomBoolean() *bool { + var ret = rnd.Intn(2)/2 == 0 + return &ret +} diff --git a/adaptors/dummy/test/integration/adaptor/connection_test.go b/adaptors/dummy/test/integration/adaptor/connection_test.go index 0fec9e86..1080cd4b 100644 --- a/adaptors/dummy/test/integration/adaptor/connection_test.go +++ b/adaptors/dummy/test/integration/adaptor/connection_test.go @@ -18,7 +18,8 @@ import ( // testing scenarios: // + Server // - validate if the connection stop when it closes -// - validate the process of input parameters +// - validate the process of input model +// - validate the recognition of the input model // - validate the process of input device var _ = Describe("Connection", func() { var ( @@ -107,6 +108,34 @@ var _ = Describe("Connection", func() { Expect(sts.Message()).To(Equal("invalid model kind: InvalidateSpecialDevice")) }) + It("should distinguish the input model", func() { + // distinguish the devices.edge.cattle.io/v1alpha1/DummySpecialDevice model + mockServer.EXPECT().Recv().Return(&v1alpha1.ConnectRequest{ + Model: &metav1.TypeMeta{ + APIVersion: "devices.edge.cattle.io/v1alpha1", + Kind: "DummySpecialDevice", + }, + Device: []byte(`{}`), + }, nil) + err = service.Connect(mockServer) + var sts = status.Convert(err) + Expect(sts.Code()).To(Equal(grpccodes.InvalidArgument)) + Expect(sts.Message()).To(Equal("failed to recognize the empty device as the namespace/name is blank")) + + // distinguish the devices.edge.cattle.io/v1alpha1/DummyProtocolDevice model + mockServer.EXPECT().Recv().Return(&v1alpha1.ConnectRequest{ + Model: &metav1.TypeMeta{ + APIVersion: "devices.edge.cattle.io/v1alpha1", + Kind: "DummyProtocolDevice", + }, + Device: []byte(`{}`), + }, nil) + err = service.Connect(mockServer) + sts = status.Convert(err) + Expect(sts.Code()).To(Equal(grpccodes.InvalidArgument)) + Expect(sts.Message()).To(Equal("failed to recognize the empty device as the namespace/name is blank")) + }) + It("should process the input device", func() { // failed unmarshal mockServer.EXPECT().Recv().Return(&v1alpha1.ConnectRequest{