diff --git a/deploy/crds/cluster.seaweedfs.com_seaweedfsclusters_crd.yaml b/deploy/crds/cluster.seaweedfs.com_seaweedfsclusters_crd.yaml new file mode 100644 index 0000000..2df6d62 --- /dev/null +++ b/deploy/crds/cluster.seaweedfs.com_seaweedfsclusters_crd.yaml @@ -0,0 +1,120 @@ +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: seaweedfsclusters.cluster.seaweedfs.com +spec: + group: cluster.seaweedfs.com + names: + kind: SeaweedfsCluster + listKind: SeaweedfsClusterList + plural: seaweedfsclusters + singular: seaweedfscluster + scope: Namespaced + subresources: + status: {} + validation: + openAPIV3Schema: + description: SeaweedfsCluster is the Schema for the seaweedfsclusters API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/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: + description: SeaweedfsClusterSpec defines the desired state of SeaweedfsCluster + properties: + filer: + description: SeaweedfsFilerSpec defines the desired state of filer server + in cluster + properties: + dir_list_limit: + description: DirListLimit limit sub dir listing size, default 100000 + format: int32 + type: integer + disable_dir_listing: + description: DisableDirListing turn off directory listing + type: boolean + max_mb: + description: MaxMB split files larger than the limit, default 32 + format: int32 + type: integer + port: + description: Port filer server http listen port + format: int32 + type: integer + replicas: + description: Replicas a size of filer replications + format: int32 + type: integer + type: object + master: + description: SeaweedfsMasterSpec defines the desired state of master + server in cluster + properties: + default_replication: + description: DefaultReplication set the data replication policy + in volumes. default "000" + type: string + disable_http: + description: DisableHTTP if disable http proto, only gRPC operations + are allowed. GRPC port is http port + 10000 + type: boolean + port: + description: Port set master server http api service port. default + is 9333 Master servers also use it identify each other. + format: int32 + type: integer + replication_size: + description: Replicas a size of a raft cluster. The master servers + are coordinated by Raft protocol, to elect a leader. + format: int32 + type: integer + type: object + version: + type: string + volumes: + items: + description: SeaweedfsVolumeSpec defines the desired state of volume + servers in cluster + properties: + compaction_mbps: + description: CompactionMbps limit background compaction or copying + speed in mega bytes per second + format: int32 + type: integer + data_center: + description: DataCenter current volume server's data center name + type: string + max: + description: Max set the maximum numbers of volumes management + by this server. Each volume is a 30G size file in under layer + filesystem. Default is 7 + format: int32 + type: integer + port: + description: Port volume server api http listen port + format: int32 + type: integer + rack: + description: Rack current volume server's rack name + type: string + type: object + type: array + type: object + status: + description: SeaweedfsClusterStatus defines the observed state of SeaweedfsCluster + type: object + type: object + version: v1alpha1 + versions: + - name: v1alpha1 + served: true + storage: true diff --git a/deploy/crds/cluster.seaweedfs.com_v1alpha1_seaweedfscluster_cr.yaml b/deploy/crds/cluster.seaweedfs.com_v1alpha1_seaweedfscluster_cr.yaml new file mode 100644 index 0000000..c0d81bd --- /dev/null +++ b/deploy/crds/cluster.seaweedfs.com_v1alpha1_seaweedfscluster_cr.yaml @@ -0,0 +1,7 @@ +apiVersion: cluster.seaweedfs.com/v1alpha1 +kind: SeaweedfsCluster +metadata: + name: example-seaweedfscluster +spec: + # Add fields here + size: 3 diff --git a/deploy/role.yaml b/deploy/role.yaml index 1a739ef..10d2f84 100644 --- a/deploy/role.yaml +++ b/deploy/role.yaml @@ -1,6 +1,7 @@ -kind: Role apiVersion: rbac.authorization.k8s.io/v1 +kind: Role metadata: + creationTimestamp: null name: seaweedfs-operator rules: - apiGroups: @@ -15,7 +16,7 @@ rules: - configmaps - secrets verbs: - - "*" + - '*' - apiGroups: - apps resources: @@ -24,22 +25,22 @@ rules: - replicasets - statefulsets verbs: - - "*" + - '*' - apiGroups: - monitoring.coreos.com resources: - servicemonitors verbs: - - "get" - - "create" + - get + - create - apiGroups: - apps - resources: - - deployments/finalizers resourceNames: - seaweedfs-operator + resources: + - deployments/finalizers verbs: - - "update" + - update - apiGroups: - "" resources: @@ -52,3 +53,10 @@ rules: - replicasets verbs: - get + - apiGroups: + - cluster.seaweedfs.com + resources: + - '*' + - seaweedfsclusters + verbs: + - '*' diff --git a/go.mod b/go.mod index 4d1a5e7..4401f0d 100644 --- a/go.mod +++ b/go.mod @@ -1,11 +1,13 @@ module github.com/seaweedfs/seaweedfs-operator require ( + github.com/go-openapi/spec v0.17.2 github.com/operator-framework/operator-sdk v0.11.1-0.20191027213559-041ec5463883 github.com/spf13/pflag v1.0.3 k8s.io/api v0.0.0-20190918155943-95b840bb6a1f k8s.io/apimachinery v0.0.0-20190913080033-27d36303b655 k8s.io/client-go v11.0.1-0.20190409021438-1a26190bd76a+incompatible + k8s.io/kube-openapi v0.0.0-20190401085232-94e1e7b7574c sigs.k8s.io/controller-runtime v0.2.0 ) diff --git a/go.sum b/go.sum index d5e1887..6b8d9a2 100644 --- a/go.sum +++ b/go.sum @@ -114,6 +114,7 @@ github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5Kwzbycv github.com/fatih/structtag v1.0.0/go.mod h1:IKitwq45uXL/yqi5mYghiD3w9H6eTOvI9vnk8tXMphA= github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= +github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/gernest/wow v0.1.0/go.mod h1:dEPabJRi5BneI1Nev1VWo0ZlcTWibHWp43qxKms4elY= github.com/getsentry/raven-go v0.1.2/go.mod h1:KungGk8q33+aIAZUIVWZDr2OfAEBsO49PX4NzFV5kcQ= @@ -168,6 +169,7 @@ github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7a github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.1 h1:/s5zKNz0uPFCZ5hddgPdo2TK2TVrUNMn0OOX8/aZMTE= github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20180513044358-24b0969c4cb7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20180924190550-6f2cf27854a4/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -184,6 +186,7 @@ github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8l github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= @@ -249,6 +252,7 @@ github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= +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/iancoleman/strcase v0.0.0-20180726023541-3605ed457bf7/go.mod h1:SK73tn/9oHe+/Y0h39VT4UCxmurVJkR5NA7kMEAOgSE= @@ -283,9 +287,11 @@ github.com/konsorten/go-windows-terminal-sequences v0.0.0-20180402223658-b729f26 github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348/go.mod h1:B69LEHPfb2qLo0BaaOLcbitczOKLWTsrBG9LczfCD4k= github.com/leanovate/gopter v0.2.4/go.mod h1:gNcbPWNEWRe4lm+bycKqxUYoH5uoVje5SkOJ3uoLer8= @@ -342,10 +348,12 @@ github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn github.com/olekukonko/tablewriter v0.0.1/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.8.0 h1:VkHVNpR4iVnU8XQR6DBm8BqYjN7CRzw+xKUbVVbbW9w= github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/gomega v1.4.2-0.20180831124310-ae19f1b56d53/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v1.4.2/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.5.0 h1:izbySO9zDPmjJ8rDjLvkA2zJHIo+HkYXHnf7eN7SSyo= github.com/onsi/gomega v1.5.0/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= @@ -380,6 +388,7 @@ github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 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 v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= @@ -454,6 +463,7 @@ github.com/stevvooe/resumable v0.0.0-20180830230917-22b14a53ba50/go.mod h1:1pdIZ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/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= @@ -596,6 +606,7 @@ google.golang.org/api v0.3.2/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMt google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.4.0 h1:/wp5JvzpHIxhs/dumFmF7BXTf3Z+dd4uXta4kVyO508= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= @@ -614,6 +625,7 @@ google.golang.org/grpc v1.19.1/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZi gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= 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= @@ -628,6 +640,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/urfave/cli.v1 v1.20.0/go.mod h1:vuBzUtMdQeixQj8LVd+/98pzhxNGQoyuPBlsXHOQNO0= gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= @@ -642,6 +655,7 @@ honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= k8s.io/api v0.0.0-20190409021203-6e4e0e4f393b h1:aBGgKJUM9Hk/3AE8WaZIApnTxG35kbuQba2w+SXqezo= k8s.io/api v0.0.0-20190409021203-6e4e0e4f393b/go.mod h1:iuAfoD4hCxJ8Onx9kaTIt30j7jUFS00AXQi6QMi99vA= +k8s.io/apiextensions-apiserver v0.0.0-20190409022649-727a075fdec8 h1:q1Qvjzs/iEdXF6A1a8H3AKVFDzJNcJn3nXMs6R6qFtA= k8s.io/apiextensions-apiserver v0.0.0-20190409022649-727a075fdec8/go.mod h1:IxkesAMoaCRoLrPJdZNZUQp9NfZnzqaVzLhb2VEQzXE= k8s.io/apimachinery v0.0.0-20190404173353-6a84e37a896d h1:Jmdtdt1ZnoGfWWIIik61Z7nKYgO3J+swQJtPYsP9wHA= k8s.io/apimachinery v0.0.0-20190404173353-6a84e37a896d/go.mod h1:ccL7Eh7zubPUSh9A3USN90/OzHNSVN6zxzde07TDCL0= @@ -684,6 +698,7 @@ sigs.k8s.io/controller-runtime v0.2.0 h1:5gL30PXOisGZl+Osi4CmLhvMUj77BO3wJeouKF2 sigs.k8s.io/controller-runtime v0.2.0/go.mod h1:ZHqrRDZi3f6BzONcvlUxkqCKgwasGk5FZrnSv9TVZF4= sigs.k8s.io/controller-tools v0.2.0/go.mod h1:8t/X+FVWvk6TaBcsa+UKUBbn7GMtvyBKX30SGl4em6Y= sigs.k8s.io/kustomize v2.0.3+incompatible/go.mod h1:MkjgH3RdOWrievjo6c9T245dYlB5QeXV4WCbnt/PEpU= +sigs.k8s.io/testing_frameworks v0.1.1 h1:cP2l8fkA3O9vekpy5Ks8mmA0NW/F7yBdXf8brkWhVrs= sigs.k8s.io/testing_frameworks v0.1.1/go.mod h1:VVBKrHmJ6Ekkfz284YKhQePcdycOzNH9qL6ht1zEr/U= sigs.k8s.io/yaml v1.1.0 h1:4A07+ZFc2wgJwo8YNlQpr1rVlgUDlxXHhPJciaPY5gs= sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= diff --git a/pkg/apis/addtoscheme_cluster_v1alpha1.go b/pkg/apis/addtoscheme_cluster_v1alpha1.go new file mode 100644 index 0000000..059681a --- /dev/null +++ b/pkg/apis/addtoscheme_cluster_v1alpha1.go @@ -0,0 +1,10 @@ +package apis + +import ( + "github.com/seaweedfs/seaweedfs-operator/pkg/apis/cluster/v1alpha1" +) + +func init() { + // Register the types with the Scheme so the components can map objects to GroupVersionKinds and back + AddToSchemes = append(AddToSchemes, v1alpha1.SchemeBuilder.AddToScheme) +} diff --git a/pkg/apis/cluster/group.go b/pkg/apis/cluster/group.go new file mode 100644 index 0000000..1f66bd5 --- /dev/null +++ b/pkg/apis/cluster/group.go @@ -0,0 +1,6 @@ +// Package cluster contains cluster API versions. +// +// This file ensures Go source parsers acknowledge the cluster package +// and any child packages. It can be removed if any other Go source files are +// added to this package. +package cluster diff --git a/pkg/apis/cluster/v1alpha1/doc.go b/pkg/apis/cluster/v1alpha1/doc.go new file mode 100644 index 0000000..e215543 --- /dev/null +++ b/pkg/apis/cluster/v1alpha1/doc.go @@ -0,0 +1,4 @@ +// Package v1alpha1 contains API Schema definitions for the cluster v1alpha1 API group +// +k8s:deepcopy-gen=package,register +// +groupName=cluster.seaweedfs.com +package v1alpha1 diff --git a/pkg/apis/cluster/v1alpha1/register.go b/pkg/apis/cluster/v1alpha1/register.go new file mode 100644 index 0000000..f227338 --- /dev/null +++ b/pkg/apis/cluster/v1alpha1/register.go @@ -0,0 +1,19 @@ +// NOTE: Boilerplate only. Ignore this file. + +// Package v1alpha1 contains API Schema definitions for the cluster v1alpha1 API group +// +k8s:deepcopy-gen=package,register +// +groupName=cluster.seaweedfs.com +package v1alpha1 + +import ( + "k8s.io/apimachinery/pkg/runtime/schema" + "sigs.k8s.io/controller-runtime/pkg/scheme" +) + +var ( + // SchemeGroupVersion is group version used to register these objects + SchemeGroupVersion = schema.GroupVersion{Group: "cluster.seaweedfs.com", Version: "v1alpha1"} + + // SchemeBuilder is used to add go types to the GroupVersionKind scheme + SchemeBuilder = &scheme.Builder{GroupVersion: SchemeGroupVersion} +) diff --git a/pkg/apis/cluster/v1alpha1/seaweedfscluster_types.go b/pkg/apis/cluster/v1alpha1/seaweedfscluster_types.go new file mode 100644 index 0000000..2625de6 --- /dev/null +++ b/pkg/apis/cluster/v1alpha1/seaweedfscluster_types.go @@ -0,0 +1,96 @@ +package v1alpha1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// SeaweedfsClusterSpec defines the desired state of SeaweedfsCluster +// +k8s:openapi-gen=true +type SeaweedfsClusterSpec struct { + Version string `json:"version,omitempty"` + Master SeaweedfsMasterSpec `json:"master,omitempty"` + Volumes []SeaweedfsVolumeSpec `json:"volumes,omitempty"` + Filer SeaweedfsFilerSpec `json:"filer,omitempty"` +} + +// SeaweedfsMasterSpec defines the desired state of master server in cluster +// +k8s:openapi-gen=true +type SeaweedfsMasterSpec struct { + // Replicas a size of a raft cluster. + // The master servers are coordinated by Raft protocol, to elect a leader. + Replicas int32 `json:"replication_size,omitempty"` + // Port set master server http api service port. default is 9333 + // Master servers also use it identify each other. + Port int32 `json:"port,omitempty"` + // DisableHTTP if disable http proto, only gRPC operations are allowed. + // GRPC port is http port + 10000 + DisableHTTP bool `json:"disable_http,omitempty"` + // DefaultReplication set the data replication policy in volumes. default "000" + DefaultReplication string `json:"default_replication,omitempty"` +} + +// SeaweedfsVolumeSpec defines the desired state of volume servers in cluster +// +k8s:openapi-gen=true +type SeaweedfsVolumeSpec struct { + // Max set the maximum numbers of volumes management by this server. + // Each volume is a 30G size file in under layer filesystem. Default is 7 + Max int32 `json:"max,omitempty"` + // CompactionMbps limit background compaction or copying speed in mega bytes per second + CompactionMbps int32 `json:"compaction_mbps,omitempty"` + //Rack current volume server's rack name + Rack string `json:"rack,omitempty"` + // DataCenter current volume server's data center name + DataCenter string `json:"data_center,omitempty"` + // Port volume server api http listen port + Port int32 `json:"port,omitempty"` +} + +// SeaweedfsFilerSpec defines the desired state of filer server in cluster +// +k8s:openapi-gen=true +type SeaweedfsFilerSpec struct { + // Replicas a size of filer replications + Replicas int32 `json:"replicas,omitempty"` + // DirListLimit limit sub dir listing size, default 100000 + DirListLimit int32 `json:"dir_list_limit,omitempty"` + // DisableDirListing turn off directory listing + DisableDirListing bool `json:"disable_dir_listing,omitempty"` + // MaxMB split files larger than the limit, default 32 + MaxMB int32 `json:"max_mb,omitempty"` + // Port filer server http listen port + Port int32 `json:"port,omitempty"` +} + +// SeaweedfsClusterStatus defines the observed state of SeaweedfsCluster +// +k8s:openapi-gen=true +type SeaweedfsClusterStatus 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 + +// SeaweedfsCluster is the Schema for the seaweedfsclusters API +// +k8s:openapi-gen=true +// +kubebuilder:subresource:status +// +kubebuilder:resource:path=seaweedfsclusters,scope=Namespaced +type SeaweedfsCluster struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec SeaweedfsClusterSpec `json:"spec,omitempty"` + Status SeaweedfsClusterStatus `json:"status,omitempty"` +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// SeaweedfsClusterList contains a list of SeaweedfsCluster +type SeaweedfsClusterList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []SeaweedfsCluster `json:"items"` +} + +func init() { + SchemeBuilder.Register(&SeaweedfsCluster{}, &SeaweedfsClusterList{}) +} diff --git a/pkg/apis/cluster/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/cluster/v1alpha1/zz_generated.deepcopy.go new file mode 100644 index 0000000..ac3f5e8 --- /dev/null +++ b/pkg/apis/cluster/v1alpha1/zz_generated.deepcopy.go @@ -0,0 +1,157 @@ +// +build !ignore_autogenerated + +// Code generated by operator-sdk. DO NOT EDIT. + +package v1alpha1 + +import ( + runtime "k8s.io/apimachinery/pkg/runtime" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SeaweedfsCluster) DeepCopyInto(out *SeaweedfsCluster) { + *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 SeaweedfsCluster. +func (in *SeaweedfsCluster) DeepCopy() *SeaweedfsCluster { + if in == nil { + return nil + } + out := new(SeaweedfsCluster) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *SeaweedfsCluster) 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 *SeaweedfsClusterList) DeepCopyInto(out *SeaweedfsClusterList) { + *out = *in + out.TypeMeta = in.TypeMeta + out.ListMeta = in.ListMeta + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]SeaweedfsCluster, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SeaweedfsClusterList. +func (in *SeaweedfsClusterList) DeepCopy() *SeaweedfsClusterList { + if in == nil { + return nil + } + out := new(SeaweedfsClusterList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *SeaweedfsClusterList) 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 *SeaweedfsClusterSpec) DeepCopyInto(out *SeaweedfsClusterSpec) { + *out = *in + out.Master = in.Master + if in.Volumes != nil { + in, out := &in.Volumes, &out.Volumes + *out = make([]SeaweedfsVolumeSpec, len(*in)) + copy(*out, *in) + } + out.Filer = in.Filer + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SeaweedfsClusterSpec. +func (in *SeaweedfsClusterSpec) DeepCopy() *SeaweedfsClusterSpec { + if in == nil { + return nil + } + out := new(SeaweedfsClusterSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SeaweedfsClusterStatus) DeepCopyInto(out *SeaweedfsClusterStatus) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SeaweedfsClusterStatus. +func (in *SeaweedfsClusterStatus) DeepCopy() *SeaweedfsClusterStatus { + if in == nil { + return nil + } + out := new(SeaweedfsClusterStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SeaweedfsFilerSpec) DeepCopyInto(out *SeaweedfsFilerSpec) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SeaweedfsFilerSpec. +func (in *SeaweedfsFilerSpec) DeepCopy() *SeaweedfsFilerSpec { + if in == nil { + return nil + } + out := new(SeaweedfsFilerSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SeaweedfsMasterSpec) DeepCopyInto(out *SeaweedfsMasterSpec) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SeaweedfsMasterSpec. +func (in *SeaweedfsMasterSpec) DeepCopy() *SeaweedfsMasterSpec { + if in == nil { + return nil + } + out := new(SeaweedfsMasterSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SeaweedfsVolumeSpec) DeepCopyInto(out *SeaweedfsVolumeSpec) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SeaweedfsVolumeSpec. +func (in *SeaweedfsVolumeSpec) DeepCopy() *SeaweedfsVolumeSpec { + if in == nil { + return nil + } + out := new(SeaweedfsVolumeSpec) + in.DeepCopyInto(out) + return out +} diff --git a/pkg/apis/cluster/v1alpha1/zz_generated.openapi.go b/pkg/apis/cluster/v1alpha1/zz_generated.openapi.go new file mode 100644 index 0000000..c545d3a --- /dev/null +++ b/pkg/apis/cluster/v1alpha1/zz_generated.openapi.go @@ -0,0 +1,256 @@ +// +build !ignore_autogenerated + +// This file was autogenerated by openapi-gen. Do not edit it manually! + +package v1alpha1 + +import ( + "github.com/go-openapi/spec" + "k8s.io/kube-openapi/pkg/common" +) + +func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenAPIDefinition { + return map[string]common.OpenAPIDefinition{ + "./pkg/apis/cluster/v1alpha1.SeaweedfsCluster": schema_pkg_apis_cluster_v1alpha1_SeaweedfsCluster(ref), + "./pkg/apis/cluster/v1alpha1.SeaweedfsClusterSpec": schema_pkg_apis_cluster_v1alpha1_SeaweedfsClusterSpec(ref), + "./pkg/apis/cluster/v1alpha1.SeaweedfsClusterStatus": schema_pkg_apis_cluster_v1alpha1_SeaweedfsClusterStatus(ref), + "./pkg/apis/cluster/v1alpha1.SeaweedfsFilerSpec": schema_pkg_apis_cluster_v1alpha1_SeaweedfsFilerSpec(ref), + "./pkg/apis/cluster/v1alpha1.SeaweedfsMasterSpec": schema_pkg_apis_cluster_v1alpha1_SeaweedfsMasterSpec(ref), + "./pkg/apis/cluster/v1alpha1.SeaweedfsVolumeSpec": schema_pkg_apis_cluster_v1alpha1_SeaweedfsVolumeSpec(ref), + } +} + +func schema_pkg_apis_cluster_v1alpha1_SeaweedfsCluster(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "SeaweedfsCluster is the Schema for the seaweedfsclusters API", + Type: []string{"object"}, + 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("./pkg/apis/cluster/v1alpha1.SeaweedfsClusterSpec"), + }, + }, + "status": { + SchemaProps: spec.SchemaProps{ + Ref: ref("./pkg/apis/cluster/v1alpha1.SeaweedfsClusterStatus"), + }, + }, + }, + }, + }, + Dependencies: []string{ + "./pkg/apis/cluster/v1alpha1.SeaweedfsClusterSpec", "./pkg/apis/cluster/v1alpha1.SeaweedfsClusterStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"}, + } +} + +func schema_pkg_apis_cluster_v1alpha1_SeaweedfsClusterSpec(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "SeaweedfsClusterSpec defines the desired state of SeaweedfsCluster", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "version": { + SchemaProps: spec.SchemaProps{ + Type: []string{"string"}, + Format: "", + }, + }, + "master": { + SchemaProps: spec.SchemaProps{ + Ref: ref("./pkg/apis/cluster/v1alpha1.SeaweedfsMasterSpec"), + }, + }, + "volumes": { + SchemaProps: spec.SchemaProps{ + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Ref: ref("./pkg/apis/cluster/v1alpha1.SeaweedfsVolumeSpec"), + }, + }, + }, + }, + }, + "filer": { + SchemaProps: spec.SchemaProps{ + Ref: ref("./pkg/apis/cluster/v1alpha1.SeaweedfsFilerSpec"), + }, + }, + }, + }, + }, + Dependencies: []string{ + "./pkg/apis/cluster/v1alpha1.SeaweedfsFilerSpec", "./pkg/apis/cluster/v1alpha1.SeaweedfsMasterSpec", "./pkg/apis/cluster/v1alpha1.SeaweedfsVolumeSpec"}, + } +} + +func schema_pkg_apis_cluster_v1alpha1_SeaweedfsClusterStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "SeaweedfsClusterStatus defines the observed state of SeaweedfsCluster", + Type: []string{"object"}, + }, + }, + } +} + +func schema_pkg_apis_cluster_v1alpha1_SeaweedfsFilerSpec(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "SeaweedfsFilerSpec defines the desired state of filer server in cluster", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "replicas": { + SchemaProps: spec.SchemaProps{ + Description: "Replicas a size of filer replications", + Type: []string{"integer"}, + Format: "int32", + }, + }, + "dir_list_limit": { + SchemaProps: spec.SchemaProps{ + Description: "DirListLimit limit sub dir listing size, default 100000", + Type: []string{"integer"}, + Format: "int32", + }, + }, + "disable_dir_listing": { + SchemaProps: spec.SchemaProps{ + Description: "DisableDirListing turn off directory listing", + Type: []string{"boolean"}, + Format: "", + }, + }, + "max_mb": { + SchemaProps: spec.SchemaProps{ + Description: "MaxMB split files larger than the limit, default 32", + Type: []string{"integer"}, + Format: "int32", + }, + }, + "port": { + SchemaProps: spec.SchemaProps{ + Description: "Port filer server http listen port", + Type: []string{"integer"}, + Format: "int32", + }, + }, + }, + }, + }, + } +} + +func schema_pkg_apis_cluster_v1alpha1_SeaweedfsMasterSpec(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "SeaweedfsMasterSpec defines the desired state of master server in cluster", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "replication_size": { + SchemaProps: spec.SchemaProps{ + Description: "Replicas a size of a raft cluster. The master servers are coordinated by Raft protocol, to elect a leader.", + Type: []string{"integer"}, + Format: "int32", + }, + }, + "port": { + SchemaProps: spec.SchemaProps{ + Description: "Port set master server http api service port. default is 9333 Master servers also use it identify each other.", + Type: []string{"integer"}, + Format: "int32", + }, + }, + "disable_http": { + SchemaProps: spec.SchemaProps{ + Description: "DisableHTTP if disable http proto, only gRPC operations are allowed. GRPC port is http port + 10000", + Type: []string{"boolean"}, + Format: "", + }, + }, + "default_replication": { + SchemaProps: spec.SchemaProps{ + Description: "DefaultReplication set the data replication policy in volumes. default \"000\"", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + } +} + +func schema_pkg_apis_cluster_v1alpha1_SeaweedfsVolumeSpec(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "SeaweedfsVolumeSpec defines the desired state of volume servers in cluster", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "max": { + SchemaProps: spec.SchemaProps{ + Description: "Max set the maximum numbers of volumes management by this server. Each volume is a 30G size file in under layer filesystem. Default is 7", + Type: []string{"integer"}, + Format: "int32", + }, + }, + "compaction_mbps": { + SchemaProps: spec.SchemaProps{ + Description: "CompactionMbps limit background compaction or copying speed in mega bytes per second", + Type: []string{"integer"}, + Format: "int32", + }, + }, + "rack": { + SchemaProps: spec.SchemaProps{ + Description: "Rack current volume server's rack name", + Type: []string{"string"}, + Format: "", + }, + }, + "data_center": { + SchemaProps: spec.SchemaProps{ + Description: "DataCenter current volume server's data center name", + Type: []string{"string"}, + Format: "", + }, + }, + "port": { + SchemaProps: spec.SchemaProps{ + Description: "Port volume server api http listen port", + Type: []string{"integer"}, + Format: "int32", + }, + }, + }, + }, + }, + } +} diff --git a/pkg/controller/add_seaweedfscluster.go b/pkg/controller/add_seaweedfscluster.go new file mode 100644 index 0000000..a234f51 --- /dev/null +++ b/pkg/controller/add_seaweedfscluster.go @@ -0,0 +1,10 @@ +package controller + +import ( + "github.com/seaweedfs/seaweedfs-operator/pkg/controller/seaweedfscluster" +) + +func init() { + // AddToManagerFuncs is a list of functions to create controllers and add them to a manager. + AddToManagerFuncs = append(AddToManagerFuncs, seaweedfscluster.Add) +} diff --git a/pkg/controller/seaweedfscluster/seaweedfscluster_controller.go b/pkg/controller/seaweedfscluster/seaweedfscluster_controller.go new file mode 100644 index 0000000..f194571 --- /dev/null +++ b/pkg/controller/seaweedfscluster/seaweedfscluster_controller.go @@ -0,0 +1,153 @@ +package seaweedfscluster + +import ( + "context" + + clusterv1alpha1 "github.com/seaweedfs/seaweedfs-operator/pkg/apis/cluster/v1alpha1" + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "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" + "sigs.k8s.io/controller-runtime/pkg/handler" + logf "sigs.k8s.io/controller-runtime/pkg/log" + "sigs.k8s.io/controller-runtime/pkg/manager" + "sigs.k8s.io/controller-runtime/pkg/reconcile" + "sigs.k8s.io/controller-runtime/pkg/source" +) + +var log = logf.Log.WithName("controller_seaweedfscluster") + +/** +* 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 SeaweedfsCluster 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 &ReconcileSeaweedfsCluster{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("seaweedfscluster-controller", mgr, controller.Options{Reconciler: r}) + if err != nil { + return err + } + + // Watch for changes to primary resource SeaweedfsCluster + err = c.Watch(&source.Kind{Type: &clusterv1alpha1.SeaweedfsCluster{}}, &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 SeaweedfsCluster + err = c.Watch(&source.Kind{Type: &corev1.Pod{}}, &handler.EnqueueRequestForOwner{ + IsController: true, + OwnerType: &clusterv1alpha1.SeaweedfsCluster{}, + }) + if err != nil { + return err + } + + return nil +} + +// blank assignment to verify that ReconcileSeaweedfsCluster implements reconcile.Reconciler +var _ reconcile.Reconciler = &ReconcileSeaweedfsCluster{} + +// ReconcileSeaweedfsCluster reconciles a SeaweedfsCluster object +type ReconcileSeaweedfsCluster 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 SeaweedfsCluster object and makes changes based on the state read +// and what is in the SeaweedfsCluster.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 *ReconcileSeaweedfsCluster) Reconcile(request reconcile.Request) (reconcile.Result, error) { + reqLogger := log.WithValues("Request.Namespace", request.Namespace, "Request.Name", request.Name) + reqLogger.Info("Reconciling SeaweedfsCluster") + + // Fetch the SeaweedfsCluster instance + instance := &clusterv1alpha1.SeaweedfsCluster{} + 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 + return reconcile.Result{}, nil + } + // Error reading the object - requeue the request. + return reconcile.Result{}, err + } + + // Define a new Pod object + pod := newPodForCR(instance) + + // Set SeaweedfsCluster instance as the owner and controller + if err := controllerutil.SetControllerReference(instance, pod, r.scheme); err != nil { + return reconcile.Result{}, err + } + + // Check if this Pod already exists + found := &corev1.Pod{} + err = r.client.Get(context.TODO(), types.NamespacedName{Name: pod.Name, Namespace: pod.Namespace}, found) + if err != nil && errors.IsNotFound(err) { + reqLogger.Info("Creating a new Pod", "Pod.Namespace", pod.Namespace, "Pod.Name", pod.Name) + err = r.client.Create(context.TODO(), pod) + if err != nil { + return reconcile.Result{}, err + } + + // Pod created successfully - don't requeue + return reconcile.Result{}, nil + } else if err != nil { + return reconcile.Result{}, err + } + + // Pod already exists - don't requeue + reqLogger.Info("Skip reconcile: Pod already exists", "Pod.Namespace", found.Namespace, "Pod.Name", found.Name) + return reconcile.Result{}, nil +} + +// newPodForCR returns a busybox pod with the same name/namespace as the cr +func newPodForCR(cr *clusterv1alpha1.SeaweedfsCluster) *corev1.Pod { + labels := map[string]string{ + "app": cr.Name, + } + return &corev1.Pod{ + ObjectMeta: metav1.ObjectMeta{ + Name: cr.Name + "-pod", + Namespace: cr.Namespace, + Labels: labels, + }, + Spec: corev1.PodSpec{ + Containers: []corev1.Container{ + { + Name: "busybox", + Image: "busybox", + Command: []string{"sleep", "3600"}, + }, + }, + }, + } +}