From 27a6bc2f31a86928309d8f56b03c414b782da172 Mon Sep 17 00:00:00 2001 From: Manank Patni Date: Wed, 14 Aug 2019 00:34:27 +0530 Subject: [PATCH] [CE-673] Add support of Peer/Orderer to operator This adds logic for Peer and Orderer node similarly to the CA node. Signed-off-by: Manank Patni Change-Id: Ib2e5570802828e4149978c65952a4d0e6d41ad3c --- .../templates/orderer/orderer_service.json | 13 ++ .../orderer/orderer_statefulset.json | 49 +++++ .../bin/templates/peer/peer_service.json | 13 ++ .../bin/templates/peer/peer_statefulset.json | 50 +++++ .../crds/fabric_v1alpha1_orderer_cr.yaml | 31 +++ .../crds/fabric_v1alpha1_orderer_crd.yaml | 66 ++++++ .../deploy/crds/fabric_v1alpha1_peer_cr.yaml | 29 +++ .../deploy/crds/fabric_v1alpha1_peer_crd.yaml | 66 ++++++ src/agent/fabric-operator/deploy/role.yaml | 2 + src/agent/fabric-operator/go.sum | 9 + .../fabric-operator/pkg/apis/fabric/utils.go | 15 ++ .../pkg/apis/fabric/v1alpha1/orderer_types.go | 43 ++++ .../pkg/apis/fabric/v1alpha1/peer_types.go | 43 ++++ .../fabric/v1alpha1/zz_generated.deepcopy.go | 154 +++++++++++++ .../fabric/v1alpha1/zz_generated.openapi.go | 126 ++++++++++- .../pkg/controller/add_orderer.go | 10 + .../pkg/controller/add_peer.go | 10 + .../controller/orderer/orderer_controller.go | 204 ++++++++++++++++++ .../pkg/controller/peer/peer_controller.go | 204 ++++++++++++++++++ 19 files changed, 1131 insertions(+), 6 deletions(-) create mode 100644 src/agent/fabric-operator/build/bin/templates/orderer/orderer_service.json create mode 100644 src/agent/fabric-operator/build/bin/templates/orderer/orderer_statefulset.json create mode 100644 src/agent/fabric-operator/build/bin/templates/peer/peer_service.json create mode 100644 src/agent/fabric-operator/build/bin/templates/peer/peer_statefulset.json create mode 100644 src/agent/fabric-operator/deploy/crds/fabric_v1alpha1_orderer_cr.yaml create mode 100644 src/agent/fabric-operator/deploy/crds/fabric_v1alpha1_orderer_crd.yaml create mode 100644 src/agent/fabric-operator/deploy/crds/fabric_v1alpha1_peer_cr.yaml create mode 100644 src/agent/fabric-operator/deploy/crds/fabric_v1alpha1_peer_crd.yaml create mode 100644 src/agent/fabric-operator/pkg/apis/fabric/v1alpha1/orderer_types.go create mode 100644 src/agent/fabric-operator/pkg/apis/fabric/v1alpha1/peer_types.go create mode 100644 src/agent/fabric-operator/pkg/controller/add_orderer.go create mode 100644 src/agent/fabric-operator/pkg/controller/add_peer.go create mode 100644 src/agent/fabric-operator/pkg/controller/orderer/orderer_controller.go create mode 100644 src/agent/fabric-operator/pkg/controller/peer/peer_controller.go diff --git a/src/agent/fabric-operator/build/bin/templates/orderer/orderer_service.json b/src/agent/fabric-operator/build/bin/templates/orderer/orderer_service.json new file mode 100644 index 000000000..532da5465 --- /dev/null +++ b/src/agent/fabric-operator/build/bin/templates/orderer/orderer_service.json @@ -0,0 +1,13 @@ +kind: Service +apiVersion: v1 +metadata: + labels: + k8s-app: "" + name: "" +spec: + selector: + k8s-app: "" + type: NodePort + ports: + - name: ordererport + port: 7054 diff --git a/src/agent/fabric-operator/build/bin/templates/orderer/orderer_statefulset.json b/src/agent/fabric-operator/build/bin/templates/orderer/orderer_statefulset.json new file mode 100644 index 000000000..d398c6efb --- /dev/null +++ b/src/agent/fabric-operator/build/bin/templates/orderer/orderer_statefulset.json @@ -0,0 +1,49 @@ +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: "" +spec: + serviceName: "" + selector: + matchLabels: + k8s-app: "" + type: orderer + volumeClaimTemplates: + - metadata: + name: ordererstorage + spec: + accessModes: [ "ReadWriteOnce" ] + storageClassName: "default" + resources: + requests: + storage: "1Gi" + template: + metadata: + labels: + k8s-app: "" + type: "orderer" + component: "orderer" + spec: + volumes: + - name: orderercerts + secret: + secretName: orderercerts + - name: toolset + configMap: + name: fabric-configuration-toolset + containers: + - name: orderer + image: "" + imagePullPolicy: Always + env: + - { name: "ORDERER_CFG_PATH", value: "/etc/hyperledger/" } + - { name: "ORDERER_GENERAL_LEDGERTYPE", value: "file" } + - { name: "ORDERER_FILELEDGER_LOCATION", value: "/etc/hyperledger/ledger/orderer" } + - { name: "ORDERER_GENERAL_LOGLEVEL", value: "debug" } + 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_service.json b/src/agent/fabric-operator/build/bin/templates/peer/peer_service.json new file mode 100644 index 000000000..be7d0617f --- /dev/null +++ b/src/agent/fabric-operator/build/bin/templates/peer/peer_service.json @@ -0,0 +1,13 @@ +kind: Service +apiVersion: v1 +metadata: + labels: + k8s-app: "" + name: "" +spec: + selector: + k8s-app: "" + type: NodePort + ports: + - name: peerport + port: 7054 diff --git a/src/agent/fabric-operator/build/bin/templates/peer/peer_statefulset.json b/src/agent/fabric-operator/build/bin/templates/peer/peer_statefulset.json new file mode 100644 index 000000000..4b6c4da87 --- /dev/null +++ b/src/agent/fabric-operator/build/bin/templates/peer/peer_statefulset.json @@ -0,0 +1,50 @@ +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: "" +spec: + serviceName: "" + selector: + matchLabels: + k8s-app: "" + type: peer + replicas: 1 + volumeClaimTemplates: + - metadata: + name: peerstorage + spec: + accessModes: [ "ReadWriteOnce" ] + storageClassName: "default" + resources: + requests: + storage: "1Gi" + template: + metadata: + labels: + k8s-app: "" + type: "peer" + component: "peer" + spec: + volumes: + - name: peercerts + secret: + secretName: peercerts + - name: toolset + configMap: + name: fabric-configuration-toolset + containers: + - name: peer + image: "" + imagePullPolicy: Always + env: + - { name: "CORE_PEER_ID", value: "org1peer1" } + - { name: "CORE_PEER_COMMITTER_ENABLED", value: "true" } + - { name: "CORE_VM_ENDPOINT", value: "tcp://docker:2375" } + - { name: "CORE_LOGGING_PEER", value: "debug" } + 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_orderer_cr.yaml b/src/agent/fabric-operator/deploy/crds/fabric_v1alpha1_orderer_cr.yaml new file mode 100644 index 000000000..8df505cb6 --- /dev/null +++ b/src/agent/fabric-operator/deploy/crds/fabric_v1alpha1_orderer_cr.yaml @@ -0,0 +1,31 @@ +apiVersion: fabric.hyperledger.org/v1alpha1 +kind: Orderer +metadata: + name: orderer00 +spec: + 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 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 new file mode 100644 index 000000000..21c09024f --- /dev/null +++ b/src/agent/fabric-operator/deploy/crds/fabric_v1alpha1_orderer_crd.yaml @@ -0,0 +1,66 @@ +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: orderers.fabric.hyperledger.org +spec: + group: fabric.hyperledger.org + names: + kind: Orderer + listKind: OrdererList + plural: orderers + singular: orderer + scope: Namespaced + subresources: + status: {} + validation: + openAPIV3Schema: + 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/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/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + properties: + configParams: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + image: + type: string + storageClass: + type: string + storageSize: + 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 + required: + - storageSize + - storageClass + - image + - configParams + type: object + status: + type: object + version: v1alpha1 + versions: + - name: v1alpha1 + served: true + storage: true 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 new file mode 100644 index 000000000..e04fbe46e --- /dev/null +++ b/src/agent/fabric-operator/deploy/crds/fabric_v1alpha1_peer_cr.yaml @@ -0,0 +1,29 @@ +apiVersion: fabric.hyperledger.org/v1alpha1 +kind: Peer +metadata: + name: peer01 +spec: + # Add fields here + 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" + 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 new file mode 100644 index 000000000..dbaff92d6 --- /dev/null +++ b/src/agent/fabric-operator/deploy/crds/fabric_v1alpha1_peer_crd.yaml @@ -0,0 +1,66 @@ +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: peers.fabric.hyperledger.org +spec: + group: fabric.hyperledger.org + names: + kind: Peer + listKind: PeerList + plural: peers + singular: peer + scope: Namespaced + subresources: + status: {} + validation: + openAPIV3Schema: + 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/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/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + properties: + configParams: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + image: + type: string + storageClass: + type: string + storageSize: + 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 + required: + - storageSize + - storageClass + - image + - configParams + type: object + status: + type: object + version: v1alpha1 + versions: + - name: v1alpha1 + served: true + storage: true diff --git a/src/agent/fabric-operator/deploy/role.yaml b/src/agent/fabric-operator/deploy/role.yaml index 8305cd944..e7c6ea457 100644 --- a/src/agent/fabric-operator/deploy/role.yaml +++ b/src/agent/fabric-operator/deploy/role.yaml @@ -56,5 +56,7 @@ rules: - fabric.hyperledger.org resources: - '*' + - peers + - orderers verbs: - '*' diff --git a/src/agent/fabric-operator/go.sum b/src/agent/fabric-operator/go.sum index 547073ec9..8429be883 100644 --- a/src/agent/fabric-operator/go.sum +++ b/src/agent/fabric-operator/go.sum @@ -91,6 +91,7 @@ github.com/fatih/camelcase v1.0.0/go.mod h1:yN2Sb0lFhZJUdVvtELVWefmrXpuZESvPmqwo github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= github.com/globalsign/mgo v0.0.0-20180905125535-1ca0a4f7cbcb/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= @@ -198,8 +199,10 @@ github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ github.com/hashicorp/golang-lru v0.5.1 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/huandu/xstrings v1.2.0/go.mod h1:DvyZB1rfVYsBIigL8HwpZgxHwXozlTgGqn63UyNX5k4= +github.com/hyperledger/cello v0.9.0 h1:0LrLnps21YaV72ZrtNZlmt44eNAap8UdpXLwKazAmhE= github.com/iancoleman/strcase v0.0.0-20180726023541-3605ed457bf7/go.mod h1:SK73tn/9oHe+/Y0h39VT4UCxmurVJkR5NA7kMEAOgSE= github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/imdario/mergo v0.3.6/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= @@ -253,9 +256,11 @@ github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRW github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.7.0 h1:WSHQ+IS43OoUrWtD1/bbclrwK8TTH5hzp+umCiuxHgs= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v1.4.2-0.20180831124310-ae19f1b56d53/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= +github.com/onsi/gomega v1.4.3 h1:RE1xgDvH7imwFD45h+u2SgIfERHlS2yNG4DObb5BSKU= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= github.com/openshift/origin v0.0.0-20160503220234-8f127d736703/go.mod h1:0Rox5r9C8aQn6j1oAOQ0c1uC86mYbUFObzjBRvUKHII= @@ -282,6 +287,7 @@ github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= @@ -334,6 +340,7 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v0.0.0-20151208002404-e3a8ff8ce365/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA= github.com/technosophos/moniker v0.0.0-20180509230615-a5dbd03a2245/go.mod h1:O1c8HleITsZqzNZDjSNzirUGsMT0oGu9LhHKoJrqO+A= @@ -473,6 +480,7 @@ gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLks gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/inf.v0 v0.9.0/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= @@ -481,6 +489,7 @@ gopkg.in/natefinch/lumberjack.v2 v2.0.0-20170531160350-a96e63847dc3/go.mod h1:l0 gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= gopkg.in/square/go-jose.v2 v2.3.0/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/src/agent/fabric-operator/pkg/apis/fabric/utils.go b/src/agent/fabric-operator/pkg/apis/fabric/utils.go index a28cb47fd..86e5f3c2f 100755 --- a/src/agent/fabric-operator/pkg/apis/fabric/utils.go +++ b/src/agent/fabric-operator/pkg/apis/fabric/utils.go @@ -98,3 +98,18 @@ func CheckAndCreateConfigMap(client client.Client, request reconcile.Request) er } return nil } + +type NodeSpec 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 + StorageSize string `json:"storageSize"` + StorageClass string `json:"storageClass"` + Image string `json:"image"` + ConfigParams []*ConfigParam `json:"configParams"` +} + +type ConfigParam struct { + Name string `json:"name"` + Value string `json:"value"` +} \ No newline at end of file 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 new file mode 100644 index 000000000..b62626ff7 --- /dev/null +++ b/src/agent/fabric-operator/pkg/apis/fabric/v1alpha1/orderer_types.go @@ -0,0 +1,43 @@ +package v1alpha1 + +import ( + fabric "github.com/hyperledger/cello/src/agent/fabric-operator/pkg/apis/fabric" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN! +// NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized. + +// OrdererStatus defines the observed state of Orderer +// +k8s:openapi-gen=true +type OrdererStatus struct { + // INSERT ADDITIONAL STATUS FIELD - define observed 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 +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// Orderer is the Schema for the orderers API +// +k8s:openapi-gen=true +// +kubebuilder:subresource:status +type Orderer struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec fabric.NodeSpec `json:"spec,omitempty"` + Status OrdererStatus `json:"status,omitempty"` +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// OrdererList contains a list of Orderer +type OrdererList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []Orderer `json:"items"` +} + +func init() { + SchemeBuilder.Register(&Orderer{}, &OrdererList{}) +} 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 new file mode 100644 index 000000000..a6d21d95f --- /dev/null +++ b/src/agent/fabric-operator/pkg/apis/fabric/v1alpha1/peer_types.go @@ -0,0 +1,43 @@ +package v1alpha1 + +import ( + fabric "github.com/hyperledger/cello/src/agent/fabric-operator/pkg/apis/fabric" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN! +// NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized. + +// PeerStatus defines the observed state of Peer +// +k8s:openapi-gen=true +type PeerStatus struct { + // INSERT ADDITIONAL STATUS FIELD - define observed 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 +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// Peer is the Schema for the peers API +// +k8s:openapi-gen=true +// +kubebuilder:subresource:status +type Peer struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec fabric.NodeSpec `json:"spec,omitempty"` + Status PeerStatus `json:"status,omitempty"` +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// PeerList contains a list of Peer +type PeerList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []Peer `json:"items"` +} + +func init() { + SchemeBuilder.Register(&Peer{}, &PeerList{}) +} 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 95b42f89a..88e0808e8 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 @@ -100,3 +100,157 @@ func (in *CAStatus) DeepCopy() *CAStatus { in.DeepCopyInto(out) return out } + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Orderer) DeepCopyInto(out *Orderer) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + out.Status = in.Status + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Orderer. +func (in *Orderer) DeepCopy() *Orderer { + if in == nil { + return nil + } + out := new(Orderer) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *Orderer) 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 *OrdererList) DeepCopyInto(out *OrdererList) { + *out = *in + out.TypeMeta = in.TypeMeta + out.ListMeta = in.ListMeta + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]Orderer, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OrdererList. +func (in *OrdererList) DeepCopy() *OrdererList { + if in == nil { + return nil + } + out := new(OrdererList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *OrdererList) 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 *OrdererStatus) DeepCopyInto(out *OrdererStatus) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OrdererStatus. +func (in *OrdererStatus) DeepCopy() *OrdererStatus { + if in == nil { + return nil + } + out := new(OrdererStatus) + 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 + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + out.Status = in.Status + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Peer. +func (in *Peer) DeepCopy() *Peer { + if in == nil { + return nil + } + out := new(Peer) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *Peer) 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 *PeerList) DeepCopyInto(out *PeerList) { + *out = *in + out.TypeMeta = in.TypeMeta + out.ListMeta = in.ListMeta + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]Peer, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PeerList. +func (in *PeerList) DeepCopy() *PeerList { + if in == nil { + return nil + } + out := new(PeerList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *PeerList) 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 *PeerStatus) DeepCopyInto(out *PeerStatus) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PeerStatus. +func (in *PeerStatus) DeepCopy() *PeerStatus { + if in == nil { + return nil + } + out := new(PeerStatus) + 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 785c66fe5..9f3a88716 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 @@ -11,9 +11,13 @@ 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.CASpec": schema_pkg_apis_fabric_v1alpha1_CASpec(ref), - "github.com/hyperledger/cello/src/agent/fabric-operator/pkg/apis/fabric/v1alpha1.CAStatus": schema_pkg_apis_fabric_v1alpha1_CAStatus(ref), + "./pkg/apis/fabric/v1alpha1.CA": schema_pkg_apis_fabric_v1alpha1_CA(ref), + "./pkg/apis/fabric/v1alpha1.CASpec": schema_pkg_apis_fabric_v1alpha1_CASpec(ref), + "./pkg/apis/fabric/v1alpha1.CAStatus": schema_pkg_apis_fabric_v1alpha1_CAStatus(ref), + "./pkg/apis/fabric/v1alpha1.Orderer": schema_pkg_apis_fabric_v1alpha1_Orderer(ref), + "./pkg/apis/fabric/v1alpha1.OrdererStatus": schema_pkg_apis_fabric_v1alpha1_OrdererStatus(ref), + "./pkg/apis/fabric/v1alpha1.Peer": schema_pkg_apis_fabric_v1alpha1_Peer(ref), + "./pkg/apis/fabric/v1alpha1.PeerStatus": schema_pkg_apis_fabric_v1alpha1_PeerStatus(ref), } } @@ -44,19 +48,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.CAStatus"), + Ref: ref("./pkg/apis/fabric/v1alpha1.CAStatus"), }, }, }, }, }, 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.CAStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"}, + "./pkg/apis/fabric/v1alpha1.CASpec", "./pkg/apis/fabric/v1alpha1.CAStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"}, } } @@ -119,3 +123,113 @@ func schema_pkg_apis_fabric_v1alpha1_CAStatus(ref common.ReferenceCallback) comm Dependencies: []string{}, } } + +func schema_pkg_apis_fabric_v1alpha1_Orderer(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "Orderer is the Schema for the orderers API", + Properties: map[string]spec.Schema{ + "kind": { + SchemaProps: spec.SchemaProps{ + 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/api-conventions.md#types-kinds", + Type: []string{"string"}, + Format: "", + }, + }, + "apiVersion": { + SchemaProps: spec.SchemaProps{ + 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/api-conventions.md#resources", + Type: []string{"string"}, + Format: "", + }, + }, + "metadata": { + SchemaProps: spec.SchemaProps{ + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"), + }, + }, + "spec": { + SchemaProps: spec.SchemaProps{ + Ref: ref("github.com/hyperledger/cello/src/agent/fabric-operator/pkg/apis/fabric.NodeSpec"), + }, + }, + "status": { + SchemaProps: spec.SchemaProps{ + Ref: ref("./pkg/apis/fabric/v1alpha1.OrdererStatus"), + }, + }, + }, + }, + }, + Dependencies: []string{ + "./pkg/apis/fabric/v1alpha1.OrdererStatus", "github.com/hyperledger/cello/src/agent/fabric-operator/pkg/apis/fabric.NodeSpec", "k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"}, + } +} + +func schema_pkg_apis_fabric_v1alpha1_OrdererStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "OrdererStatus defines the observed state of Orderer", + Properties: map[string]spec.Schema{}, + }, + }, + Dependencies: []string{}, + } +} + +func schema_pkg_apis_fabric_v1alpha1_Peer(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "Peer is the Schema for the peers API", + Properties: map[string]spec.Schema{ + "kind": { + SchemaProps: spec.SchemaProps{ + 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/api-conventions.md#types-kinds", + Type: []string{"string"}, + Format: "", + }, + }, + "apiVersion": { + SchemaProps: spec.SchemaProps{ + 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/api-conventions.md#resources", + Type: []string{"string"}, + Format: "", + }, + }, + "metadata": { + SchemaProps: spec.SchemaProps{ + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"), + }, + }, + "spec": { + SchemaProps: spec.SchemaProps{ + Ref: ref("github.com/hyperledger/cello/src/agent/fabric-operator/pkg/apis/fabric.NodeSpec"), + }, + }, + "status": { + SchemaProps: spec.SchemaProps{ + Ref: ref("./pkg/apis/fabric/v1alpha1.PeerStatus"), + }, + }, + }, + }, + }, + Dependencies: []string{ + "./pkg/apis/fabric/v1alpha1.PeerStatus", "github.com/hyperledger/cello/src/agent/fabric-operator/pkg/apis/fabric.NodeSpec", "k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"}, + } +} + +func schema_pkg_apis_fabric_v1alpha1_PeerStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "PeerStatus defines the observed state of Peer", + Properties: map[string]spec.Schema{}, + }, + }, + Dependencies: []string{}, + } +} diff --git a/src/agent/fabric-operator/pkg/controller/add_orderer.go b/src/agent/fabric-operator/pkg/controller/add_orderer.go new file mode 100644 index 000000000..358d5cfda --- /dev/null +++ b/src/agent/fabric-operator/pkg/controller/add_orderer.go @@ -0,0 +1,10 @@ +package controller + +import ( + "github.com/hyperledger/cello/src/agent/fabric-operator/pkg/controller/orderer" +) + +func init() { + // AddToManagerFuncs is a list of functions to create controllers and add them to a manager. + AddToManagerFuncs = append(AddToManagerFuncs, orderer.Add) +} diff --git a/src/agent/fabric-operator/pkg/controller/add_peer.go b/src/agent/fabric-operator/pkg/controller/add_peer.go new file mode 100644 index 000000000..5a3b6e165 --- /dev/null +++ b/src/agent/fabric-operator/pkg/controller/add_peer.go @@ -0,0 +1,10 @@ +package controller + +import ( + "github.com/hyperledger/cello/src/agent/fabric-operator/pkg/controller/peer" +) + +func init() { + // AddToManagerFuncs is a list of functions to create controllers and add them to a manager. + AddToManagerFuncs = append(AddToManagerFuncs, peer.Add) +} diff --git a/src/agent/fabric-operator/pkg/controller/orderer/orderer_controller.go b/src/agent/fabric-operator/pkg/controller/orderer/orderer_controller.go new file mode 100644 index 000000000..3e23e6656 --- /dev/null +++ b/src/agent/fabric-operator/pkg/controller/orderer/orderer_controller.go @@ -0,0 +1,204 @@ +package orderer + +import ( + "context" + + 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" + appsv1 "k8s.io/api/apps/v1" + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/errors" + + //metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/api/resource" + "k8s.io/apimachinery/pkg/runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/controller" + "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" + "sigs.k8s.io/controller-runtime/pkg/handler" + "sigs.k8s.io/controller-runtime/pkg/manager" + "sigs.k8s.io/controller-runtime/pkg/reconcile" + logf "sigs.k8s.io/controller-runtime/pkg/runtime/log" + "sigs.k8s.io/controller-runtime/pkg/source" +) + +var log = logf.Log.WithName("controller_orderer") + +/** +* USER ACTION REQUIRED: This is a scaffold file intended for the user to modify with their own Controller +* business logic. Delete these comments after modifying this file.* + */ + +// Add creates a new Orderer Controller and adds it to the Manager. The Manager will set fields on the Controller +// and Start it when the Manager is Started. +func Add(mgr manager.Manager) error { + return add(mgr, newReconciler(mgr)) +} + +// newReconciler returns a new reconcile.Reconciler +func newReconciler(mgr manager.Manager) reconcile.Reconciler { + return &ReconcileOrderer{client: mgr.GetClient(), scheme: mgr.GetScheme()} +} + +// add adds a new Controller to mgr with r as the reconcile.Reconciler +func add(mgr manager.Manager, r reconcile.Reconciler) error { + // Create a new controller + c, err := controller.New("orderer-controller", mgr, controller.Options{Reconciler: r}) + if err != nil { + return err + } + + // Watch for changes to primary resource Orderer + err = c.Watch(&source.Kind{Type: &fabricv1alpha1.Orderer{}}, &handler.EnqueueRequestForObject{}) + if err != nil { + return err + } + + // TODO(user): Modify this to be the types you create that are owned by the primary resource + // Watch for changes to secondary resource Pods and requeue the owner Orderer + err = c.Watch(&source.Kind{Type: &corev1.Pod{}}, &handler.EnqueueRequestForOwner{ + IsController: true, + OwnerType: &fabricv1alpha1.Orderer{}, + }) + if err != nil { + return err + } + + return nil +} + +// blank assignment to verify that ReconcileOrderer implements reconcile.Reconciler +var _ reconcile.Reconciler = &ReconcileOrderer{} + +// ReconcileOrderer reconciles a Orderer object +type ReconcileOrderer struct { + // This client, initialized using mgr.Client() above, is a split client + // that reads objects from the cache and writes to the apiserver + client client.Client + scheme *runtime.Scheme +} + +// Reconcile reads that state of the cluster for a Orderer object and makes changes based on the state read +// and what is in the Orderer.Spec +// TODO(user): Modify this Reconcile function to implement your Controller logic. This example creates +// a Pod as an example +// Note: +// The Controller will requeue the Request to be processed again if the returned error is non-nil or +// Result.Requeue is true, otherwise upon completion it will remove the work from the queue. +func (r *ReconcileOrderer) Reconcile(request reconcile.Request) (reconcile.Result, error) { + reqLogger := log.WithValues("Request.Namespace", request.Namespace, "Request.Name", request.Name) + reqLogger.Info("Reconciling Orderer") + + err := fabric.CheckAndCreateConfigMap(r.client, request) + if err != nil { + reqLogger.Error(err, "Failed to find Fabric configuration, can not continue!") + return reconcile.Result{}, err + } + + // Fetch the Orderer instance + instance := &fabricv1alpha1.Orderer{} + err := r.client.Get(context.TODO(), request.NamespacedName, instance) + if err != nil { + if errors.IsNotFound(err) { + // Request object not found, could have been deleted after reconcile request. + // Owned objects are automatically garbage collected. For additional cleanup logic use finalizers. + // Return and don't requeue + reqLogger.Info("Orderer resource not found. Ignoring since object must be deleted.") + return reconcile.Result{}, nil + } + // Error reading the object - requeue the request. + reqLogger.Error(err, "Failed to get Orderer.") + return reconcile.Result{}, err + } + + foundService := &corev1.Service{} + err = r.client.Get(context.TODO(), request.NamespacedName, foundService) + if err != nil && errors.IsNotFound(err) { + // Define a new Service object + service := r.newServiceForCR(instance, request) + reqLogger.Info("Creating a new service.", "Service.Namespace", service.Namespace, + "Service.Name", service.Name) + err = r.client.Create(context.TODO(), service) + if err != nil { + reqLogger.Error(err, "Failed to create new service for Orderer.", "Service.Namespace", + service.Namespace, "Service.Name", service.Name) + return reconcile.Result{}, err + } + } else if err != nil { + reqLogger.Error(err, "Failed to get Orderer service.") + return reconcile.Result{}, err + } + + foundSTS := &appsv1.StatefulSet{} + 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) + reqLogger.Info("Creating a new set.", "StatefulSet.Namespace", sts.Namespace, + "StatefulSet.Name", sts.Name) + err = r.client.Create(context.TODO(), sts) + if err != nil { + reqLogger.Error(err, "Failed to create new statefulset for Orderer.", "StatefulSet.Namespace", + sts.Namespace, "StatefulSet.Name", sts.Name) + return reconcile.Result{}, err + } + } else if err != nil { + reqLogger.Error(err, "Failed to get Orderer StatefulSet.") + return reconcile.Result{}, err + } + + return reconcile.Result{}, nil +} + +// 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.json") + service, ok := obj.(*corev1.Service) + if !ok { + service = nil + } else { + service.Name = request.Name + service.Namespace = request.Namespace + service.Labels["k8s-app"] = service.Name + service.Spec.Selector["k8s-app"] = service.Name + controllerutil.SetControllerReference(cr, service, r.scheme) + } + return service +} + +// 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 { + obj, _, err := fabric.GetObjectFromTemplate("orderer/orderer_statefulset.json") + if err != nil { + log.Error(err, "Failed to load statefulset.") + } + sts, ok := obj.(*appsv1.StatefulSet) + if !ok { + sts = nil + } else { + sts.Name = request.Name + sts.Namespace = request.Namespace + sts.Spec.ServiceName = sts.Name + sts.Spec.Selector.MatchLabels["k8s-app"] = sts.Name + storageClassName := fabric.GetDefault(cr.Spec.StorageClass, "default").(string) + sts.Spec.VolumeClaimTemplates[0].Spec.StorageClassName = &storageClassName + 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 { + envName := e.Name + envValue := e.Value + env := corev1.EnvVar{ + Name: envName, + Value: envValue, + } + containerEnvs = append(containerEnvs, env) + } + sts.Spec.Template.Spec.Containers[0].Env = containerEnvs + controllerutil.SetControllerReference(cr, sts, r.scheme) + } + return sts +} diff --git a/src/agent/fabric-operator/pkg/controller/peer/peer_controller.go b/src/agent/fabric-operator/pkg/controller/peer/peer_controller.go new file mode 100644 index 000000000..bcdd65764 --- /dev/null +++ b/src/agent/fabric-operator/pkg/controller/peer/peer_controller.go @@ -0,0 +1,204 @@ +e package peer + +import ( + "context" + + 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" + appsv1 "k8s.io/api/apps/v1" + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/errors" + + //metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/api/resource" + "k8s.io/apimachinery/pkg/runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/controller" + "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" + "sigs.k8s.io/controller-runtime/pkg/handler" + "sigs.k8s.io/controller-runtime/pkg/manager" + "sigs.k8s.io/controller-runtime/pkg/reconcile" + logf "sigs.k8s.io/controller-runtime/pkg/runtime/log" + "sigs.k8s.io/controller-runtime/pkg/source" +) + +var log = logf.Log.WithName("controller_peer") + +/** +* USER ACTION REQUIRED: This is a scaffold file intended for the user to modify with their own Controller +* business logic. Delete these comments after modifying this file.* + */ + +// Add creates a new Peer Controller and adds it to the Manager. The Manager will set fields on the Controller +// and Start it when the Manager is Started. +func Add(mgr manager.Manager) error { + return add(mgr, newReconciler(mgr)) +} + +// newReconciler returns a new reconcile.Reconciler +func newReconciler(mgr manager.Manager) reconcile.Reconciler { + return &ReconcilePeer{client: mgr.GetClient(), scheme: mgr.GetScheme()} +} + +// add adds a new Controller to mgr with r as the reconcile.Reconciler +func add(mgr manager.Manager, r reconcile.Reconciler) error { + // Create a new controller + c, err := controller.New("peer-controller", mgr, controller.Options{Reconciler: r}) + if err != nil { + return err + } + + // Watch for changes to primary resource Peer + err = c.Watch(&source.Kind{Type: &fabricv1alpha1.Peer{}}, &handler.EnqueueRequestForObject{}) + if err != nil { + return err + } + + // TODO(user): Modify this to be the types you create that are owned by the primary resource + // Watch for changes to secondary resource Pods and requeue the owner Peer + err = c.Watch(&source.Kind{Type: &corev1.Pod{}}, &handler.EnqueueRequestForOwner{ + IsController: true, + OwnerType: &fabricv1alpha1.Peer{}, + }) + if err != nil { + return err + } + + return nil +} + +// blank assignment to verify that ReconcilePeer implements reconcile.Reconciler +var _ reconcile.Reconciler = &ReconcilePeer{} + +// ReconcilePeer reconciles a Peer object +type ReconcilePeer struct { + // This client, initialized using mgr.Client() above, is a split client + // that reads objects from the cache and writes to the apiserver + client client.Client + scheme *runtime.Scheme +} + +// Reconcile reads that state of the cluster for a Peer object and makes changes based on the state read +// and what is in the Peer.Spec +// TODO(user): Modify this Reconcile function to implement your Controller logic. This example creates +// a Pod as an example +// Note: +// The Controller will requeue the Request to be processed again if the returned error is non-nil or +// Result.Requeue is true, otherwise upon completion it will remove the work from the queue. +func (r *ReconcilePeer) Reconcile(request reconcile.Request) (reconcile.Result, error) { + reqLogger := log.WithValues("Request.Namespace", request.Namespace, "Request.Name", request.Name) + reqLogger.Info("Reconciling Peer") + + err := fabric.CheckAndCreateConfigMap(r.client, request) + if err != nil { + reqLogger.Error(err, "Failed to find Fabric configuration, can not continue!") + return reconcile.Result{}, err + } + + // Fetch the Peer instance + instance := &fabricv1alpha1.Peer{} + err := r.client.Get(context.TODO(), request.NamespacedName, instance) + if err != nil { + if errors.IsNotFound(err) { + // Request object not found, could have been deleted after reconcile request. + // Owned objects are automatically garbage collected. For additional cleanup logic use finalizers. + // Return and don't requeue + reqLogger.Info("Peer resource not found. Ignoring since object must be deleted.") + return reconcile.Result{}, nil + } + // Error reading the object - requeue the request. + reqLogger.Error(err, "Failed to get Peer.") + return reconcile.Result{}, err + } + + foundService := &corev1.Service{} + err = r.client.Get(context.TODO(), request.NamespacedName, foundService) + if err != nil && errors.IsNotFound(err) { + // Define a new Service object + service := r.newServiceForCR(instance, request) + reqLogger.Info("Creating a new service.", "Service.Namespace", service.Namespace, + "Service.Name", service.Name) + err = r.client.Create(context.TODO(), service) + if err != nil { + reqLogger.Error(err, "Failed to create new service for Peer.", "Service.Namespace", + service.Namespace, "Service.Name", service.Name) + return reconcile.Result{}, err + } + } else if err != nil { + reqLogger.Error(err, "Failed to get Peer service.") + return reconcile.Result{}, err + } + + foundSTS := &appsv1.StatefulSet{} + 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) + reqLogger.Info("Creating a new set.", "StatefulSet.Namespace", sts.Namespace, + "StatefulSet.Name", sts.Name) + err = r.client.Create(context.TODO(), sts) + if err != nil { + reqLogger.Error(err, "Failed to create new statefulset for Peer.", "StatefulSet.Namespace", + sts.Namespace, "StatefulSet.Name", sts.Name) + return reconcile.Result{}, err + } + } else if err != nil { + reqLogger.Error(err, "Failed to get Peer StatefulSet.") + return reconcile.Result{}, err + } + + return reconcile.Result{}, nil +} + +// 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.json") + service, ok := obj.(*corev1.Service) + if !ok { + service = nil + } else { + service.Name = request.Name + service.Namespace = request.Namespace + service.Labels["k8s-app"] = service.Name + service.Spec.Selector["k8s-app"] = service.Name + controllerutil.SetControllerReference(cr, service, r.scheme) + } + return service +} + +// 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 { + obj, _, err := fabric.GetObjectFromTemplate("peer/peer_statefulset.json") + if err != nil { + log.Error(err, "Failed to load statefulset.") + } + sts, ok := obj.(*appsv1.StatefulSet) + if !ok { + sts = nil + } else { + sts.Name = request.Name + sts.Namespace = request.Namespace + sts.Spec.ServiceName = sts.Name + sts.Spec.Selector.MatchLabels["k8s-app"] = sts.Name + storageClassName := fabric.GetDefault(cr.Spec.StorageClass, "default").(string) + sts.Spec.VolumeClaimTemplates[0].Spec.StorageClassName = &storageClassName + 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 { + envName := e.Name + envValue := e.Value + env := corev1.EnvVar{ + Name: envName, + Value: envValue, + } + containerEnvs = append(containerEnvs, env) + } + sts.Spec.Template.Spec.Containers[0].Env = containerEnvs + controllerutil.SetControllerReference(cr, sts, r.scheme) + } + return sts +}