diff --git a/src/agent/fabric-operator/build/bin/templates/ca/ca_secret.yaml b/src/agent/fabric-operator/build/bin/templates/ca/ca_secret.yaml new file mode 100644 index 000000000..9b17ea2d2 --- /dev/null +++ b/src/agent/fabric-operator/build/bin/templates/ca/ca_secret.yaml @@ -0,0 +1,7 @@ +kind: Secret +apiVersion: v1 +metadata: + name: "" +type: Opaque +data: + key: "YWRtaW4=" \ No newline at end of file diff --git a/src/agent/fabric-operator/build/bin/templates/orderer/orderer_secret.yaml b/src/agent/fabric-operator/build/bin/templates/orderer/orderer_secret.yaml new file mode 100644 index 000000000..9b17ea2d2 --- /dev/null +++ b/src/agent/fabric-operator/build/bin/templates/orderer/orderer_secret.yaml @@ -0,0 +1,7 @@ +kind: Secret +apiVersion: v1 +metadata: + name: "" +type: Opaque +data: + key: "YWRtaW4=" \ No newline at end of file diff --git a/src/agent/fabric-operator/build/bin/templates/orderer/orderer_statefulset.yaml b/src/agent/fabric-operator/build/bin/templates/orderer/orderer_statefulset.yaml index 177ece8e4..142fc938b 100755 --- a/src/agent/fabric-operator/build/bin/templates/orderer/orderer_statefulset.yaml +++ b/src/agent/fabric-operator/build/bin/templates/orderer/orderer_statefulset.yaml @@ -25,6 +25,9 @@ spec: component: "orderer" spec: volumes: + - name: orderercerts + secret: + secretName: orderercerts - name: toolset configMap: name: fabric-configuration-toolset @@ -40,5 +43,6 @@ spec: volumeMounts: - mountPath: "/etc/hyperledger/orderer" name: ordererstorage + - mountPath: "/certs" + name: orderercerts command: ["orderer"] - diff --git a/src/agent/fabric-operator/build/bin/templates/peer/peer_secret.yaml b/src/agent/fabric-operator/build/bin/templates/peer/peer_secret.yaml new file mode 100644 index 000000000..9b17ea2d2 --- /dev/null +++ b/src/agent/fabric-operator/build/bin/templates/peer/peer_secret.yaml @@ -0,0 +1,7 @@ +kind: Secret +apiVersion: v1 +metadata: + name: "" +type: Opaque +data: + key: "YWRtaW4=" \ No newline at end of file diff --git a/src/agent/fabric-operator/build/bin/templates/peer/peer_statefulset.yaml b/src/agent/fabric-operator/build/bin/templates/peer/peer_statefulset.yaml index ccae9fd5d..48396ad63 100755 --- a/src/agent/fabric-operator/build/bin/templates/peer/peer_statefulset.yaml +++ b/src/agent/fabric-operator/build/bin/templates/peer/peer_statefulset.yaml @@ -26,6 +26,9 @@ spec: component: "peer" spec: volumes: + - name: peercerts + secret: + secretName: peercerts - name: toolset configMap: name: fabric-configuration-toolset @@ -41,5 +44,7 @@ spec: volumeMounts: - mountPath: "/etc/hyperledger/peer" name: peerstorage + - mountPath: "/certs" + name: peercerts command: ["peer"] args: ["node", "start"] diff --git a/src/agent/fabric-operator/deploy/crds/fabric_v1alpha1_ca_cr.yaml b/src/agent/fabric-operator/deploy/crds/fabric_v1alpha1_ca_cr.yaml index ab86e0dfc..8a4afee6e 100755 --- a/src/agent/fabric-operator/deploy/crds/fabric_v1alpha1_ca_cr.yaml +++ b/src/agent/fabric-operator/deploy/crds/fabric_v1alpha1_ca_cr.yaml @@ -8,24 +8,22 @@ spec: # you have the k8s secret created. admin: "sampleadmin" adminPassword: "samplepassword" - - # Specify Fabric binaries to be used to setup the fabric CA - image: "hyperledger/fabric-ca:1.4.1" - # Specify storage being used by this Certificate Authority. - storageSize: "1Gi" - storageClass: "default" + #storageClass: "default" + #storageSize: "1Gi" # If you have an set of certs that you like to use instead of # generating a set by Fabric CA, you can specify as the following. # Certificates and private keys have all to be base64 encoded as # the values of the each item below. - # certs: - # cert: "The base64 encoded certificate" - # key: "The base64 encoded private key" - # tlsCert: "The base64 encoded tls certificate" - # tlsKey: "The base64 encoded tls private key" - + #certs: + # cert: + # key: + # tlsCert: + # tlsKey: + nodeSpec: + # Specify Fabric binaries to be used to setup the fabric CA + image: "hyperledger/fabric-ca:1.4.1" # Optionally, FQDN can also be specified # hosts: ["ca.sample.com", "169.45.20.0"] @@ -49,4 +47,4 @@ spec: # FABRIC_CA_SERVER_CSR_NAMES_0_ST: "North Carolina" # FABRIC_CA_SERVER_CSR_NAMES_0_L: "Cary" # FABRIC_CA_SERVER_CSR_NAMES_0_O: "Sample Org" - # FABRIC_CA_SERVER_CSR_NAMES_0_OU: "Sample Org Unit" \ No newline at end of file + # FABRIC_CA_SERVER_CSR_NAMES_0_OU: "Sample Org Unit" diff --git a/src/agent/fabric-operator/deploy/crds/fabric_v1alpha1_orderer_cr.yaml b/src/agent/fabric-operator/deploy/crds/fabric_v1alpha1_orderer_cr.yaml index 8aefcb811..c51b8ea47 100755 --- a/src/agent/fabric-operator/deploy/crds/fabric_v1alpha1_orderer_cr.yaml +++ b/src/agent/fabric-operator/deploy/crds/fabric_v1alpha1_orderer_cr.yaml @@ -3,40 +3,56 @@ kind: Orderer metadata: name: orderer00 spec: - storageSize: "1Gi" - storageClass: "default" - image: "hyperledger/fabric-orderer:1.4.1" - - # To specify resource limits for this orderer node, - # use kubernetes resource requirements spec - # resources: - # requests: - # memory: "32Mi" - # cpu: "200m" - # limits: - # memory: "1024mi" - # cpu: "250" - - # Add all the configurable peer parameters as + # If you have an set of certs that you like to use instead of + # generating a set by Fabric CA, you can specify as the following. + # Certificates and private keys have all to be base64 encoded as + # the values of the each item below. + #certs: + # tlsCerts: + # tlsPrivatekey: + # tlsCert: + # tlsRootcas: + # msp: + # adminCerts: + # caCerts: + # keyStore: + # signCerts: + # tlsCacerts: + nodeSpec: + # To specify resource limits for this orderer node, + # use kubernetes resource requirements spec + # resources: + # requests: + # memory: "32Mi" + # cpu: "200m" + # limits: + # memory: "1024mi" + # cpu: "250" + storageSize: "1Gi" + storageClass: "default" + image: "hyperledger/fabric-orderer:1.4.1" + # Add all the configurable peer parameters as # name-value pairs - configParams: - - name: ORDERER_CFG_PATH - value: /shared/ - - name: ORDERER_GENERAL_LEDGERTYPE - value: file - - name: ORDERER_FILELEDGER_LOCATION - value: /shared/ledger/orderer - - name: ORDERER_GENERAL_BATCHTIMEOUT - value: 1s - - name: ORDERER_GENERAL_BATCHSIZE_MAXMESSAGECOUNT - value: "10" - - name: ORDERER_GENERAL_MAXWINDOWSIZE - value: "1000" - - name: ORDERER_GENERAL_ORDERERTYPE - value: solo - - name: ORDERER_GENERAL_LISTENADDRESS - value: 0.0.0.0 - - name: ORDERER_GENERAL_LISTENPORT - value: "31010" - - name: ORDERER_GENERAL_LOGLEVEL - value: debug + configParams: + - name: ORDERER_CFG_PATH + value: /shared/ + - name: ORDERER_GENERAL_LEDGERTYPE + value: file + - name: ORDERER_FILELEDGER_LOCATION + value: /shared/ledger/orderer + - name: ORDERER_GENERAL_BATCHTIMEOUT + value: 1s + - name: ORDERER_GENERAL_BATCHSIZE_MAXMESSAGECOUNT + value: "10" + - name: ORDERER_GENERAL_MAXWINDOWSIZE + value: "1000" + - name: ORDERER_GENERAL_ORDERERTYPE + value: solo + - name: ORDERER_GENERAL_LISTENADDRESS + value: 0.0.0.0 + - name: ORDERER_GENERAL_LISTENPORT + value: "31010" + - name: ORDERER_GENERAL_LOGLEVEL + value: debug + - name: ORDERER_GENERAL_TLS_ENABLED + value: "true" diff --git a/src/agent/fabric-operator/deploy/crds/fabric_v1alpha1_orderer_crd.yaml b/src/agent/fabric-operator/deploy/crds/fabric_v1alpha1_orderer_crd.yaml index c4b4515bb..ed95c2ae9 100644 --- a/src/agent/fabric-operator/deploy/crds/fabric_v1alpha1_orderer_crd.yaml +++ b/src/agent/fabric-operator/deploy/crds/fabric_v1alpha1_orderer_crd.yaml @@ -29,37 +29,95 @@ spec: type: object spec: properties: - configParams: - items: - properties: - name: - type: string - value: - type: string - required: - - name - - value - type: object - type: array - hosts: - items: - type: string - type: array - image: + certs: description: 'INSERT ADDITIONAL SPEC FIELDS - desired state of cluster Important: Run "operator-sdk generate k8s" to regenerate code after modifying this file Add custom validation using kubebuilder tags: https://book-v1.book.kubebuilder.io/beyond_basics/generating_crd.html' - type: string - resources: + properties: + msp: + properties: + adminCerts: + items: + type: string + type: array + caCerts: + items: + type: string + type: array + intermediateCerts: + items: + type: string + type: array + keyStore: + type: string + signCerts: + type: string + tlsCacerts: + items: + type: string + type: array + tlsIntermediatecerts: + items: + type: string + type: array + required: + - adminCerts + - caCerts + - keyStore + - signCerts + type: object + tlsCerts: + properties: + tlsCert: + type: string + tlsPrivatekey: + type: string + tlsRootcas: + items: + type: string + type: array + tlsRootcert: + type: string + type: object + required: + - msp + - tlsCerts + type: object + nodeSpec: + properties: + configParams: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + hosts: + items: + type: string + type: array + image: + description: 'INSERT ADDITIONAL SPEC FIELDS - desired state of cluster + Important: Run "operator-sdk generate k8s" to regenerate code + after modifying this file Add custom validation using kubebuilder + tags: https://book-v1.book.kubebuilder.io/beyond_basics/generating_crd.html' + type: string + resources: + type: object + storageClass: + type: string + storageSize: + type: string + required: + - image + - configParams type: object - storageClass: - type: string - storageSize: - type: string - required: - - image - - configParams type: object status: properties: diff --git a/src/agent/fabric-operator/deploy/crds/fabric_v1alpha1_peer_cr.yaml b/src/agent/fabric-operator/deploy/crds/fabric_v1alpha1_peer_cr.yaml index ff10243de..dd222639d 100755 --- a/src/agent/fabric-operator/deploy/crds/fabric_v1alpha1_peer_cr.yaml +++ b/src/agent/fabric-operator/deploy/crds/fabric_v1alpha1_peer_cr.yaml @@ -1,40 +1,54 @@ apiVersion: fabric.hyperledger.org/v1alpha1 kind: Peer metadata: - name: peer01 + name: peer001 spec: - # Add fields here - storageSize: "1Gi" - storageClass: "default" - image: "hyperledger/fabric-peer:1.4.1" - - # To specify resource limits for this Peer node, - # use kubernetes resource requirements spec - # resources: - # requests: - # memory: "32Mi" - # cpu: "200m" - # limits: - # memory: "1024mi" - # cpu: "250" - - # Add all the configurable peer parameters as - # name-value pairs - configParams: - - name: CORE_PEER_ADDRESSAUTODETECT - value: "true" - - name: CORE_PEER_NETWORKID - value: nid1 - - name: CORE_PEER_ID - value: org1peer1 - - name: CORE_PEER_ADDRESS - value: blockchain-org1peer1:30110 - - name: CORE_PEER_LISTENADDRESS - value: 0.0.0.0:30110 - - name: CORE_PEER_EVENTS_ADDRESS - value: 0.0.0.0:30111 - - name: CORE_PEER_GOSSIP_BOOTSTRAP - value: blockchain-org1peer1:30110 - - name: CORE_PEER_GOSSIP_ORGLEADER - value: "false" - + # If you have an set of certs that you like to use instead of + # generating a set by Fabric CA, you can specify as the following. + # Certificates and private keys have all to be base64 encoded as + # the values of the each item below. + #certs: + # tlsCerts: + # tlsPrivatekey: + # tlsCert: + # tlsRootcert: + # msp: + # adminCerts: + # caCerts: + # keyStore: + # signCerts: + # tlsCacerts: + nodeSpec: + # To specify resource limits for this Peer node, + # use kubernetes resource requirements spec + # resources: + # requests: + # memory: "32Mi" + # cpu: "200m" + # limits: + # memory: "1024mi" + # cpu: "250" + storageSize: "1Gi" + storageClass: "default" + image: "hyperledger/fabric-peer:1.4.1" + # Add all the configurable peer parameters as + # name-value pairs + configParams: + - name: CORE_PEER_ADDRESSAUTODETECT + value: "true" + - name: CORE_PEER_NETWORKID + value: nid1 + - name: CORE_PEER_ID + value: org1peer1 + - name: CORE_PEER_ADDRESS + value: blockchain-org1peer1:30110 + - name: CORE_PEER_LISTENADDRESS + value: 0.0.0.0:30110 + - name: CORE_PEER_EVENTS_ADDRESS + value: 0.0.0.0:30111 + - name: CORE_PEER_GOSSIP_BOOTSTRAP + value: blockchain-org1peer1:30110 + - name: CORE_PEER_GOSSIP_ORGLEADER + value: "false" + - name: CORE_PEER_TLS_ENABLED + value: "true" diff --git a/src/agent/fabric-operator/deploy/crds/fabric_v1alpha1_peer_crd.yaml b/src/agent/fabric-operator/deploy/crds/fabric_v1alpha1_peer_crd.yaml index 35411f140..d90e91c84 100644 --- a/src/agent/fabric-operator/deploy/crds/fabric_v1alpha1_peer_crd.yaml +++ b/src/agent/fabric-operator/deploy/crds/fabric_v1alpha1_peer_crd.yaml @@ -29,37 +29,95 @@ spec: type: object spec: properties: - configParams: - items: - properties: - name: - type: string - value: - type: string - required: - - name - - value - type: object - type: array - hosts: - items: - type: string - type: array - image: + certs: description: 'INSERT ADDITIONAL SPEC FIELDS - desired state of cluster Important: Run "operator-sdk generate k8s" to regenerate code after modifying this file Add custom validation using kubebuilder tags: https://book-v1.book.kubebuilder.io/beyond_basics/generating_crd.html' - type: string - resources: + properties: + msp: + properties: + adminCerts: + items: + type: string + type: array + caCerts: + items: + type: string + type: array + intermediateCerts: + items: + type: string + type: array + keyStore: + type: string + signCerts: + type: string + tlsCacerts: + items: + type: string + type: array + tlsIntermediatecerts: + items: + type: string + type: array + required: + - adminCerts + - caCerts + - keyStore + - signCerts + type: object + tlsCerts: + properties: + tlsCert: + type: string + tlsPrivatekey: + type: string + tlsRootcas: + items: + type: string + type: array + tlsRootcert: + type: string + type: object + required: + - msp + - tlsCerts + type: object + nodeSpec: + properties: + configParams: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + hosts: + items: + type: string + type: array + image: + description: 'INSERT ADDITIONAL SPEC FIELDS - desired state of cluster + Important: Run "operator-sdk generate k8s" to regenerate code + after modifying this file Add custom validation using kubebuilder + tags: https://book-v1.book.kubebuilder.io/beyond_basics/generating_crd.html' + type: string + resources: + type: object + storageClass: + type: string + storageSize: + type: string + required: + - image + - configParams type: object - storageClass: - type: string - storageSize: - type: string - required: - - image - - configParams type: object status: properties: diff --git a/src/agent/fabric-operator/go.mod b/src/agent/fabric-operator/go.mod index 3093c743a..71a75824c 100644 --- a/src/agent/fabric-operator/go.mod +++ b/src/agent/fabric-operator/go.mod @@ -1,13 +1,13 @@ module github.com/hyperledger/cello/src/agent/fabric-operator require ( - github.com/NYTimes/gziphandler v1.0.1 // indirect + github.com/go-openapi/spec v0.19.0 github.com/operator-framework/operator-sdk v0.9.1-0.20190806200632-6c7039c37324 github.com/spf13/pflag v1.0.3 k8s.io/api v0.0.0-20190612125737-db0771252981 k8s.io/apimachinery v0.0.0-20190612125636-6a5db36e93ad k8s.io/client-go v11.0.0+incompatible - k8s.io/kube-openapi v0.0.0-20190603182131-db7b694dc208 // indirect + k8s.io/kube-openapi v0.0.0-20190603182131-db7b694dc208 sigs.k8s.io/controller-runtime v0.1.12 sigs.k8s.io/controller-tools v0.1.10 ) @@ -28,3 +28,5 @@ replace ( ) replace github.com/operator-framework/operator-sdk => github.com/operator-framework/operator-sdk v0.9.0 + +go 1.13 diff --git a/src/agent/fabric-operator/pkg/apis/fabric/v1alpha1/helper.go b/src/agent/fabric-operator/pkg/apis/fabric/v1alpha1/helper.go index 7a3f1f601..b2e447561 100755 --- a/src/agent/fabric-operator/pkg/apis/fabric/v1alpha1/helper.go +++ b/src/agent/fabric-operator/pkg/apis/fabric/v1alpha1/helper.go @@ -9,6 +9,28 @@ import ( corev1 "k8s.io/api/core/v1" ) +// +k8s:openapi-gen=true +type Certs struct { + Msp *Msp `json:"msp"` + TLSCerts *TLSCerts `json:"tlsCerts"` +} + +type Msp struct { + AdminCerts []string `json:"adminCerts,required"` + CaCerts []string `json:"caCerts,required"` + IntermediateCerts []string `json:"intermediateCerts,omitempty"` + KeyStore string `json:"keyStore,required"` + SignCerts string `json:"signCerts,required"` + TLSCacerts []string `json:"tlsCacerts,omitempty"` + TLSIntermediatecerts []string `json:"tlsIntermediatecerts,omitempty"` +} + +type TLSCerts struct { + TLSPrivatekey string `json:"tlsPrivatekey,omitempty"` + TLSCert string `json:"tlsCert,omitempty"` + TLSRootcert string `json:"tlsRootcert,omitempty"` + TLSRootcas []string `json:"tlsRootcas,omitempty"` +} // +k8s:openapi-gen=true type NodeSpec struct { // INSERT ADDITIONAL SPEC FIELDS - desired state of cluster diff --git a/src/agent/fabric-operator/pkg/apis/fabric/v1alpha1/orderer_types.go b/src/agent/fabric-operator/pkg/apis/fabric/v1alpha1/orderer_types.go index 22b6f3d0f..c09547ae3 100755 --- a/src/agent/fabric-operator/pkg/apis/fabric/v1alpha1/orderer_types.go +++ b/src/agent/fabric-operator/pkg/apis/fabric/v1alpha1/orderer_types.go @@ -7,6 +7,17 @@ import ( // 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. + +// OrdererSpec defines the desired state of Orderer +// +k8s:openapi-gen=true +type OrdererSpec struct { + // INSERT ADDITIONAL SPEC FIELDS - desired state of cluster + // Important: Run "operator-sdk generate k8s" to regenerate code after modifying this file + // Add custom validation using kubebuilder tags: https://book-v1.book.kubebuilder.io/beyond_basics/generating_crd.html + Certs *Certs `json:"certs,omitempty"` + NodeSpec `json:"nodeSpec,omitempty"` +} + // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object // Orderer is the Schema for the orderers API @@ -16,7 +27,7 @@ type Orderer struct { metav1.TypeMeta `json:",inline"` metav1.ObjectMeta `json:"metadata,omitempty"` - Spec NodeSpec `json:"spec,omitempty"` + Spec OrdererSpec `json:"spec,omitempty"` Status NodeStatus `json:"status,omitempty"` } diff --git a/src/agent/fabric-operator/pkg/apis/fabric/v1alpha1/peer_types.go b/src/agent/fabric-operator/pkg/apis/fabric/v1alpha1/peer_types.go index 0ac5c5919..ee974cbb7 100755 --- a/src/agent/fabric-operator/pkg/apis/fabric/v1alpha1/peer_types.go +++ b/src/agent/fabric-operator/pkg/apis/fabric/v1alpha1/peer_types.go @@ -7,6 +7,17 @@ import ( // 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. + +// PeerSpec defines the desired state of Peer +// +k8s:openapi-gen=true +type PeerSpec struct { + // INSERT ADDITIONAL SPEC FIELDS - desired state of cluster + // Important: Run "operator-sdk generate k8s" to regenerate code after modifying this file + // Add custom validation using kubebuilder tags: https://book-v1.book.kubebuilder.io/beyond_basics/generating_crd.html + Certs *Certs `json:"certs,omitempty"` + NodeSpec `json:"nodeSpec,omitempty"` +} + // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object // Peer is the Schema for the peers API @@ -16,7 +27,7 @@ type Peer struct { metav1.TypeMeta `json:",inline"` metav1.ObjectMeta `json:"metadata,omitempty"` - Spec NodeSpec `json:"spec,omitempty"` + Spec PeerSpec `json:"spec,omitempty"` Status NodeStatus `json:"status,omitempty"` } diff --git a/src/agent/fabric-operator/pkg/apis/fabric/v1alpha1/zz_generated.deepcopy.go b/src/agent/fabric-operator/pkg/apis/fabric/v1alpha1/zz_generated.deepcopy.go index 4ed5c5ad0..6d37c3b59 100644 --- a/src/agent/fabric-operator/pkg/apis/fabric/v1alpha1/zz_generated.deepcopy.go +++ b/src/agent/fabric-operator/pkg/apis/fabric/v1alpha1/zz_generated.deepcopy.go @@ -107,6 +107,32 @@ func (in *CASpec) DeepCopy() *CASpec { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Certs) DeepCopyInto(out *Certs) { + *out = *in + if in.Msp != nil { + in, out := &in.Msp, &out.Msp + *out = new(Msp) + (*in).DeepCopyInto(*out) + } + if in.TLSCerts != nil { + in, out := &in.TLSCerts, &out.TLSCerts + *out = new(TLSCerts) + (*in).DeepCopyInto(*out) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Certs. +func (in *Certs) DeepCopy() *Certs { + if in == nil { + return nil + } + out := new(Certs) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ConfigParam) DeepCopyInto(out *ConfigParam) { *out = *in @@ -123,6 +149,47 @@ func (in *ConfigParam) DeepCopy() *ConfigParam { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Msp) DeepCopyInto(out *Msp) { + *out = *in + if in.AdminCerts != nil { + in, out := &in.AdminCerts, &out.AdminCerts + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.CaCerts != nil { + in, out := &in.CaCerts, &out.CaCerts + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.IntermediateCerts != nil { + in, out := &in.IntermediateCerts, &out.IntermediateCerts + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.TLSCacerts != nil { + in, out := &in.TLSCacerts, &out.TLSCacerts + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.TLSIntermediatecerts != nil { + in, out := &in.TLSIntermediatecerts, &out.TLSIntermediatecerts + *out = make([]string, len(*in)) + copy(*out, *in) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Msp. +func (in *Msp) DeepCopy() *Msp { + if in == nil { + return nil + } + out := new(Msp) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *NodeSpec) DeepCopyInto(out *NodeSpec) { *out = *in @@ -227,6 +294,28 @@ func (in *OrdererList) DeepCopyObject() runtime.Object { return nil } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *OrdererSpec) DeepCopyInto(out *OrdererSpec) { + *out = *in + if in.Certs != nil { + in, out := &in.Certs, &out.Certs + *out = new(Certs) + (*in).DeepCopyInto(*out) + } + in.NodeSpec.DeepCopyInto(&out.NodeSpec) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OrdererSpec. +func (in *OrdererSpec) DeepCopy() *OrdererSpec { + if in == nil { + return nil + } + out := new(OrdererSpec) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *Peer) DeepCopyInto(out *Peer) { *out = *in @@ -287,3 +376,46 @@ func (in *PeerList) DeepCopyObject() runtime.Object { } return nil } + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PeerSpec) DeepCopyInto(out *PeerSpec) { + *out = *in + if in.Certs != nil { + in, out := &in.Certs, &out.Certs + *out = new(Certs) + (*in).DeepCopyInto(*out) + } + in.NodeSpec.DeepCopyInto(&out.NodeSpec) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PeerSpec. +func (in *PeerSpec) DeepCopy() *PeerSpec { + if in == nil { + return nil + } + out := new(PeerSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TLSCerts) DeepCopyInto(out *TLSCerts) { + *out = *in + if in.TLSRootcas != nil { + in, out := &in.TLSRootcas, &out.TLSRootcas + *out = make([]string, len(*in)) + copy(*out, *in) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TLSCerts. +func (in *TLSCerts) DeepCopy() *TLSCerts { + if in == nil { + return nil + } + out := new(TLSCerts) + in.DeepCopyInto(out) + return out +} diff --git a/src/agent/fabric-operator/pkg/apis/fabric/v1alpha1/zz_generated.openapi.go b/src/agent/fabric-operator/pkg/apis/fabric/v1alpha1/zz_generated.openapi.go index b88a4636b..3e6dea547 100644 --- a/src/agent/fabric-operator/pkg/apis/fabric/v1alpha1/zz_generated.openapi.go +++ b/src/agent/fabric-operator/pkg/apis/fabric/v1alpha1/zz_generated.openapi.go @@ -1,4 +1,4 @@ -// +build ! +// +build !ignore_autogenerated // This file was autogenerated by openapi-gen. Do not edit it manually! @@ -11,14 +11,17 @@ import ( func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenAPIDefinition { return map[string]common.OpenAPIDefinition{ - "github.com/hyperledger/cello/src/agent/fabric-operator/pkg/apis/fabric/v1alpha1.CA": schema_pkg_apis_fabric_v1alpha1_CA(ref), - "github.com/hyperledger/cello/src/agent/fabric-operator/pkg/apis/fabric/v1alpha1.CACerts": schema_pkg_apis_fabric_v1alpha1_CACerts(ref), - "github.com/hyperledger/cello/src/agent/fabric-operator/pkg/apis/fabric/v1alpha1.CASpec": schema_pkg_apis_fabric_v1alpha1_CASpec(ref), - "github.com/hyperledger/cello/src/agent/fabric-operator/pkg/apis/fabric/v1alpha1.ConfigParam": schema_pkg_apis_fabric_v1alpha1_ConfigParam(ref), - "github.com/hyperledger/cello/src/agent/fabric-operator/pkg/apis/fabric/v1alpha1.NodeSpec": schema_pkg_apis_fabric_v1alpha1_NodeSpec(ref), - "github.com/hyperledger/cello/src/agent/fabric-operator/pkg/apis/fabric/v1alpha1.NodeStatus": schema_pkg_apis_fabric_v1alpha1_NodeStatus(ref), - "github.com/hyperledger/cello/src/agent/fabric-operator/pkg/apis/fabric/v1alpha1.Orderer": schema_pkg_apis_fabric_v1alpha1_Orderer(ref), - "github.com/hyperledger/cello/src/agent/fabric-operator/pkg/apis/fabric/v1alpha1.Peer": schema_pkg_apis_fabric_v1alpha1_Peer(ref), + "./pkg/apis/fabric/v1alpha1.CA": schema_pkg_apis_fabric_v1alpha1_CA(ref), + "./pkg/apis/fabric/v1alpha1.CACerts": schema_pkg_apis_fabric_v1alpha1_CACerts(ref), + "./pkg/apis/fabric/v1alpha1.CASpec": schema_pkg_apis_fabric_v1alpha1_CASpec(ref), + "./pkg/apis/fabric/v1alpha1.Certs": schema_pkg_apis_fabric_v1alpha1_Certs(ref), + "./pkg/apis/fabric/v1alpha1.ConfigParam": schema_pkg_apis_fabric_v1alpha1_ConfigParam(ref), + "./pkg/apis/fabric/v1alpha1.NodeSpec": schema_pkg_apis_fabric_v1alpha1_NodeSpec(ref), + "./pkg/apis/fabric/v1alpha1.NodeStatus": schema_pkg_apis_fabric_v1alpha1_NodeStatus(ref), + "./pkg/apis/fabric/v1alpha1.Orderer": schema_pkg_apis_fabric_v1alpha1_Orderer(ref), + "./pkg/apis/fabric/v1alpha1.OrdererSpec": schema_pkg_apis_fabric_v1alpha1_OrdererSpec(ref), + "./pkg/apis/fabric/v1alpha1.Peer": schema_pkg_apis_fabric_v1alpha1_Peer(ref), + "./pkg/apis/fabric/v1alpha1.PeerSpec": schema_pkg_apis_fabric_v1alpha1_PeerSpec(ref), } } @@ -49,19 +52,19 @@ func schema_pkg_apis_fabric_v1alpha1_CA(ref common.ReferenceCallback) common.Ope }, "spec": { SchemaProps: spec.SchemaProps{ - Ref: ref("github.com/hyperledger/cello/src/agent/fabric-operator/pkg/apis/fabric/v1alpha1.CASpec"), + Ref: ref("./pkg/apis/fabric/v1alpha1.CASpec"), }, }, "status": { SchemaProps: spec.SchemaProps{ - Ref: ref("github.com/hyperledger/cello/src/agent/fabric-operator/pkg/apis/fabric/v1alpha1.NodeStatus"), + Ref: ref("./pkg/apis/fabric/v1alpha1.NodeStatus"), }, }, }, }, }, Dependencies: []string{ - "github.com/hyperledger/cello/src/agent/fabric-operator/pkg/apis/fabric/v1alpha1.CASpec", "github.com/hyperledger/cello/src/agent/fabric-operator/pkg/apis/fabric/v1alpha1.NodeStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"}, + "./pkg/apis/fabric/v1alpha1.CASpec", "./pkg/apis/fabric/v1alpha1.NodeStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"}, } } @@ -123,12 +126,12 @@ func schema_pkg_apis_fabric_v1alpha1_CASpec(ref common.ReferenceCallback) common }, "certs": { SchemaProps: spec.SchemaProps{ - Ref: ref("github.com/hyperledger/cello/src/agent/fabric-operator/pkg/apis/fabric/v1alpha1.CACerts"), + Ref: ref("./pkg/apis/fabric/v1alpha1.CACerts"), }, }, "nodeSpec": { SchemaProps: spec.SchemaProps{ - Ref: ref("github.com/hyperledger/cello/src/agent/fabric-operator/pkg/apis/fabric/v1alpha1.NodeSpec"), + Ref: ref("./pkg/apis/fabric/v1alpha1.NodeSpec"), }, }, }, @@ -136,7 +139,31 @@ func schema_pkg_apis_fabric_v1alpha1_CASpec(ref common.ReferenceCallback) common }, }, Dependencies: []string{ - "github.com/hyperledger/cello/src/agent/fabric-operator/pkg/apis/fabric/v1alpha1.CACerts", "github.com/hyperledger/cello/src/agent/fabric-operator/pkg/apis/fabric/v1alpha1.NodeSpec"}, + "./pkg/apis/fabric/v1alpha1.CACerts", "./pkg/apis/fabric/v1alpha1.NodeSpec"}, + } +} + +func schema_pkg_apis_fabric_v1alpha1_Certs(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Properties: map[string]spec.Schema{ + "msp": { + SchemaProps: spec.SchemaProps{ + Ref: ref("./pkg/apis/fabric/v1alpha1.Msp"), + }, + }, + "tlsCerts": { + SchemaProps: spec.SchemaProps{ + Ref: ref("./pkg/apis/fabric/v1alpha1.TLSCerts"), + }, + }, + }, + Required: []string{"msp", "tlsCerts"}, + }, + }, + Dependencies: []string{ + "./pkg/apis/fabric/v1alpha1.Msp", "./pkg/apis/fabric/v1alpha1.TLSCerts"}, } } @@ -183,7 +210,7 @@ func schema_pkg_apis_fabric_v1alpha1_NodeSpec(ref common.ReferenceCallback) comm Items: &spec.SchemaOrArray{ Schema: &spec.Schema{ SchemaProps: spec.SchemaProps{ - Ref: ref("github.com/hyperledger/cello/src/agent/fabric-operator/pkg/apis/fabric/v1alpha1.ConfigParam"), + Ref: ref("./pkg/apis/fabric/v1alpha1.ConfigParam"), }, }, }, @@ -224,7 +251,7 @@ func schema_pkg_apis_fabric_v1alpha1_NodeSpec(ref common.ReferenceCallback) comm }, }, Dependencies: []string{ - "github.com/hyperledger/cello/src/agent/fabric-operator/pkg/apis/fabric/v1alpha1.ConfigParam", "k8s.io/api/core/v1.ResourceRequirements"}, + "./pkg/apis/fabric/v1alpha1.ConfigParam", "k8s.io/api/core/v1.ResourceRequirements"}, } } @@ -276,19 +303,44 @@ func schema_pkg_apis_fabric_v1alpha1_Orderer(ref common.ReferenceCallback) commo }, "spec": { SchemaProps: spec.SchemaProps{ - Ref: ref("github.com/hyperledger/cello/src/agent/fabric-operator/pkg/apis/fabric/v1alpha1.NodeSpec"), + Ref: ref("./pkg/apis/fabric/v1alpha1.OrdererSpec"), }, }, "status": { SchemaProps: spec.SchemaProps{ - Ref: ref("github.com/hyperledger/cello/src/agent/fabric-operator/pkg/apis/fabric/v1alpha1.NodeStatus"), + Ref: ref("./pkg/apis/fabric/v1alpha1.NodeStatus"), }, }, }, }, }, Dependencies: []string{ - "github.com/hyperledger/cello/src/agent/fabric-operator/pkg/apis/fabric/v1alpha1.NodeSpec", "github.com/hyperledger/cello/src/agent/fabric-operator/pkg/apis/fabric/v1alpha1.NodeStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"}, + "./pkg/apis/fabric/v1alpha1.NodeStatus", "./pkg/apis/fabric/v1alpha1.OrdererSpec", "k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"}, + } +} + +func schema_pkg_apis_fabric_v1alpha1_OrdererSpec(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "OrdererSpec defines the desired state of Orderer", + Properties: map[string]spec.Schema{ + "certs": { + SchemaProps: spec.SchemaProps{ + Description: "INSERT ADDITIONAL SPEC FIELDS - desired state of cluster Important: Run \"operator-sdk generate k8s\" to regenerate code after modifying this file Add custom validation using kubebuilder tags: https://book-v1.book.kubebuilder.io/beyond_basics/generating_crd.html", + Ref: ref("./pkg/apis/fabric/v1alpha1.Certs"), + }, + }, + "nodeSpec": { + SchemaProps: spec.SchemaProps{ + Ref: ref("./pkg/apis/fabric/v1alpha1.NodeSpec"), + }, + }, + }, + }, + }, + Dependencies: []string{ + "./pkg/apis/fabric/v1alpha1.Certs", "./pkg/apis/fabric/v1alpha1.NodeSpec"}, } } @@ -319,18 +371,43 @@ func schema_pkg_apis_fabric_v1alpha1_Peer(ref common.ReferenceCallback) common.O }, "spec": { SchemaProps: spec.SchemaProps{ - Ref: ref("github.com/hyperledger/cello/src/agent/fabric-operator/pkg/apis/fabric/v1alpha1.NodeSpec"), + Ref: ref("./pkg/apis/fabric/v1alpha1.PeerSpec"), }, }, "status": { SchemaProps: spec.SchemaProps{ - Ref: ref("github.com/hyperledger/cello/src/agent/fabric-operator/pkg/apis/fabric/v1alpha1.NodeStatus"), + Ref: ref("./pkg/apis/fabric/v1alpha1.NodeStatus"), + }, + }, + }, + }, + }, + Dependencies: []string{ + "./pkg/apis/fabric/v1alpha1.NodeStatus", "./pkg/apis/fabric/v1alpha1.PeerSpec", "k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"}, + } +} + +func schema_pkg_apis_fabric_v1alpha1_PeerSpec(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "PeerSpec defines the desired state of Peer", + Properties: map[string]spec.Schema{ + "certs": { + SchemaProps: spec.SchemaProps{ + Description: "INSERT ADDITIONAL SPEC FIELDS - desired state of cluster Important: Run \"operator-sdk generate k8s\" to regenerate code after modifying this file Add custom validation using kubebuilder tags: https://book-v1.book.kubebuilder.io/beyond_basics/generating_crd.html", + Ref: ref("./pkg/apis/fabric/v1alpha1.Certs"), + }, + }, + "nodeSpec": { + SchemaProps: spec.SchemaProps{ + Ref: ref("./pkg/apis/fabric/v1alpha1.NodeSpec"), }, }, }, }, }, Dependencies: []string{ - "github.com/hyperledger/cello/src/agent/fabric-operator/pkg/apis/fabric/v1alpha1.NodeSpec", "github.com/hyperledger/cello/src/agent/fabric-operator/pkg/apis/fabric/v1alpha1.NodeStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"}, + "./pkg/apis/fabric/v1alpha1.Certs", "./pkg/apis/fabric/v1alpha1.NodeSpec"}, } } diff --git a/src/agent/fabric-operator/pkg/controller/orderer/orderer_controller.go b/src/agent/fabric-operator/pkg/controller/orderer/orderer_controller.go old mode 100755 new mode 100644 index d624b6294..d3125d8ae --- a/src/agent/fabric-operator/pkg/controller/orderer/orderer_controller.go +++ b/src/agent/fabric-operator/pkg/controller/orderer/orderer_controller.go @@ -3,6 +3,7 @@ package orderer import ( "context" "strconv" + "strings" fabric "github.com/hyperledger/cello/src/agent/fabric-operator/pkg/apis/fabric" fabricv1alpha1 "github.com/hyperledger/cello/src/agent/fabric-operator/pkg/apis/fabric/v1alpha1" @@ -12,6 +13,7 @@ import ( "k8s.io/apimachinery/pkg/api/resource" "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/types" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/controller" "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" @@ -63,6 +65,15 @@ func add(mgr manager.Manager, r reconcile.Reconciler) error { return err } + // Watch for changes to secret that we create + err = c.Watch(&source.Kind{Type: &corev1.Secret{}}, &handler.EnqueueRequestForOwner{ + IsController: true, + OwnerType: &fabricv1alpha1.CA{}, + }) + if err != nil { + return err + } + // Watch for changes to services that we create err = c.Watch(&source.Kind{Type: &corev1.Service{}}, &handler.EnqueueRequestForOwner{ IsController: true, @@ -119,6 +130,23 @@ func (r *ReconcileOrderer) Reconcile(request reconcile.Request) (reconcile.Resul return reconcile.Result{}, err } + secret := &corev1.Secret{} + secretID := request.Name + "-secret" + foundSecret := &corev1.Secret{} + err = r.client.Get(context.TODO(), + types.NamespacedName{Name: secretID, Namespace: request.Namespace}, + foundSecret) + if err != nil && errors.IsNotFound(err) { + secret = r.newSecretForCR(instance, request) + err = r.client.Create(context.TODO(), secret) + if err != nil { + reqLogger.Error(err, "Failed to retrieve Fabric Peer secrets") + return reconcile.Result{}, err + } + // When we reach here, it means that we have created the secret successfully + // and ready to do more + } + foundService := &corev1.Service{} err = r.client.Get(context.TODO(), request.NamespacedName, foundService) if err != nil && errors.IsNotFound(err) { @@ -170,7 +198,7 @@ func (r *ReconcileOrderer) Reconcile(request reconcile.Request) (reconcile.Resul err = r.client.Get(context.TODO(), request.NamespacedName, foundSTS) if err != nil && errors.IsNotFound(err) { // Define a new StatefulSet object - sts := r.newSTSForCR(instance, request) + sts := r.newSTSForCR(secret, instance, request) reqLogger.Info("Creating a new set.", "StatefulSet.Namespace", sts.Namespace, "StatefulSet.Name", sts.Name) err = r.client.Create(context.TODO(), sts) @@ -187,6 +215,47 @@ func (r *ReconcileOrderer) Reconcile(request reconcile.Request) (reconcile.Resul return reconcile.Result{}, nil } +// newSecretForCR returns k8s secret with the name + "-secret" /namespace as the cr +func (r *ReconcileOrderer) newSecretForCR(cr *fabricv1alpha1.Orderer, request reconcile.Request) *corev1.Secret { + obj, _, _ := fabric.GetObjectFromTemplate("orderer/orderer_secret.yaml") + secret, ok := obj.(*corev1.Secret) + if !ok { + secret = nil + } else { + secret.Name = request.Name + "-secret" + secret.Namespace = request.Namespace + if cr.Spec.Certs != nil { + for i, adminCert := range cr.Spec.Certs.Msp.AdminCerts { + secret.Data["adminCert"+strconv.Itoa(i)] = []byte(adminCert) + } + for i, caCert := range cr.Spec.Certs.Msp.CaCerts { + secret.Data["caCert"+strconv.Itoa(i)] = []byte(caCert) + } + secret.Data["keyStore"] = []byte(cr.Spec.Certs.Msp.KeyStore) + secret.Data["signCerts"] = []byte(cr.Spec.Certs.Msp.SignCerts) + for i, tlsCacerts := range cr.Spec.Certs.Msp.TLSCacerts { + secret.Data["tlsCacerts"+strconv.Itoa(i)] = []byte(tlsCacerts) + } + value := "" + for _, param := range cr.Spec.ConfigParams { + if param.Name == "ORDERER_GENERAL_TLS_ENABLED" { + value = param.Value + break; + } + } + if value != "" && value == "true" && cr.Spec.Certs.TLSCerts != nil { + secret.Data["tlsPrivatekey"] = []byte(cr.Spec.Certs.TLSCerts.TLSPrivatekey) + secret.Data["tlsCert"] = []byte(cr.Spec.Certs.TLSCerts.TLSCert) + for i, tlsRootcas := range cr.Spec.Certs.TLSCerts.TLSRootcas { + secret.Data["tlsRootcas"+strconv.Itoa(i)] = []byte(tlsRootcas) + } + } + } + controllerutil.SetControllerReference(cr, secret, r.scheme) + } + return secret +} + // newServiceForCR returns a fabric Orderer service with the same name/namespace as the cr func (r *ReconcileOrderer) newServiceForCR(cr *fabricv1alpha1.Orderer, request reconcile.Request) *corev1.Service { obj, _, _ := fabric.GetObjectFromTemplate("orderer/orderer_service.yaml") @@ -204,7 +273,7 @@ func (r *ReconcileOrderer) newServiceForCR(cr *fabricv1alpha1.Orderer, request r } // newPodForCR returns a fabric Orderer statefulset with the same name/namespace as the cr -func (r *ReconcileOrderer) newSTSForCR(cr *fabricv1alpha1.Orderer, request reconcile.Request) *appsv1.StatefulSet { +func (r *ReconcileOrderer) newSTSForCR(secret *corev1.Secret, cr *fabricv1alpha1.Orderer, request reconcile.Request) *appsv1.StatefulSet { obj, _, err := fabric.GetObjectFromTemplate("orderer/orderer_statefulset.yaml") if err != nil { log.Error(err, "Failed to load statefulset.") @@ -222,14 +291,82 @@ func (r *ReconcileOrderer) newSTSForCR(cr *fabricv1alpha1.Orderer, request recon storageSize := fabric.GetDefault(cr.Spec.StorageSize, "5Gi").(string) sts.Spec.VolumeClaimTemplates[0].Spec.Resources.Requests["storage"] = resource.MustParse(storageSize) sts.Spec.Template.Labels["k8s-app"] = sts.Name - sts.Spec.Template.Spec.Containers[0].Image = - fabric.GetDefault(cr.Spec.Image, "hyperledger/fabric-orderer:1.4.1").(string) containerEnvs := []corev1.EnvVar{} for _, e := range cr.Spec.ConfigParams { containerEnvs = append(containerEnvs, corev1.EnvVar{ Name: e.Name, Value: e.Value, }) } + sts.Spec.Template.Spec.Containers[0].Image = + fabric.GetDefault(cr.Spec.Image, "hyperledger/fabric-orderer:1.4.1").(string) + + if secret != nil { + sts.Spec.Template.Spec.Volumes[0].VolumeSource.Secret.SecretName = request.Name + "-secret" + secretItems := []corev1.KeyToPath{} + + // Add MSP Certificates + for i, _ := range cr.Spec.Certs.Msp.AdminCerts { + secretName := "adminCert"+strconv.Itoa(i)+".pem" + secretItems = append(secretItems, corev1.KeyToPath{ + Key: secretName, Path: "/certs/msp/admincerts/" + secretName, + }) + } + + for i, _ := range cr.Spec.Certs.Msp.CaCerts { + secretName := "caCert"+strconv.Itoa(i)+".pem" + secretItems = append(secretItems, corev1.KeyToPath{ + Key: secretName, Path: "/certs/msp/cacerts/" + secretName, + }) + } + + secretItems = append(secretItems, + corev1.KeyToPath{Key: "keyStore", Path: "/certs/msp/keystore"}, + corev1.KeyToPath{Key: "signCerts", Path: "/certs/msp/signCerts.pem"}, + ) + + for i, _ := range cr.Spec.Certs.Msp.TLSCacerts { + secretName := "tlsCacerts"+strconv.Itoa(i)+".pem" + secretItems = append(secretItems, corev1.KeyToPath{ + Key: secretName, Path: "/certs/msp/tlscacerts/" + secretName, + }) + } + containerEnvs = append(containerEnvs, corev1.EnvVar{ + Name: "ORDERER_GENERAL_LOCALMSPDIR", Value: "/certs/msp/", + }) + + // Add tls certificates + value := "" + for _, param := range cr.Spec.ConfigParams { + if param.Name == "ORDERER_GENERAL_TLS_ENABLED" { + value = param.Value + break; + } + } + if value != "" && value == "true" && cr.Spec.Certs.TLSCerts != nil { + secretItems = append(secretItems, + corev1.KeyToPath{Key: "tlsPrivatekey", Path: "/certs/tls/server.key"}, + corev1.KeyToPath{Key: "tlsCert", Path: "/certs/tls/server.crt"}, + ) + + tlsRootcasList := []string{} + + for i, _ := range cr.Spec.Certs.TLSCerts.TLSRootcas { + secretName := "tlsRootcas"+strconv.Itoa(i)+".crt" + tlsRootcasList = append(tlsRootcasList, "/certs/tls/" + secretName) + secretItems = append(secretItems, corev1.KeyToPath{ + Key: secretName, Path: "/certs/msp/" + secretName, + }) + } + + containerEnvs = append(containerEnvs, + corev1.EnvVar{Name: "ORDERER_GENERAL_TLS_PRIVATEKEY", Value: "/certs/tls/server.key"}, + corev1.EnvVar{Name: "ORDERER_GENERAL_TLS_CERTIFICATE", Value: "/certs/tls/server.crt"}, + corev1.EnvVar{Name: "ORDERER_GENERAL_TLS_ROOTCAS", Value: "[" + strings.Join(tlsRootcasList, ",") + "]" }, + ) + } + + sts.Spec.Template.Spec.Volumes[0].VolumeSource.Secret.Items = secretItems + } sts.Spec.Template.Spec.Containers[0].Env = containerEnvs sts.Spec.Template.Spec.Containers[0].Resources = cr.Spec.Resources controllerutil.SetControllerReference(cr, sts, r.scheme) diff --git a/src/agent/fabric-operator/pkg/controller/peer/peer_controller.go b/src/agent/fabric-operator/pkg/controller/peer/peer_controller.go old mode 100755 new mode 100644 index d650282eb..74376174c --- a/src/agent/fabric-operator/pkg/controller/peer/peer_controller.go +++ b/src/agent/fabric-operator/pkg/controller/peer/peer_controller.go @@ -12,6 +12,7 @@ import ( "k8s.io/apimachinery/pkg/api/resource" "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/types" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/controller" "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" @@ -63,6 +64,15 @@ func add(mgr manager.Manager, r reconcile.Reconciler) error { return err } + // Watch for changes to secret that we create + err = c.Watch(&source.Kind{Type: &corev1.Secret{}}, &handler.EnqueueRequestForOwner{ + IsController: true, + OwnerType: &fabricv1alpha1.CA{}, + }) + if err != nil { + return err + } + // Watch for changes to services that we create err = c.Watch(&source.Kind{Type: &corev1.Service{}}, &handler.EnqueueRequestForOwner{ IsController: true, @@ -119,6 +129,23 @@ func (r *ReconcilePeer) Reconcile(request reconcile.Request) (reconcile.Result, return reconcile.Result{}, err } + secret := &corev1.Secret{} + secretID := request.Name + "-secret" + foundSecret := &corev1.Secret{} + err = r.client.Get(context.TODO(), + types.NamespacedName{Name: secretID, Namespace: request.Namespace}, + foundSecret) + if err != nil && errors.IsNotFound(err) { + secret = r.newSecretForCR(instance, request) + err = r.client.Create(context.TODO(), secret) + if err != nil { + reqLogger.Error(err, "Failed to retrieve Fabric Peer secrets") + return reconcile.Result{}, err + } + // When we reach here, it means that we have created the secret successfully + // and ready to do more + } + foundService := &corev1.Service{} err = r.client.Get(context.TODO(), request.NamespacedName, foundService) if err != nil && errors.IsNotFound(err) { @@ -170,7 +197,7 @@ func (r *ReconcilePeer) Reconcile(request reconcile.Request) (reconcile.Result, err = r.client.Get(context.TODO(), request.NamespacedName, foundSTS) if err != nil && errors.IsNotFound(err) { // Define a new StatefulSet object - sts := r.newSTSForCR(instance, request) + sts := r.newSTSForCR(secret, instance, request) reqLogger.Info("Creating a new set.", "StatefulSet.Namespace", sts.Namespace, "StatefulSet.Name", sts.Name) err = r.client.Create(context.TODO(), sts) @@ -187,6 +214,47 @@ func (r *ReconcilePeer) Reconcile(request reconcile.Request) (reconcile.Result, return reconcile.Result{}, nil } +// newSecretForCR returns k8s secret with the name + "-secret" /namespace as the cr +func (r *ReconcilePeer) newSecretForCR(cr *fabricv1alpha1.Peer, request reconcile.Request) *corev1.Secret { + obj, _, _ := fabric.GetObjectFromTemplate("peer/peer_secret.yaml") + secret, ok := obj.(*corev1.Secret) + if !ok { + secret = nil + } else { + secret.Name = request.Name + "-secret" + secret.Namespace = request.Namespace + if cr.Spec.Certs != nil { + // Add MSP certs as kubernetes secret + for i, adminCert := range cr.Spec.Certs.Msp.AdminCerts { + secret.Data["adminCert"+strconv.Itoa(i)] = []byte(adminCert) + } + for i, caCert := range cr.Spec.Certs.Msp.CaCerts { + secret.Data["caCert"+strconv.Itoa(i)] = []byte(caCert) + } + secret.Data["keyStore"] = []byte(cr.Spec.Certs.Msp.KeyStore) + secret.Data["signCerts"] = []byte(cr.Spec.Certs.Msp.SignCerts) + for i, tlsCacerts := range cr.Spec.Certs.Msp.TLSCacerts { + secret.Data["tlsCacerts"+strconv.Itoa(i)] = []byte(tlsCacerts) + } + // Add TLS certs as kubernetes secret + value := "" + for _, param := range cr.Spec.ConfigParams { + if param.Name == "CORE_PEER_TLS_ENABLED" { + value = param.Value + break; + } + } + if value != "" && value == "true" && cr.Spec.Certs.TLSCerts != nil { + secret.Data["tlsKey"] = []byte(cr.Spec.Certs.TLSCerts.TLSPrivatekey) + secret.Data["tlsCert"] = []byte(cr.Spec.Certs.TLSCerts.TLSCert) + secret.Data["tlsRootcert"] = []byte(cr.Spec.Certs.TLSCerts.TLSRootcert) + } + } + controllerutil.SetControllerReference(cr, secret, r.scheme) + } + return secret +} + // newServiceForCR returns a fabric Peer service with the same name/namespace as the cr func (r *ReconcilePeer) newServiceForCR(cr *fabricv1alpha1.Peer, request reconcile.Request) *corev1.Service { obj, _, _ := fabric.GetObjectFromTemplate("peer/peer_service.yaml") @@ -204,7 +272,7 @@ func (r *ReconcilePeer) newServiceForCR(cr *fabricv1alpha1.Peer, request reconci } // newPodForCR returns a fabric Peer statefulset with the same name/namespace as the cr -func (r *ReconcilePeer) newSTSForCR(cr *fabricv1alpha1.Peer, request reconcile.Request) *appsv1.StatefulSet { +func (r *ReconcilePeer) newSTSForCR(secret *corev1.Secret, cr *fabricv1alpha1.Peer, request reconcile.Request) *appsv1.StatefulSet { obj, _, err := fabric.GetObjectFromTemplate("peer/peer_statefulset.yaml") if err != nil { log.Error(err, "Failed to load statefulset.") @@ -222,14 +290,73 @@ func (r *ReconcilePeer) newSTSForCR(cr *fabricv1alpha1.Peer, request reconcile.R storageSize := fabric.GetDefault(cr.Spec.StorageSize, "5Gi").(string) sts.Spec.VolumeClaimTemplates[0].Spec.Resources.Requests["storage"] = resource.MustParse(storageSize) sts.Spec.Template.Labels["k8s-app"] = sts.Name - sts.Spec.Template.Spec.Containers[0].Image = - fabric.GetDefault(cr.Spec.Image, "hyperledger/fabric-peer:1.4.1").(string) containerEnvs := []corev1.EnvVar{} for _, e := range cr.Spec.ConfigParams { containerEnvs = append(containerEnvs, corev1.EnvVar{ Name: e.Name, Value: e.Value, }) } + sts.Spec.Template.Spec.Containers[0].Image = + fabric.GetDefault(cr.Spec.Image, "hyperledger/fabric-peer:1.4.1").(string) + + if secret != nil { + sts.Spec.Template.Spec.Volumes[0].VolumeSource.Secret.SecretName = request.Name + "-secret" + secretItems := []corev1.KeyToPath{} + + // Add MSP certificates + for i, _ := range cr.Spec.Certs.Msp.AdminCerts { + secretName := "adminCert"+strconv.Itoa(i)+".pem" + secretItems = append(secretItems, corev1.KeyToPath{ + Key: secretName, Path: "/certs/msp/admincerts/" + secretName, + }) + } + + for i, _ := range cr.Spec.Certs.Msp.CaCerts { + secretName := "caCert"+strconv.Itoa(i)+".pem" + secretItems = append(secretItems, corev1.KeyToPath{ + Key: secretName, Path: "/certs/msp/cacerts/" + secretName, + }) + } + + secretItems = append(secretItems, + corev1.KeyToPath{Key: "keyStore", Path: "/certs/msp/keystore"}, + corev1.KeyToPath{Key: "signCerts", Path: "/certs/msp/signCerts.pem"}, + ) + + for i, _ := range cr.Spec.Certs.Msp.TLSCacerts { + secretName := "tlsCacerts"+strconv.Itoa(i)+".pem" + secretItems = append(secretItems, corev1.KeyToPath{ + Key: secretName, Path: "/certs/msp/tlscacerts/" + secretName, + }) + } + containerEnvs = append(containerEnvs, + corev1.EnvVar{Name: "CORE_PEER_MSPCONFIGPATH", Value: "/certs/msp/"}, + ) + + // Add tls certificates + value := "" + for _, param := range cr.Spec.ConfigParams { + if param.Name == "CORE_PEER_TLS_ENABLED" { + value = param.Value + break; + } + } + if value != "" && value == "true" && cr.Spec.Certs.TLSCerts != nil { + secretItems = append(secretItems, + corev1.KeyToPath{Key: "tlsKey", Path: "/certs/tls/server.key"}, + corev1.KeyToPath{Key: "tlsCert", Path: "/certs/tls/server.crt"}, + corev1.KeyToPath{Key: "tlsRootcert", Path: "/certs/tls/ca.crt"}, + ) + containerEnvs = append(containerEnvs, + corev1.EnvVar{Name: "CORE_PEER_TLS_CERT_FILE", Value: "/certs/tls/server.key"}, + corev1.EnvVar{Name: "CORE_PEER_TLS_KEY_FILE", Value: "/certs/tls/server.crt"}, + corev1.EnvVar{Name: "CORE_PEER_TLS_ROOTCERT_FILE", Value: "/certs/tls/ca.crt"}, + ) + } + + sts.Spec.Template.Spec.Volumes[0].VolumeSource.Secret.Items = secretItems + } + sts.Spec.Template.Spec.Containers[0].Env = containerEnvs sts.Spec.Template.Spec.Containers[0].Resources = cr.Spec.Resources controllerutil.SetControllerReference(cr, sts, r.scheme)