| @@ -0,0 +1,46 @@ | |||
| #!/bin/bash | |||
| build_folder="$PWD/build" | |||
| imagebuild_folder="$PWD/imagebuild" | |||
| yml_folder="$PWD/yml" | |||
| echo "开始构建agent镜像..." | |||
| cd "$imagebuild_folder"/agent || exit | |||
| rm -rf agent | |||
| rm -rf confs | |||
| cp -r "$build_folder"/agent . | |||
| #cp -r "$build_folder"/confs . | |||
| sh build.sh | |||
| echo "agent镜像构建完成" | |||
| echo "开始构建coordinator镜像..." | |||
| cd "$imagebuild_folder"/coordinator || exit | |||
| rm -rf coordinator | |||
| rm -rf confs | |||
| cp -r "$build_folder"/coordinator . | |||
| #cp -r "$build_folder"/confs . | |||
| sh build.sh | |||
| echo "coordinator镜像构建完成" | |||
| echo "开始构建scanner镜像..." | |||
| cd "$imagebuild_folder"/scanner || exit | |||
| rm -rf scanner | |||
| rm -rf confs | |||
| cp -r "$build_folder"/scanner . | |||
| #cp -r "$build_folder"/confs . | |||
| sh build.sh | |||
| echo "scanner镜像构建完成" | |||
| echo "开始构建client镜像..." | |||
| cd "$imagebuild_folder"/client || exit | |||
| rm -rf client | |||
| rm -rf confs | |||
| cp -r "$build_folder"/client . | |||
| #cp -r "$build_folder"/confs . | |||
| sh build.sh | |||
| echo "client镜像构建完成" | |||
| echo "全部镜像构建完成" | |||
| #echo "生成yaml脚本" | |||
| #cd "$yml_folder" || exit | |||
| #sh replace.sh | |||
| @@ -0,0 +1,6 @@ | |||
| #FROM scratch | |||
| FROM alpine:latest | |||
| COPY . /opt | |||
| WORKDIR /opt/agent | |||
| RUN chmod +x agent | |||
| ENTRYPOINT ["./agent"] | |||
| @@ -0,0 +1,4 @@ | |||
| #!/bin/bash | |||
| docker build -t 112.95.163.90:5010/agentservice-x86:latest . | |||
| docker push 112.95.163.90:5010/agentservice-x86:latest | |||
| @@ -0,0 +1,6 @@ | |||
| #FROM scratch | |||
| FROM alpine:latest | |||
| COPY . /opt | |||
| WORKDIR /opt/client | |||
| RUN chmod +x client | |||
| ENTRYPOINT ["./client","serve","http"] | |||
| @@ -0,0 +1,4 @@ | |||
| #!/bin/bash | |||
| docker build -t 112.95.163.90:5010/clientservice-x86:latest . | |||
| docker push 112.95.163.90:5010/clientservice-x86:latest | |||
| @@ -0,0 +1,12 @@ | |||
| #FROM scratch | |||
| FROM alpine:latest | |||
| COPY . /opt | |||
| WORKDIR /opt/coordinator | |||
| RUN apk add --no-cache tzdata | |||
| ENV TZ=Asia/Shanghai | |||
| RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone | |||
| RUN chmod +x coordinator | |||
| #ENTRYPOINT ["tail","-f","/etc/hosts"] | |||
| #RUN ./coordinator & | |||
| #ENTRYPOINT ["tail","-f","log/coordinator.log"] | |||
| ENTRYPOINT ["./coordinator"] | |||
| @@ -0,0 +1,4 @@ | |||
| #!/bin/bash | |||
| docker build -t 112.95.163.90:5010/coordinatorservice-x86:latest . | |||
| docker push 112.95.163.90:5010/coordinatorservice-x86:latest | |||
| @@ -0,0 +1,9 @@ | |||
| #FROM scratch | |||
| FROM alpine:latest | |||
| COPY . /opt | |||
| WORKDIR /opt/scanner | |||
| RUN apk add --no-cache tzdata | |||
| ENV TZ=Asia/Shanghai | |||
| RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone | |||
| RUN chmod +x scanner | |||
| ENTRYPOINT ["./scanner"] | |||
| @@ -0,0 +1,4 @@ | |||
| #!/bin/bash | |||
| docker build -t 112.95.163.90:5010/scannerservice-x86:latest . | |||
| docker push 112.95.163.90:5010/scannerservice-x86:latest | |||
| @@ -0,0 +1,14 @@ | |||
| 1、将storage编译好的build文件放在cloudream目录下 | |||
| 2、在cloudream目录下,运行build_all.sh,构建镜像 | |||
| ./build_all.sh | |||
| 3、进入yaml目录 | |||
| cd yaml | |||
| 4、修改config.ini,填好镜像仓库及其他agent部署信息 | |||
| 5、运行replace.sh,生成yaml文件 | |||
| 6、修改rclone_pv_*.yaml,填写对应节点的rclone配置文件 | |||
| 7、执行启动脚本start.sh,运行pod | |||
| ./start.sh | |||
| 8、等待启动完成后,查看pod是否正常运行 | |||
| kubectl get po -A -owide | |||
| 9、若需要停止,执行stop.sh | |||
| ./stop.sh | |||
| @@ -0,0 +1,25 @@ | |||
| [General] | |||
| image_registry=112.95.163.90:5010 | |||
| [agent1] | |||
| label=pcm3 | |||
| port=32001 | |||
| node=izbp1h7pf0vgxo33ss3b0bz | |||
| [agent2] | |||
| label=pcm03 | |||
| port=32002 | |||
| node=ecs-test | |||
| [coordinator] | |||
| label=pcm00 | |||
| node=10-9-72-244 | |||
| [scanner] | |||
| label=pcm01 | |||
| node=10-9-72-244 | |||
| [client] | |||
| label=pcm2 | |||
| port=32010 | |||
| node=10-9-72-244 | |||
| @@ -0,0 +1,42 @@ | |||
| { | |||
| "id": 1, | |||
| "local": { | |||
| "nodeID": 1, | |||
| "localIP": "127.0.0.1", | |||
| "externalIP": "127.0.0.1", | |||
| "locationID": 1 | |||
| }, | |||
| "grpc": { | |||
| "ip": "127.0.0.1", | |||
| "port": 5010 | |||
| }, | |||
| "logger": { | |||
| "output": "file", | |||
| "outputFileName": "agent", | |||
| "outputDirectory": "log", | |||
| "level": "debug" | |||
| }, | |||
| "rabbitMQ": { | |||
| "address": "127.0.0.1:5672", | |||
| "account": "cloudream", | |||
| "password": "123456", | |||
| "vhost": "/" | |||
| }, | |||
| "ipfs": { | |||
| "address": "127.0.0.1:5001" | |||
| }, | |||
| "distlock": { | |||
| "etcdAddress": "127.0.0.1:2379", | |||
| "etcdUsername": "", | |||
| "etcdPassword": "", | |||
| "etcdLockLeaseTimeSec": 5, | |||
| "randomReleasingDelayMs": 3000, | |||
| "serviceDescription": "I am a agent" | |||
| }, | |||
| "connectivity": { | |||
| "testInterval": 300 | |||
| }, | |||
| "downloader": { | |||
| "maxStripCacheCount": 100 | |||
| } | |||
| } | |||
| @@ -0,0 +1,35 @@ | |||
| { | |||
| "local": { | |||
| "localIP": "127.0.0.1", | |||
| "externalIP": "127.0.0.1", | |||
| "locationID": 1 | |||
| }, | |||
| "agentGRPC": { | |||
| "port": 5010 | |||
| }, | |||
| "logger": { | |||
| "output": "stdout", | |||
| "level": "debug" | |||
| }, | |||
| "rabbitMQ": { | |||
| "address": "127.0.0.1:5672", | |||
| "account": "cloudream", | |||
| "password": "123456", | |||
| "vhost": "/" | |||
| }, | |||
| "ipfs": null, | |||
| "distlock": { | |||
| "etcdAddress": "127.0.0.1:2379", | |||
| "etcdUsername": "", | |||
| "etcdPassword": "", | |||
| "etcdLockLeaseTimeSec": 5, | |||
| "randomReleasingDelayMs": 3000, | |||
| "serviceDescription": "I am a client" | |||
| }, | |||
| "connectivity": { | |||
| "testInterval": 300 | |||
| }, | |||
| "downloader": { | |||
| "maxStripCacheCount": 100 | |||
| } | |||
| } | |||
| @@ -0,0 +1,20 @@ | |||
| { | |||
| "logger": { | |||
| "output": "file", | |||
| "outputFileName": "coordinator", | |||
| "outputDirectory": "log", | |||
| "level": "debug" | |||
| }, | |||
| "db": { | |||
| "address": "127.0.0.1:3306", | |||
| "account": "root", | |||
| "password": "123456", | |||
| "databaseName": "cloudream" | |||
| }, | |||
| "rabbitMQ": { | |||
| "address": "127.0.0.1:5672", | |||
| "account": "cloudream", | |||
| "password": "123456", | |||
| "vhost": "/" | |||
| } | |||
| } | |||
| @@ -0,0 +1,26 @@ | |||
| apiVersion: v1 | |||
| kind: PersistentVolume | |||
| metadata: | |||
| name: rclone-{{NODE_NAME}} | |||
| labels: | |||
| name: rclone-{{NODE_NAME}} | |||
| spec: | |||
| capacity: | |||
| storage: 10Gi | |||
| accessModes: | |||
| - ReadWriteMany | |||
| storageClassName: rclone | |||
| csi: | |||
| driver: csi-rclone | |||
| volumeHandle: rclone-data-id | |||
| volumeAttributes: | |||
| remote: "xxxx" | |||
| remotePath: "xxxx" | |||
| configData: | | |||
| [xxxx] | |||
| type = s3 | |||
| provider = xxxx | |||
| access_key_id = xxxx | |||
| secret_access_key = xxxx | |||
| endpoint = xxxx | |||
| @@ -0,0 +1,30 @@ | |||
| { | |||
| "ecFileSizeThreshold": 104857600, | |||
| "nodeUnavailableSeconds": 300, | |||
| "logger": { | |||
| "output": "file", | |||
| "outputFileName": "scanner", | |||
| "outputDirectory": "log", | |||
| "level": "debug" | |||
| }, | |||
| "db": { | |||
| "address": "127.0.0.1:3306", | |||
| "account": "root", | |||
| "password": "123456", | |||
| "databaseName": "cloudream" | |||
| }, | |||
| "rabbitMQ": { | |||
| "address": "127.0.0.1:5672", | |||
| "account": "cloudream", | |||
| "password": "123456", | |||
| "vhost": "/" | |||
| }, | |||
| "distlock": { | |||
| "etcdAddress": "127.0.0.1:2379", | |||
| "etcdUsername": "", | |||
| "etcdPassword": "", | |||
| "etcdLockLeaseTimeSec": 5, | |||
| "randomReleasingDelayMs": 3000, | |||
| "serviceDescription": "I am a scanner" | |||
| } | |||
| } | |||
| @@ -0,0 +1,18 @@ | |||
| FROM alpine:3.16 | |||
| RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories | |||
| RUN apk add --no-cache ca-certificates bash fuse3 curl unzip tini | |||
| #RUN curl https://rclone.org/install.sh | bash | |||
| COPY rclone /usr/bin/rclone | |||
| RUN chmod +x /usr/bin/rclone | |||
| # Use pre-compiled version (with cirectory marker patch) | |||
| # https://github.com/rclone/rclone/pull/5323 | |||
| # COPY bin/rclone /usr/bin/rclone | |||
| # RUN chmod 755 /usr/bin/rclone \ | |||
| # && chown root:root /usr/bin/rclone | |||
| COPY ./_output/csi-rclone-plugin /bin/csi-rclone-plugin | |||
| RUN chmod +x /bin/csi-rclone-plugin | |||
| ENTRYPOINT [ "/sbin/tini", "--"] | |||
| CMD ["/bin/csi-rclone-plugin"] | |||
| @@ -0,0 +1,4 @@ | |||
| #!/bin/bash | |||
| docker build -t 10.16.43.85:5010/csi-rclone-reloaded_arm64:v1.4.0 . | |||
| docker push 10.16.43.85:5010/csi-rclone-reloaded_arm64:v1.4.0 | |||
| @@ -0,0 +1,18 @@ | |||
| FROM alpine:3.16 | |||
| RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories | |||
| RUN apk add --no-cache ca-certificates bash fuse3 curl unzip tini | |||
| #RUN curl https://rclone.org/install.sh | bash | |||
| COPY rclone /usr/bin/rclone | |||
| RUN chmod +x /usr/bin/rclone | |||
| # Use pre-compiled version (with cirectory marker patch) | |||
| # https://github.com/rclone/rclone/pull/5323 | |||
| # COPY bin/rclone /usr/bin/rclone | |||
| # RUN chmod 755 /usr/bin/rclone \ | |||
| # && chown root:root /usr/bin/rclone | |||
| COPY ./_output/csi-rclone-plugin /bin/csi-rclone-plugin | |||
| RUN chmod +x /bin/csi-rclone-plugin | |||
| ENTRYPOINT [ "/sbin/tini", "--"] | |||
| CMD ["/bin/csi-rclone-plugin"] | |||
| @@ -0,0 +1,4 @@ | |||
| #!/bin/bash | |||
| docker build -t 112.95.163.90:5010/csi-rclone-reloaded:v1.4.0 . | |||
| docker push 112.95.163.90:5010/csi-rclone-reloaded:v1.4.0 | |||
| @@ -0,0 +1,48 @@ | |||
| # This YAML file contains RBAC API objects that are necessary to run external | |||
| # CSI attacher for rclone adapter | |||
| apiVersion: v1 | |||
| kind: ServiceAccount | |||
| metadata: | |||
| name: csi-controller-rclone | |||
| namespace: kube-system | |||
| --- | |||
| kind: ClusterRole | |||
| apiVersion: rbac.authorization.k8s.io/v1 | |||
| metadata: | |||
| name: external-controller-rclone | |||
| rules: | |||
| - apiGroups: [""] | |||
| resources: ["persistentvolumes"] | |||
| verbs: ["get", "list", "watch", "update"] | |||
| - apiGroups: [""] | |||
| resources: ["nodes"] | |||
| verbs: ["get", "list", "watch"] | |||
| - apiGroups: ["csi.storage.k8s.io"] | |||
| resources: ["csinodeinfos"] | |||
| verbs: ["get", "list", "watch"] | |||
| - apiGroups: ["storage.k8s.io"] | |||
| resources: ["volumeattachments"] | |||
| verbs: ["get", "list", "watch", "update"] | |||
| - apiGroups: ["storage.k8s.io"] | |||
| resources: ["volumeattachments/status"] | |||
| verbs: ["patch"] | |||
| - apiGroups: ["coordination.k8s.io"] | |||
| resources: ["leases"] | |||
| verbs: ["get", "create", "update"] | |||
| - apiGroups: [""] | |||
| resources: ["events"] | |||
| verbs: ["create"] | |||
| --- | |||
| kind: ClusterRoleBinding | |||
| apiVersion: rbac.authorization.k8s.io/v1 | |||
| metadata: | |||
| name: csi-attacher-role-rclone | |||
| subjects: | |||
| - kind: ServiceAccount | |||
| name: csi-controller-rclone | |||
| namespace: kube-system | |||
| roleRef: | |||
| kind: ClusterRole | |||
| name: external-controller-rclone | |||
| apiGroup: rbac.authorization.k8s.io | |||
| @@ -0,0 +1,56 @@ | |||
| # This YAML file contains attacher & csi driver API objects that are necessary | |||
| # to run external CSI attacher for rclone | |||
| kind: StatefulSet | |||
| apiVersion: apps/v1 | |||
| metadata: | |||
| name: csi-controller-rclone | |||
| namespace: kube-system | |||
| spec: | |||
| serviceName: "csi-controller-rclone" | |||
| replicas: 1 | |||
| selector: | |||
| matchLabels: | |||
| app: csi-controller-rclone | |||
| template: | |||
| metadata: | |||
| labels: | |||
| app: csi-controller-rclone | |||
| spec: | |||
| serviceAccountName: csi-controller-rclone | |||
| containers: | |||
| - name: csi-attacher | |||
| #image: k8s.gcr.io/sig-storage/csi-attacher:v3.4.0 | |||
| image: registry.cn-hangzhou.aliyuncs.com/google_containers/csi-attacher:v3.4.0 | |||
| args: | |||
| - "--v=5" | |||
| - "--csi-address=$(ADDRESS)" | |||
| - "--leader-election" | |||
| env: | |||
| - name: ADDRESS | |||
| value: /csi/csi.sock | |||
| imagePullPolicy: "Always" | |||
| volumeMounts: | |||
| - name: socket-dir | |||
| mountPath: /csi | |||
| - name: rclone | |||
| image: dvcrn/csi-rclone-reloaded:v1.4.0 | |||
| image: 112.95.163.90:5010/csi-rclone-reloaded:v1.4.0 | |||
| args: | |||
| - "/bin/csi-rclone-plugin" | |||
| - "--nodeid=$(NODE_ID)" | |||
| - "--endpoint=$(CSI_ENDPOINT)" | |||
| env: | |||
| - name: NODE_ID | |||
| valueFrom: | |||
| fieldRef: | |||
| fieldPath: spec.nodeName | |||
| - name: CSI_ENDPOINT | |||
| value: unix://plugin/csi.sock | |||
| imagePullPolicy: "Always" | |||
| volumeMounts: | |||
| - name: socket-dir | |||
| mountPath: /plugin | |||
| volumes: | |||
| - name: socket-dir | |||
| emptyDir: {} | |||
| @@ -0,0 +1,8 @@ | |||
| # this should be deregistered once the controller stops | |||
| apiVersion: storage.k8s.io/v1 | |||
| kind: CSIDriver | |||
| metadata: | |||
| name: csi-rclone | |||
| spec: | |||
| attachRequired: true | |||
| podInfoOnMount: false # are we sure about this? | |||
| @@ -0,0 +1,40 @@ | |||
| # This YAML defines all API objects to create RBAC roles for CSI node plugin | |||
| apiVersion: v1 | |||
| kind: ServiceAccount | |||
| metadata: | |||
| name: csi-nodeplugin-rclone | |||
| namespace: kube-system | |||
| --- | |||
| kind: ClusterRole | |||
| apiVersion: rbac.authorization.k8s.io/v1 | |||
| metadata: | |||
| name: csi-nodeplugin-rclone | |||
| rules: | |||
| - apiGroups: [""] | |||
| resources: ["persistentvolumes"] | |||
| verbs: ["get", "list", "watch", "update"] | |||
| - apiGroups: [""] | |||
| resources: ["secrets", "secret"] | |||
| verbs: ["get", "list"] | |||
| - apiGroups: [""] | |||
| resources: ["nodes"] | |||
| verbs: ["get", "list", "watch", "update"] | |||
| - apiGroups: ["storage.k8s.io"] | |||
| resources: ["volumeattachments"] | |||
| verbs: ["get", "list", "watch", "update"] | |||
| - apiGroups: [""] | |||
| resources: ["events"] | |||
| verbs: ["get", "list", "watch", "create", "update", "patch"] | |||
| --- | |||
| kind: ClusterRoleBinding | |||
| apiVersion: rbac.authorization.k8s.io/v1 | |||
| metadata: | |||
| name: csi-nodeplugin-rclone | |||
| subjects: | |||
| - kind: ServiceAccount | |||
| name: csi-nodeplugin-rclone | |||
| namespace: kube-system | |||
| roleRef: | |||
| kind: ClusterRole | |||
| name: csi-nodeplugin-rclone | |||
| apiGroup: rbac.authorization.k8s.io | |||
| @@ -0,0 +1,106 @@ | |||
| # This YAML file contains driver-registrar & csi driver nodeplugin API objects | |||
| # that are necessary to run CSI nodeplugin for rclone | |||
| kind: DaemonSet | |||
| apiVersion: apps/v1 | |||
| metadata: | |||
| name: csi-nodeplugin-rclone | |||
| namespace: kube-system | |||
| spec: | |||
| selector: | |||
| matchLabels: | |||
| app: csi-nodeplugin-rclone | |||
| template: | |||
| metadata: | |||
| labels: | |||
| app: csi-nodeplugin-rclone | |||
| spec: | |||
| serviceAccountName: csi-nodeplugin-rclone | |||
| #hostNetwork: true | |||
| #dnsPolicy: ClusterFirstWithHostNet | |||
| dnsPolicy: Default | |||
| containers: | |||
| - name: node-driver-registrar | |||
| #image: k8s.gcr.io/sig-storage/csi-node-driver-registrar:v2.4.0 | |||
| image: registry.cn-hangzhou.aliyuncs.com/google_containers/csi-node-driver-registrar:v2.4.0 | |||
| lifecycle: | |||
| preStop: | |||
| exec: | |||
| command: | |||
| [ | |||
| "/bin/sh", | |||
| "-c", | |||
| "rm -rf /registration/csi-rclone /registration/csi-rclone-reg.sock", | |||
| ] | |||
| args: | |||
| - --v=5 | |||
| - --csi-address=/plugin/csi.sock | |||
| - --kubelet-registration-path=/var/lib/kubelet/plugins/csi-rclone/csi.sock | |||
| env: | |||
| - name: KUBE_NODE_NAME | |||
| valueFrom: | |||
| fieldRef: | |||
| fieldPath: spec.nodeName | |||
| volumeMounts: | |||
| - name: plugin-dir | |||
| mountPath: /plugin | |||
| - name: registration-dir | |||
| mountPath: /registration | |||
| - name: rclone | |||
| securityContext: | |||
| privileged: true | |||
| capabilities: | |||
| add: ["SYS_ADMIN"] | |||
| allowPrivilegeEscalation: true | |||
| #image: dvcrn/csi-rclone-reloaded:v1.4.0 | |||
| image: 112.95.163.90:5010/csi-rclone-reloaded:v1.4.0 | |||
| args: | |||
| - "/bin/csi-rclone-plugin" | |||
| - "--nodeid=$(NODE_ID)" | |||
| - "--endpoint=$(CSI_ENDPOINT)" | |||
| # - "2>&1 > /opt/log/a.log" | |||
| env: | |||
| - name: NODE_ID | |||
| valueFrom: | |||
| fieldRef: | |||
| fieldPath: spec.nodeName | |||
| - name: CSI_ENDPOINT | |||
| value: unix://plugin/csi.sock | |||
| #- name: RCLONE_LOG_FILE | |||
| # value: /opt/log/a.log | |||
| #- name: RCLONE_LOG_LEVEL | |||
| # value: DEBUG | |||
| imagePullPolicy: "Always" | |||
| lifecycle: | |||
| postStart: | |||
| exec: | |||
| command: | |||
| [ | |||
| "/bin/sh", | |||
| "-c", | |||
| "mount -t fuse.rclone | while read -r mount; do umount $(echo $mount | awk '{print $3}') ; done", | |||
| ] | |||
| volumeMounts: | |||
| - name: plugin-dir | |||
| mountPath: /plugin | |||
| - name: pods-mount-dir | |||
| mountPath: /var/lib/kubelet/pods | |||
| mountPropagation: "Bidirectional" | |||
| #- name: test-dir | |||
| # mountPath: /opt/log | |||
| volumes: | |||
| - name: plugin-dir | |||
| hostPath: | |||
| path: /var/lib/kubelet/plugins/csi-rclone | |||
| type: DirectoryOrCreate | |||
| - name: pods-mount-dir | |||
| hostPath: | |||
| path: /var/lib/kubelet/pods | |||
| type: Directory | |||
| - hostPath: | |||
| path: /var/lib/kubelet/plugins_registry | |||
| type: DirectoryOrCreate | |||
| name: registration-dir | |||
| #- name: test-dir | |||
| # hostPath: | |||
| # path: /home/pcm/abc | |||
| # type: DirectoryOrCreate | |||
| @@ -0,0 +1,66 @@ | |||
| --- | |||
| # Multiarch build file credits go to Lars Kellogg-Stedman at blog.oddbit.com. If You ever see this - thanks! | |||
| name: "build images" | |||
| on: | |||
| push: | |||
| branches: | |||
| - master | |||
| jobs: | |||
| docker: | |||
| runs-on: ubuntu-latest | |||
| steps: | |||
| - name: Checkout | |||
| uses: actions/checkout@v2 | |||
| - name: Prepare | |||
| id: prep | |||
| run: | | |||
| DOCKER_IMAGE=dvcrn/${GITHUB_REPOSITORY#*/} | |||
| VERSION=$(cat VERSION) | |||
| TAGS="${DOCKER_IMAGE}:${VERSION},${DOCKER_IMAGE}:latest" | |||
| echo ${TAGS} | |||
| echo ${VERSION} | |||
| echo ${DOCKER_IMAGE} | |||
| echo "tags=${TAGS}" >> $GITHUB_ENV | |||
| echo "docker_image=${DOCKER_IMAGE}" >> $GITHUB_ENV | |||
| - name: Set up QEMU | |||
| uses: docker/setup-qemu-action@v2 | |||
| with: | |||
| platforms: all | |||
| - name: Set up Docker Buildx | |||
| id: buildx | |||
| uses: docker/setup-buildx-action@v2 | |||
| - name: Login to DockerHub | |||
| if: github.event_name != 'pull_request' | |||
| uses: docker/login-action@v2 | |||
| with: | |||
| username: dvcrn | |||
| password: ${{ secrets.DOCKER_PASSWORD }} | |||
| - name: Build | |||
| uses: docker/build-push-action@v2 | |||
| with: | |||
| builder: ${{ steps.buildx.outputs.name }} | |||
| context: . | |||
| file: ./Dockerfile | |||
| platforms: linux/amd64,linux/arm64 | |||
| push: true | |||
| tags: ${{ env.tags }} | |||
| # - name: Build DM | |||
| # uses: docker/build-push-action@v2 | |||
| # with: | |||
| # builder: ${{ steps.buildx.outputs.name }} | |||
| # context: . | |||
| # file: ./Dockerfile.dm | |||
| # platforms: linux/amd64,linux/arm64 | |||
| # push: true | |||
| # tags: ${{ env.tags }} | |||
| @@ -0,0 +1,3 @@ | |||
| _output/ | |||
| .vscode | |||
| rclone-build/ | |||
| @@ -0,0 +1,10 @@ | |||
| # CHANGELOG | |||
| 1.4.0 (dvcrn): | |||
| - Merge support for specifying config in secrets: https://github.com/wunderio/csi-rclone/pull/7 | |||
| - Remove namespace of storageclass | |||
| - Move all resources into kube-system namespace | |||
| 1.3.0: | |||
| - Container init changed to tini | |||
| - rclone plugin version v1.59.2 | |||
| @@ -0,0 +1,23 @@ | |||
| #### | |||
| FROM golang:alpine AS builder | |||
| RUN apk update && apk add --no-cache git make bash | |||
| WORKDIR $GOPATH/src/csi-rclone-nodeplugin | |||
| COPY . . | |||
| RUN make plugin | |||
| #### | |||
| FROM alpine:3.16 | |||
| RUN apk add --no-cache ca-certificates bash fuse curl unzip tini | |||
| RUN curl https://rclone.org/install.sh | bash | |||
| # Use pre-compiled version (with cirectory marker patch) | |||
| # https://github.com/rclone/rclone/pull/5323 | |||
| # COPY bin/rclone /usr/bin/rclone | |||
| # RUN chmod 755 /usr/bin/rclone \ | |||
| # && chown root:root /usr/bin/rclone | |||
| COPY --from=builder /go/src/csi-rclone-nodeplugin/_output/csi-rclone-plugin /bin/csi-rclone-plugin | |||
| ENTRYPOINT [ "/sbin/tini", "--"] | |||
| CMD ["/bin/csi-rclone-plugin"] | |||
| @@ -0,0 +1,23 @@ | |||
| #### | |||
| FROM golang:alpine AS builder | |||
| RUN apk update && apk add --no-cache git make bash | |||
| WORKDIR $GOPATH/src/csi-rclone-nodeplugin | |||
| COPY . . | |||
| RUN make plugin-dm | |||
| #### | |||
| FROM alpine:3.16 | |||
| RUN apk add --no-cache ca-certificates bash fuse curl unzip tini | |||
| # RUN curl https://rclone.org/install.sh | bash | |||
| # Use pre-compiled version (with cirectory marker patch) | |||
| # https://github.com/rclone/rclone/pull/5323 | |||
| COPY ./install-dm.sh /tmp | |||
| COPY ./rclone-build /tmp/rclone-build | |||
| RUN /tmp/install-dm.sh | |||
| COPY --from=builder /go/src/csi-rclone-nodeplugin/_output/csi-rclone-plugin-dm /bin/csi-rclone-plugin | |||
| ENTRYPOINT [ "/sbin/tini", "--"] | |||
| CMD ["/bin/csi-rclone-plugin"] | |||
| @@ -0,0 +1,202 @@ | |||
| Apache License | |||
| Version 2.0, January 2004 | |||
| http://www.apache.org/licenses/ | |||
| TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION | |||
| 1. Definitions. | |||
| "License" shall mean the terms and conditions for use, reproduction, | |||
| and distribution as defined by Sections 1 through 9 of this document. | |||
| "Licensor" shall mean the copyright owner or entity authorized by | |||
| the copyright owner that is granting the License. | |||
| "Legal Entity" shall mean the union of the acting entity and all | |||
| other entities that control, are controlled by, or are under common | |||
| control with that entity. For the purposes of this definition, | |||
| "control" means (i) the power, direct or indirect, to cause the | |||
| direction or management of such entity, whether by contract or | |||
| otherwise, or (ii) ownership of fifty percent (50%) or more of the | |||
| outstanding shares, or (iii) beneficial ownership of such entity. | |||
| "You" (or "Your") shall mean an individual or Legal Entity | |||
| exercising permissions granted by this License. | |||
| "Source" form shall mean the preferred form for making modifications, | |||
| including but not limited to software source code, documentation | |||
| source, and configuration files. | |||
| "Object" form shall mean any form resulting from mechanical | |||
| transformation or translation of a Source form, including but | |||
| not limited to compiled object code, generated documentation, | |||
| and conversions to other media types. | |||
| "Work" shall mean the work of authorship, whether in Source or | |||
| Object form, made available under the License, as indicated by a | |||
| copyright notice that is included in or attached to the work | |||
| (an example is provided in the Appendix below). | |||
| "Derivative Works" shall mean any work, whether in Source or Object | |||
| form, that is based on (or derived from) the Work and for which the | |||
| editorial revisions, annotations, elaborations, or other modifications | |||
| represent, as a whole, an original work of authorship. For the purposes | |||
| of this License, Derivative Works shall not include works that remain | |||
| separable from, or merely link (or bind by name) to the interfaces of, | |||
| the Work and Derivative Works thereof. | |||
| "Contribution" shall mean any work of authorship, including | |||
| the original version of the Work and any modifications or additions | |||
| to that Work or Derivative Works thereof, that is intentionally | |||
| submitted to Licensor for inclusion in the Work by the copyright owner | |||
| or by an individual or Legal Entity authorized to submit on behalf of | |||
| the copyright owner. For the purposes of this definition, "submitted" | |||
| means any form of electronic, verbal, or written communication sent | |||
| to the Licensor or its representatives, including but not limited to | |||
| communication on electronic mailing lists, source code control systems, | |||
| and issue tracking systems that are managed by, or on behalf of, the | |||
| Licensor for the purpose of discussing and improving the Work, but | |||
| excluding communication that is conspicuously marked or otherwise | |||
| designated in writing by the copyright owner as "Not a Contribution." | |||
| "Contributor" shall mean Licensor and any individual or Legal Entity | |||
| on behalf of whom a Contribution has been received by Licensor and | |||
| subsequently incorporated within the Work. | |||
| 2. Grant of Copyright License. Subject to the terms and conditions of | |||
| this License, each Contributor hereby grants to You a perpetual, | |||
| worldwide, non-exclusive, no-charge, royalty-free, irrevocable | |||
| copyright license to reproduce, prepare Derivative Works of, | |||
| publicly display, publicly perform, sublicense, and distribute the | |||
| Work and such Derivative Works in Source or Object form. | |||
| 3. Grant of Patent License. Subject to the terms and conditions of | |||
| this License, each Contributor hereby grants to You a perpetual, | |||
| worldwide, non-exclusive, no-charge, royalty-free, irrevocable | |||
| (except as stated in this section) patent license to make, have made, | |||
| use, offer to sell, sell, import, and otherwise transfer the Work, | |||
| where such license applies only to those patent claims licensable | |||
| by such Contributor that are necessarily infringed by their | |||
| Contribution(s) alone or by combination of their Contribution(s) | |||
| with the Work to which such Contribution(s) was submitted. If You | |||
| institute patent litigation against any entity (including a | |||
| cross-claim or counterclaim in a lawsuit) alleging that the Work | |||
| or a Contribution incorporated within the Work constitutes direct | |||
| or contributory patent infringement, then any patent licenses | |||
| granted to You under this License for that Work shall terminate | |||
| as of the date such litigation is filed. | |||
| 4. Redistribution. You may reproduce and distribute copies of the | |||
| Work or Derivative Works thereof in any medium, with or without | |||
| modifications, and in Source or Object form, provided that You | |||
| meet the following conditions: | |||
| (a) You must give any other recipients of the Work or | |||
| Derivative Works a copy of this License; and | |||
| (b) You must cause any modified files to carry prominent notices | |||
| stating that You changed the files; and | |||
| (c) You must retain, in the Source form of any Derivative Works | |||
| that You distribute, all copyright, patent, trademark, and | |||
| attribution notices from the Source form of the Work, | |||
| excluding those notices that do not pertain to any part of | |||
| the Derivative Works; and | |||
| (d) If the Work includes a "NOTICE" text file as part of its | |||
| distribution, then any Derivative Works that You distribute must | |||
| include a readable copy of the attribution notices contained | |||
| within such NOTICE file, excluding those notices that do not | |||
| pertain to any part of the Derivative Works, in at least one | |||
| of the following places: within a NOTICE text file distributed | |||
| as part of the Derivative Works; within the Source form or | |||
| documentation, if provided along with the Derivative Works; or, | |||
| within a display generated by the Derivative Works, if and | |||
| wherever such third-party notices normally appear. The contents | |||
| of the NOTICE file are for informational purposes only and | |||
| do not modify the License. You may add Your own attribution | |||
| notices within Derivative Works that You distribute, alongside | |||
| or as an addendum to the NOTICE text from the Work, provided | |||
| that such additional attribution notices cannot be construed | |||
| as modifying the License. | |||
| You may add Your own copyright statement to Your modifications and | |||
| may provide additional or different license terms and conditions | |||
| for use, reproduction, or distribution of Your modifications, or | |||
| for any such Derivative Works as a whole, provided Your use, | |||
| reproduction, and distribution of the Work otherwise complies with | |||
| the conditions stated in this License. | |||
| 5. Submission of Contributions. Unless You explicitly state otherwise, | |||
| any Contribution intentionally submitted for inclusion in the Work | |||
| by You to the Licensor shall be under the terms and conditions of | |||
| this License, without any additional terms or conditions. | |||
| Notwithstanding the above, nothing herein shall supersede or modify | |||
| the terms of any separate license agreement you may have executed | |||
| with Licensor regarding such Contributions. | |||
| 6. Trademarks. This License does not grant permission to use the trade | |||
| names, trademarks, service marks, or product names of the Licensor, | |||
| except as required for reasonable and customary use in describing the | |||
| origin of the Work and reproducing the content of the NOTICE file. | |||
| 7. Disclaimer of Warranty. Unless required by applicable law or | |||
| agreed to in writing, Licensor provides the Work (and each | |||
| Contributor provides its Contributions) on an "AS IS" BASIS, | |||
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or | |||
| implied, including, without limitation, any warranties or conditions | |||
| of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A | |||
| PARTICULAR PURPOSE. You are solely responsible for determining the | |||
| appropriateness of using or redistributing the Work and assume any | |||
| risks associated with Your exercise of permissions under this License. | |||
| 8. Limitation of Liability. In no event and under no legal theory, | |||
| whether in tort (including negligence), contract, or otherwise, | |||
| unless required by applicable law (such as deliberate and grossly | |||
| negligent acts) or agreed to in writing, shall any Contributor be | |||
| liable to You for damages, including any direct, indirect, special, | |||
| incidental, or consequential damages of any character arising as a | |||
| result of this License or out of the use or inability to use the | |||
| Work (including but not limited to damages for loss of goodwill, | |||
| work stoppage, computer failure or malfunction, or any and all | |||
| other commercial damages or losses), even if such Contributor | |||
| has been advised of the possibility of such damages. | |||
| 9. Accepting Warranty or Additional Liability. While redistributing | |||
| the Work or Derivative Works thereof, You may choose to offer, | |||
| and charge a fee for, acceptance of support, warranty, indemnity, | |||
| or other liability obligations and/or rights consistent with this | |||
| License. However, in accepting such obligations, You may act only | |||
| on Your own behalf and on Your sole responsibility, not on behalf | |||
| of any other Contributor, and only if You agree to indemnify, | |||
| defend, and hold each Contributor harmless for any liability | |||
| incurred by, or claims asserted against, such Contributor by reason | |||
| of your accepting any such warranty or additional liability. | |||
| END OF TERMS AND CONDITIONS | |||
| APPENDIX: How to apply the Apache License to your work. | |||
| To apply the Apache License to your work, attach the following | |||
| boilerplate notice, with the fields enclosed by brackets "[]" | |||
| replaced with your own identifying information. (Don't include | |||
| the brackets!) The text should be enclosed in the appropriate | |||
| comment syntax for the file format. We also recommend that a | |||
| file or class name and description of purpose be included on the | |||
| same "printed page" as the copyright notice for easier | |||
| identification within third-party archives. | |||
| Copyright [yyyy] [name of copyright owner] | |||
| Licensed under the Apache License, Version 2.0 (the "License"); | |||
| you may not use this file except in compliance with the License. | |||
| You may obtain a copy of the License at | |||
| http://www.apache.org/licenses/LICENSE-2.0 | |||
| Unless required by applicable law or agreed to in writing, software | |||
| distributed under the License is distributed on an "AS IS" BASIS, | |||
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
| See the License for the specific language governing permissions and | |||
| limitations under the License. | |||
| @@ -0,0 +1,54 @@ | |||
| # Copyright 2017 The Kubernetes Authors. | |||
| # | |||
| # Licensed under the Apache License, Version 2.0 (the "License"); | |||
| # you may not use this file except in compliance with the License. | |||
| # You may obtain a copy of the License at | |||
| # | |||
| # http://www.apache.org/licenses/LICENSE-2.0 | |||
| # | |||
| # Unless required by applicable law or agreed to in writing, software | |||
| # distributed under the License is distributed on an "AS IS" BASIS, | |||
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
| # See the License for the specific language governing permissions and | |||
| # limitations under the License. | |||
| VERSION=$(shell cat VERSION) | |||
| REGISTRY_NAME=dvcrn | |||
| IMAGE_NAME=csi-rclone-reloaded | |||
| IMAGE_TAG=$(REGISTRY_NAME)/$(IMAGE_NAME):$(VERSION) | |||
| .PHONY: all rclone-plugin clean rclone-container | |||
| all: plugin container push | |||
| dm: plugin-dm container-dm push-dm | |||
| plugin: | |||
| go mod download | |||
| CGO_ENABLED=0 GOOS=linux go build -a -gcflags=-trimpath=$(go env GOPATH) -asmflags=-trimpath=$(go env GOPATH) -ldflags '-X github.com/wunderio/csi-rclone/pkg/rclone.DriverVersion=$(VERSION) -extldflags "-static"' -o _output/csi-rclone-plugin ./cmd/csi-rclone-plugin | |||
| plugin-dm: | |||
| go mod download | |||
| CGO_ENABLED=0 GOOS=linux go build -a -gcflags=-trimpath=$(go env GOPATH) -asmflags=-trimpath=$(go env GOPATH) -ldflags '-X github.com/wunderio/csi-rclone/pkg/rclone.DriverVersion=$(VERSION)-dm -extldflags "-static"' -o _output/csi-rclone-plugin-dm ./cmd/csi-rclone-plugin | |||
| container: | |||
| docker build -t $(IMAGE_TAG) -f ./cmd/csi-rclone-plugin/Dockerfile . | |||
| container-dm: | |||
| docker build -t $(IMAGE_TAG)-dm -f ./cmd/csi-rclone-plugin/Dockerfile.dm . | |||
| push: | |||
| docker push $(IMAGE_TAG) | |||
| push-dm: | |||
| docker push $(IMAGE_TAG)-dm | |||
| buildx: | |||
| docker buildx build --platform linux/amd64,linux/arm64 --push -t $(IMAGE_TAG) -f ./cmd/csi-rclone-plugin/Dockerfile . | |||
| buildx-dm: | |||
| docker buildx build --platform linux/amd64,linux/arm64 --push -t $(IMAGE_TAG)-dm -f ./cmd/csi-rclone-plugin/Dockerfile.dm . | |||
| clean: | |||
| go clean -r -x | |||
| -rm -rf _output | |||
| @@ -0,0 +1,185 @@ | |||
| # CSI rclone mount plugin | |||
| Fork of https://github.com/wunderio/csi-rclone that is a bit slow with merging PRs | |||
| Differences with that fork: | |||
| - Everything is under kube-system namespace | |||
| - Allow specifying of secrets for PV | |||
| - StorageClass is no longer namespaced | |||
| This project implements Container Storage Interface (CSI) plugin that allows using [rclone mount](https://rclone.org/) as storage backend. Rclone mount points and [parameters](https://rclone.org/commands/rclone_mount/) can be configured using Secret or PersistentVolume volumeAttibutes. | |||
| ## Kubernetes cluster compatability | |||
| Works (tested): | |||
| - `deploy/kubernetes/1.19`: K8S>= 1.19.x (due to storage.k8s.io/v1 CSIDriver API) | |||
| - `deploy/kubernetes/1.13`: K8S 1.13.x - 1.21.x (storage.k8s.io/v1beta1 CSIDriver API) | |||
| Does not work: | |||
| - v1.12.7-gke.10, driver name csi-rclone not found in the list of registered CSI drivers | |||
| ## Installing CSI driver to kubernetes cluster | |||
| TLDR: ` kubectl apply -f deploy/kubernetes/1.19` (or `deploy/kubernetes/1.13` for older version) to get the CSI setup | |||
| ### Example: Adding Dropbox through rclone | |||
| The easiest way to use this is to specify your rclone configuration inside the PV: | |||
| ```yaml | |||
| apiVersion: v1 | |||
| kind: PersistentVolume | |||
| metadata: | |||
| name: rclone-dropbox | |||
| labels: | |||
| name: rclone-dropbox | |||
| spec: | |||
| accessModes: | |||
| - ReadWriteMany | |||
| capacity: | |||
| storage: 10Gi | |||
| storageClassName: rclone | |||
| csi: | |||
| driver: csi-rclone | |||
| volumeHandle: rclone-dropbox-data-id | |||
| volumeAttributes: | |||
| remote: "dropbox" | |||
| remotePath: "" | |||
| configData: | | |||
| [dropbox] | |||
| type = dropbox | |||
| client_id = xxx | |||
| client_secret = xxx | |||
| token = {"access_token":"xxx","token_type":"bearer","refresh_token":"xxx","expiry":"xxx"} | |||
| --- | |||
| apiVersion: v1 | |||
| kind: PersistentVolumeClaim | |||
| metadata: | |||
| name: rclone-dropbox | |||
| spec: | |||
| accessModes: | |||
| - ReadWriteMany | |||
| resources: | |||
| requests: | |||
| storage: 10Gi | |||
| storageClassName: rclone | |||
| selector: | |||
| matchLabels: | |||
| name: rclone-dropbox | |||
| ``` | |||
| (to get access token, setup Dropbox locally with rclone first, then copy whatever `rclone config show` gives you) | |||
| ### Example: S3 storage without direct rclone configuration | |||
| ```yaml | |||
| apiVersion: v1 | |||
| kind: PersistentVolume | |||
| metadata: | |||
| name: rclone-wasabi | |||
| labels: | |||
| name: rclone-wasabi | |||
| spec: | |||
| accessModes: | |||
| - ReadWriteMany | |||
| capacity: | |||
| storage: 1000Gi | |||
| storageClassName: rclone | |||
| csi: | |||
| driver: csi-rclone | |||
| volumeHandle: data-id | |||
| volumeAttributes: | |||
| remote: "bucketname" | |||
| remotePath: "" | |||
| s3-provider: "Wasabi" | |||
| s3-endpoint: "https://s3.ap-southeast-1.wasabisys.com" | |||
| s3-access-key-id: "xxx" | |||
| s3-secret-access-key: "xxx" | |||
| --- | |||
| <pvc manifest here> | |||
| ``` | |||
| ### Example: Using a secret (thanks to [wunderio/csi-rclone#7](https://github.com/wunderio/csi-rclone/pull/7)) | |||
| _Note:_ secrets act as defaults, you can still override keys in your PV definitions. | |||
| _Note 2_: Use `secret-rclone` as global default for when there are no secrets defined, for example if you always want the same S3 credentials across your PVs | |||
| _Note 3_: Secrets need to be in the same namespace as the csi controller, so if you used the default of this repository, add it to `kube-system` | |||
| ```yaml | |||
| apiVersion: v1 | |||
| kind: Secret | |||
| metadata: | |||
| name: my-secret | |||
| namespace: kube-system # <-- secret needs to be in kube-system namespace, same as CSI controller | |||
| type: Opaque | |||
| stringData: | |||
| remote: "my-s3" | |||
| remotePath: "projectname" | |||
| configData: | | |||
| [my-s3] | |||
| type = s3 | |||
| provider = Minio | |||
| access_key_id = ACCESS_KEY_ID | |||
| secret_access_key = SECRET_ACCESS_KEY | |||
| endpoint = http://minio-release.default:9000 | |||
| ``` | |||
| Then specify it into the PV: | |||
| ```yaml | |||
| apiVersion: v1 | |||
| kind: PersistentVolume | |||
| metadata: | |||
| name: rclone-dropbox | |||
| labels: | |||
| name: rclone-dropbox | |||
| spec: | |||
| accessModes: | |||
| - ReadWriteMany | |||
| capacity: | |||
| storage: 10Gi | |||
| storageClassName: rclone | |||
| csi: | |||
| driver: csi-rclone | |||
| volumeHandle: rclone-dropbox-data-id | |||
| volumeAttributes: | |||
| secretName: "my-secret" | |||
| ``` | |||
| ## Debugging & logs | |||
| - After creating a pod, if something goes wrong you should be able to see it using `kubectl describe <pod>` | |||
| - Check logs of the controller: `kubectl logs -f -l app=csi-nodeplugin-rclone --namespace kube-system -c rclone` | |||
| ## Building plugin and creating image | |||
| Current code is referencing projects repository on github.com. If you fork the repository, you have to change go includes in several places (use search and replace). | |||
| 1. First push the changed code to remote. The build will use paths from `pkg/` directory. | |||
| 2. Build the plugin | |||
| ``` | |||
| make plugin | |||
| ``` | |||
| 3. Build the container and inject the plugin into it. | |||
| ``` | |||
| make container | |||
| ``` | |||
| 4. Change docker.io account in `Makefile` and use `make push` to push the image to remote. | |||
| ``` | |||
| make push | |||
| ``` | |||
| ## Changelog | |||
| See [CHANGELOG.txt](CHANGELOG.txt) | |||
| @@ -0,0 +1 @@ | |||
| v1.4.0 | |||
| @@ -0,0 +1,15 @@ | |||
| FROM alpine:3.16 | |||
| RUN apk add --no-cache ca-certificates bash fuse curl unzip tini | |||
| RUN curl https://rclone.org/install.sh | bash | |||
| # Use pre-compiled version (with cirectory marker patch) | |||
| # https://github.com/rclone/rclone/pull/5323 | |||
| # COPY bin/rclone /usr/bin/rclone | |||
| # RUN chmod 755 /usr/bin/rclone \ | |||
| # && chown root:root /usr/bin/rclone | |||
| COPY ./_output/csi-rclone-plugin /bin/csi-rclone-plugin | |||
| ENTRYPOINT [ "/sbin/tini", "--"] | |||
| CMD ["/bin/csi-rclone-plugin"] | |||
| @@ -0,0 +1,15 @@ | |||
| FROM alpine:3.16 | |||
| RUN apk add --no-cache ca-certificates bash fuse curl unzip tini | |||
| # RUN curl https://rclone.org/install.sh | bash | |||
| # Use pre-compiled version (with cirectory marker patch) | |||
| # https://github.com/rclone/rclone/pull/5323 | |||
| COPY ./install-dm.sh /tmp | |||
| COPY ./rclone-build /tmp/rclone-build | |||
| RUN /tmp/install-dm.sh | |||
| COPY ./_output/csi-rclone-plugin-dm /bin/csi-rclone-plugin | |||
| ENTRYPOINT [ "/sbin/tini", "--"] | |||
| CMD ["/bin/csi-rclone-plugin"] | |||
| @@ -0,0 +1,65 @@ | |||
| package main | |||
| import ( | |||
| "flag" | |||
| "fmt" | |||
| "os" | |||
| "github.com/spf13/cobra" | |||
| "github.com/wunderio/csi-rclone/pkg/rclone" | |||
| ) | |||
| var ( | |||
| endpoint string | |||
| nodeID string | |||
| ) | |||
| func init() { | |||
| flag.Set("logtostderr", "true") | |||
| } | |||
| func main() { | |||
| flag.CommandLine.Parse([]string{}) | |||
| cmd := &cobra.Command{ | |||
| Use: "rclone", | |||
| Short: "CSI based rclone driver", | |||
| Run: func(cmd *cobra.Command, args []string) { | |||
| handle() | |||
| }, | |||
| } | |||
| cmd.Flags().AddGoFlagSet(flag.CommandLine) | |||
| cmd.PersistentFlags().StringVar(&nodeID, "nodeid", "", "node id") | |||
| cmd.MarkPersistentFlagRequired("nodeid") | |||
| cmd.PersistentFlags().StringVar(&endpoint, "endpoint", "", "CSI endpoint") | |||
| cmd.MarkPersistentFlagRequired("endpoint") | |||
| versionCmd := &cobra.Command{ | |||
| Use: "version", | |||
| Short: "Prints information about this version of csi rclone plugin", | |||
| Run: func(cmd *cobra.Command, args []string) { | |||
| fmt.Printf(`csi-rclone plugin | |||
| Version: %s | |||
| `, rclone.DriverVersion) | |||
| }, | |||
| } | |||
| cmd.AddCommand(versionCmd) | |||
| versionCmd.ResetFlags() | |||
| cmd.ParseFlags(os.Args[1:]) | |||
| if err := cmd.Execute(); err != nil { | |||
| fmt.Fprintf(os.Stderr, "%s", err.Error()) | |||
| os.Exit(1) | |||
| } | |||
| os.Exit(0) | |||
| } | |||
| func handle() { | |||
| d := rclone.NewDriver(nodeID, endpoint) | |||
| d.Run() | |||
| } | |||
| @@ -0,0 +1,66 @@ | |||
| # This YAML file contains RBAC API objects that are necessary to run external | |||
| # CSI attacher for rclone adapter | |||
| apiVersion: v1 | |||
| kind: ServiceAccount | |||
| metadata: | |||
| name: csi-controller-rclone | |||
| namespace: kube-system | |||
| --- | |||
| kind: ClusterRole | |||
| apiVersion: rbac.authorization.k8s.io/v1 | |||
| metadata: | |||
| name: external-controller-rclone | |||
| rules: | |||
| - apiGroups: [""] | |||
| resources: ["persistentvolumes"] | |||
| verbs: ["get", "list", "watch", "update"] | |||
| - apiGroups: [""] | |||
| resources: ["nodes"] | |||
| verbs: ["get", "list", "watch"] | |||
| - apiGroups: ["csi.storage.k8s.io"] | |||
| resources: ["csinodeinfos"] | |||
| verbs: ["get", "list", "watch"] | |||
| - apiGroups: ["storage.k8s.io"] | |||
| resources: ["volumeattachments"] | |||
| verbs: ["get", "list", "watch", "update"] | |||
| --- | |||
| kind: ClusterRoleBinding | |||
| apiVersion: rbac.authorization.k8s.io/v1 | |||
| metadata: | |||
| name: csi-attacher-role-rclone | |||
| subjects: | |||
| - kind: ServiceAccount | |||
| name: csi-controller-rclone | |||
| namespace: kube-system | |||
| roleRef: | |||
| kind: ClusterRole | |||
| name: external-controller-rclone | |||
| apiGroup: rbac.authorization.k8s.io | |||
| --- | |||
| kind: ClusterRole | |||
| apiVersion: rbac.authorization.k8s.io/v1 | |||
| metadata: | |||
| name: csi-cluster-driver-registrar-role | |||
| rules: | |||
| - apiGroups: ["csi.storage.k8s.io"] | |||
| resources: ["csidrivers"] | |||
| verbs: ["create", "delete"] | |||
| - apiGroups: ["apiextensions.k8s.io"] | |||
| resources: ["customresourcedefinitions"] | |||
| verbs: ["create", "list", "watch", "delete"] | |||
| --- | |||
| kind: ClusterRoleBinding | |||
| apiVersion: rbac.authorization.k8s.io/v1 | |||
| metadata: | |||
| name: csi-cluster-driver-registrar-binding | |||
| subjects: | |||
| - kind: ServiceAccount | |||
| name: csi-controller-rclone | |||
| namespace: kube-system | |||
| roleRef: | |||
| kind: ClusterRole | |||
| name: csi-cluster-driver-registrar-role | |||
| apiGroup: rbac.authorization.k8s.io | |||
| @@ -0,0 +1,65 @@ | |||
| # This YAML file contains attacher & csi driver API objects that are necessary | |||
| # to run external CSI attacher for rclone | |||
| kind: StatefulSet | |||
| apiVersion: apps/v1 | |||
| metadata: | |||
| name: csi-controller-rclone | |||
| namespace: kube-system | |||
| spec: | |||
| serviceName: "csi-controller-rclone" | |||
| replicas: 1 | |||
| selector: | |||
| matchLabels: | |||
| app: csi-controller-rclone | |||
| template: | |||
| metadata: | |||
| labels: | |||
| app: csi-controller-rclone | |||
| spec: | |||
| serviceAccountName: csi-controller-rclone | |||
| containers: | |||
| - name: csi-attacher | |||
| image: quay.io/k8scsi/csi-attacher:v1.1.1 | |||
| args: | |||
| - "--v=5" | |||
| - "--csi-address=$(ADDRESS)" | |||
| env: | |||
| - name: ADDRESS | |||
| value: /csi/csi.sock | |||
| imagePullPolicy: "Always" | |||
| volumeMounts: | |||
| - name: socket-dir | |||
| mountPath: /csi | |||
| - name: csi-cluster-driver-registrar | |||
| image: quay.io/k8scsi/csi-cluster-driver-registrar:v1.0.1 | |||
| args: | |||
| - "--v=5" | |||
| - '--pod-info-mount-version="v1"' | |||
| - "--csi-address=$(ADDRESS)" | |||
| env: | |||
| - name: ADDRESS | |||
| value: /csi/csi.sock | |||
| volumeMounts: | |||
| - name: socket-dir | |||
| mountPath: /csi | |||
| - name: rclone | |||
| image: dvcrn/csi-rclone-reloaded:v1.4.0 | |||
| args: | |||
| - "/bin/csi-rclone-plugin" | |||
| - "--nodeid=$(NODE_ID)" | |||
| - "--endpoint=$(CSI_ENDPOINT)" | |||
| env: | |||
| - name: NODE_ID | |||
| valueFrom: | |||
| fieldRef: | |||
| fieldPath: spec.nodeName | |||
| - name: CSI_ENDPOINT | |||
| value: unix://plugin/csi.sock | |||
| imagePullPolicy: "Always" | |||
| volumeMounts: | |||
| - name: socket-dir | |||
| mountPath: /plugin | |||
| volumes: | |||
| - name: socket-dir | |||
| emptyDir: {} | |||
| @@ -0,0 +1,40 @@ | |||
| # This YAML defines all API objects to create RBAC roles for CSI node plugin | |||
| apiVersion: v1 | |||
| kind: ServiceAccount | |||
| metadata: | |||
| name: csi-nodeplugin-rclone | |||
| namespace: kube-system | |||
| --- | |||
| kind: ClusterRole | |||
| apiVersion: rbac.authorization.k8s.io/v1 | |||
| metadata: | |||
| name: csi-nodeplugin-rclone | |||
| rules: | |||
| - apiGroups: [""] | |||
| resources: ["persistentvolumes"] | |||
| verbs: ["get", "list", "watch", "update"] | |||
| - apiGroups: [""] | |||
| resources: ["secrets", "secret"] | |||
| verbs: ["get", "list"] | |||
| - apiGroups: [""] | |||
| resources: ["nodes"] | |||
| verbs: ["get", "list", "watch", "update"] | |||
| - apiGroups: ["storage.k8s.io"] | |||
| resources: ["volumeattachments"] | |||
| verbs: ["get", "list", "watch", "update"] | |||
| - apiGroups: [""] | |||
| resources: ["events"] | |||
| verbs: ["get", "list", "watch", "create", "update", "patch"] | |||
| --- | |||
| kind: ClusterRoleBinding | |||
| apiVersion: rbac.authorization.k8s.io/v1 | |||
| metadata: | |||
| name: csi-nodeplugin-rclone | |||
| subjects: | |||
| - kind: ServiceAccount | |||
| name: csi-nodeplugin-rclone | |||
| namespace: kube-system | |||
| roleRef: | |||
| kind: ClusterRole | |||
| name: csi-nodeplugin-rclone | |||
| apiGroup: rbac.authorization.k8s.io | |||
| @@ -0,0 +1,92 @@ | |||
| # This YAML file contains driver-registrar & csi driver nodeplugin API objects | |||
| # that are necessary to run CSI nodeplugin for rclone | |||
| kind: DaemonSet | |||
| apiVersion: apps/v1 | |||
| metadata: | |||
| name: csi-nodeplugin-rclone | |||
| namespace: kube-system | |||
| spec: | |||
| selector: | |||
| matchLabels: | |||
| app: csi-nodeplugin-rclone | |||
| template: | |||
| metadata: | |||
| labels: | |||
| app: csi-nodeplugin-rclone | |||
| spec: | |||
| serviceAccountName: csi-nodeplugin-rclone | |||
| hostNetwork: true | |||
| dnsPolicy: ClusterFirstWithHostNet | |||
| containers: | |||
| - name: node-driver-registrar | |||
| image: quay.io/k8scsi/csi-node-driver-registrar:v1.1.0 | |||
| lifecycle: | |||
| preStop: | |||
| exec: | |||
| command: | |||
| [ | |||
| "/bin/sh", | |||
| "-c", | |||
| "rm -rf /registration/csi-rclone /registration/csi-rclone-reg.sock", | |||
| ] | |||
| args: | |||
| - --v=5 | |||
| - --csi-address=/plugin/csi.sock | |||
| - --kubelet-registration-path=/var/lib/kubelet/plugins/csi-rclone/csi.sock | |||
| env: | |||
| - name: KUBE_NODE_NAME | |||
| valueFrom: | |||
| fieldRef: | |||
| fieldPath: spec.nodeName | |||
| volumeMounts: | |||
| - name: plugin-dir | |||
| mountPath: /plugin | |||
| - name: registration-dir | |||
| mountPath: /registration | |||
| - name: rclone | |||
| securityContext: | |||
| privileged: true | |||
| capabilities: | |||
| add: ["SYS_ADMIN"] | |||
| allowPrivilegeEscalation: true | |||
| image: dvcrn/csi-rclone-reloaded:v1.4.0 | |||
| args: | |||
| - "/bin/csi-rclone-plugin" | |||
| - "--nodeid=$(NODE_ID)" | |||
| - "--endpoint=$(CSI_ENDPOINT)" | |||
| env: | |||
| - name: NODE_ID | |||
| valueFrom: | |||
| fieldRef: | |||
| fieldPath: spec.nodeName | |||
| - name: CSI_ENDPOINT | |||
| value: unix://plugin/csi.sock | |||
| imagePullPolicy: "Always" | |||
| lifecycle: | |||
| postStart: | |||
| exec: | |||
| command: | |||
| [ | |||
| "/bin/sh", | |||
| "-c", | |||
| "mount -t fuse.rclone | while read -r mount; do umount $(echo $mount | awk '{print $3}') ; done", | |||
| ] | |||
| volumeMounts: | |||
| - name: plugin-dir | |||
| mountPath: /plugin | |||
| - name: pods-mount-dir | |||
| mountPath: /var/lib/kubelet/pods | |||
| mountPropagation: "Bidirectional" | |||
| volumes: | |||
| - name: plugin-dir | |||
| hostPath: | |||
| path: /var/lib/kubelet/plugins/csi-rclone | |||
| type: DirectoryOrCreate | |||
| - name: pods-mount-dir | |||
| hostPath: | |||
| path: /var/lib/kubelet/pods | |||
| type: Directory | |||
| - hostPath: | |||
| path: /var/lib/kubelet/plugins_registry | |||
| type: DirectoryOrCreate | |||
| name: registration-dir | |||
| @@ -0,0 +1,5 @@ | |||
| apiVersion: storage.k8s.io/v1 | |||
| kind: StorageClass | |||
| metadata: | |||
| name: rclone | |||
| provisioner: kubernetes.io/no-provisioner | |||
| @@ -0,0 +1,48 @@ | |||
| # This YAML file contains RBAC API objects that are necessary to run external | |||
| # CSI attacher for rclone adapter | |||
| apiVersion: v1 | |||
| kind: ServiceAccount | |||
| metadata: | |||
| name: csi-controller-rclone | |||
| namespace: kube-system | |||
| --- | |||
| kind: ClusterRole | |||
| apiVersion: rbac.authorization.k8s.io/v1 | |||
| metadata: | |||
| name: external-controller-rclone | |||
| rules: | |||
| - apiGroups: [""] | |||
| resources: ["persistentvolumes"] | |||
| verbs: ["get", "list", "watch", "update"] | |||
| - apiGroups: [""] | |||
| resources: ["nodes"] | |||
| verbs: ["get", "list", "watch"] | |||
| - apiGroups: ["csi.storage.k8s.io"] | |||
| resources: ["csinodeinfos"] | |||
| verbs: ["get", "list", "watch"] | |||
| - apiGroups: ["storage.k8s.io"] | |||
| resources: ["volumeattachments"] | |||
| verbs: ["get", "list", "watch", "update"] | |||
| - apiGroups: ["storage.k8s.io"] | |||
| resources: ["volumeattachments/status"] | |||
| verbs: ["patch"] | |||
| - apiGroups: ["coordination.k8s.io"] | |||
| resources: ["leases"] | |||
| verbs: ["get", "create", "update"] | |||
| - apiGroups: [""] | |||
| resources: ["events"] | |||
| verbs: ["create"] | |||
| --- | |||
| kind: ClusterRoleBinding | |||
| apiVersion: rbac.authorization.k8s.io/v1 | |||
| metadata: | |||
| name: csi-attacher-role-rclone | |||
| subjects: | |||
| - kind: ServiceAccount | |||
| name: csi-controller-rclone | |||
| namespace: kube-system | |||
| roleRef: | |||
| kind: ClusterRole | |||
| name: external-controller-rclone | |||
| apiGroup: rbac.authorization.k8s.io | |||
| @@ -0,0 +1,54 @@ | |||
| # This YAML file contains attacher & csi driver API objects that are necessary | |||
| # to run external CSI attacher for rclone | |||
| kind: StatefulSet | |||
| apiVersion: apps/v1 | |||
| metadata: | |||
| name: csi-controller-rclone | |||
| namespace: kube-system | |||
| spec: | |||
| serviceName: "csi-controller-rclone" | |||
| replicas: 1 | |||
| selector: | |||
| matchLabels: | |||
| app: csi-controller-rclone | |||
| template: | |||
| metadata: | |||
| labels: | |||
| app: csi-controller-rclone | |||
| spec: | |||
| serviceAccountName: csi-controller-rclone | |||
| containers: | |||
| - name: csi-attacher | |||
| image: k8s.gcr.io/sig-storage/csi-attacher:v3.4.0 | |||
| args: | |||
| - "--v=5" | |||
| - "--csi-address=$(ADDRESS)" | |||
| - "--leader-election" | |||
| env: | |||
| - name: ADDRESS | |||
| value: /csi/csi.sock | |||
| imagePullPolicy: "Always" | |||
| volumeMounts: | |||
| - name: socket-dir | |||
| mountPath: /csi | |||
| - name: rclone | |||
| image: dvcrn/csi-rclone-reloaded:v1.4.0 | |||
| args: | |||
| - "/bin/csi-rclone-plugin" | |||
| - "--nodeid=$(NODE_ID)" | |||
| - "--endpoint=$(CSI_ENDPOINT)" | |||
| env: | |||
| - name: NODE_ID | |||
| valueFrom: | |||
| fieldRef: | |||
| fieldPath: spec.nodeName | |||
| - name: CSI_ENDPOINT | |||
| value: unix://plugin/csi.sock | |||
| imagePullPolicy: "Always" | |||
| volumeMounts: | |||
| - name: socket-dir | |||
| mountPath: /plugin | |||
| volumes: | |||
| - name: socket-dir | |||
| emptyDir: {} | |||
| @@ -0,0 +1,8 @@ | |||
| # this should be deregistered once the controller stops | |||
| apiVersion: storage.k8s.io/v1 | |||
| kind: CSIDriver | |||
| metadata: | |||
| name: csi-rclone | |||
| spec: | |||
| attachRequired: true | |||
| podInfoOnMount: false # are we sure about this? | |||
| @@ -0,0 +1,40 @@ | |||
| # This YAML defines all API objects to create RBAC roles for CSI node plugin | |||
| apiVersion: v1 | |||
| kind: ServiceAccount | |||
| metadata: | |||
| name: csi-nodeplugin-rclone | |||
| namespace: kube-system | |||
| --- | |||
| kind: ClusterRole | |||
| apiVersion: rbac.authorization.k8s.io/v1 | |||
| metadata: | |||
| name: csi-nodeplugin-rclone | |||
| rules: | |||
| - apiGroups: [""] | |||
| resources: ["persistentvolumes"] | |||
| verbs: ["get", "list", "watch", "update"] | |||
| - apiGroups: [""] | |||
| resources: ["secrets", "secret"] | |||
| verbs: ["get", "list"] | |||
| - apiGroups: [""] | |||
| resources: ["nodes"] | |||
| verbs: ["get", "list", "watch", "update"] | |||
| - apiGroups: ["storage.k8s.io"] | |||
| resources: ["volumeattachments"] | |||
| verbs: ["get", "list", "watch", "update"] | |||
| - apiGroups: [""] | |||
| resources: ["events"] | |||
| verbs: ["get", "list", "watch", "create", "update", "patch"] | |||
| --- | |||
| kind: ClusterRoleBinding | |||
| apiVersion: rbac.authorization.k8s.io/v1 | |||
| metadata: | |||
| name: csi-nodeplugin-rclone | |||
| subjects: | |||
| - kind: ServiceAccount | |||
| name: csi-nodeplugin-rclone | |||
| namespace: kube-system | |||
| roleRef: | |||
| kind: ClusterRole | |||
| name: csi-nodeplugin-rclone | |||
| apiGroup: rbac.authorization.k8s.io | |||
| @@ -0,0 +1,92 @@ | |||
| # This YAML file contains driver-registrar & csi driver nodeplugin API objects | |||
| # that are necessary to run CSI nodeplugin for rclone | |||
| kind: DaemonSet | |||
| apiVersion: apps/v1 | |||
| metadata: | |||
| name: csi-nodeplugin-rclone | |||
| namespace: kube-system | |||
| spec: | |||
| selector: | |||
| matchLabels: | |||
| app: csi-nodeplugin-rclone | |||
| template: | |||
| metadata: | |||
| labels: | |||
| app: csi-nodeplugin-rclone | |||
| spec: | |||
| serviceAccountName: csi-nodeplugin-rclone | |||
| hostNetwork: true | |||
| dnsPolicy: ClusterFirstWithHostNet | |||
| containers: | |||
| - name: node-driver-registrar | |||
| image: k8s.gcr.io/sig-storage/csi-node-driver-registrar:v2.4.0 | |||
| lifecycle: | |||
| preStop: | |||
| exec: | |||
| command: | |||
| [ | |||
| "/bin/sh", | |||
| "-c", | |||
| "rm -rf /registration/csi-rclone /registration/csi-rclone-reg.sock", | |||
| ] | |||
| args: | |||
| - --v=5 | |||
| - --csi-address=/plugin/csi.sock | |||
| - --kubelet-registration-path=/var/lib/kubelet/plugins/csi-rclone/csi.sock | |||
| env: | |||
| - name: KUBE_NODE_NAME | |||
| valueFrom: | |||
| fieldRef: | |||
| fieldPath: spec.nodeName | |||
| volumeMounts: | |||
| - name: plugin-dir | |||
| mountPath: /plugin | |||
| - name: registration-dir | |||
| mountPath: /registration | |||
| - name: rclone | |||
| securityContext: | |||
| privileged: true | |||
| capabilities: | |||
| add: ["SYS_ADMIN"] | |||
| allowPrivilegeEscalation: true | |||
| image: dvcrn/csi-rclone-reloaded:v1.4.0 | |||
| args: | |||
| - "/bin/csi-rclone-plugin" | |||
| - "--nodeid=$(NODE_ID)" | |||
| - "--endpoint=$(CSI_ENDPOINT)" | |||
| env: | |||
| - name: NODE_ID | |||
| valueFrom: | |||
| fieldRef: | |||
| fieldPath: spec.nodeName | |||
| - name: CSI_ENDPOINT | |||
| value: unix://plugin/csi.sock | |||
| imagePullPolicy: "Always" | |||
| lifecycle: | |||
| postStart: | |||
| exec: | |||
| command: | |||
| [ | |||
| "/bin/sh", | |||
| "-c", | |||
| "mount -t fuse.rclone | while read -r mount; do umount $(echo $mount | awk '{print $3}') ; done", | |||
| ] | |||
| volumeMounts: | |||
| - name: plugin-dir | |||
| mountPath: /plugin | |||
| - name: pods-mount-dir | |||
| mountPath: /var/lib/kubelet/pods | |||
| mountPropagation: "Bidirectional" | |||
| volumes: | |||
| - name: plugin-dir | |||
| hostPath: | |||
| path: /var/lib/kubelet/plugins/csi-rclone | |||
| type: DirectoryOrCreate | |||
| - name: pods-mount-dir | |||
| hostPath: | |||
| path: /var/lib/kubelet/pods | |||
| type: Directory | |||
| - hostPath: | |||
| path: /var/lib/kubelet/plugins_registry | |||
| type: DirectoryOrCreate | |||
| name: registration-dir | |||
| @@ -0,0 +1,5 @@ | |||
| apiVersion: storage.k8s.io/v1 | |||
| kind: StorageClass | |||
| metadata: | |||
| name: rclone | |||
| provisioner: kubernetes.io/no-provisioner | |||
| @@ -0,0 +1,72 @@ | |||
| apiVersion: v1 | |||
| kind: PersistentVolume | |||
| metadata: | |||
| name: data-rclone-example | |||
| labels: | |||
| name: data-rclone-example | |||
| spec: | |||
| accessModes: | |||
| - ReadWriteMany | |||
| capacity: | |||
| storage: 10Gi | |||
| storageClassName: rclone | |||
| csi: | |||
| driver: csi-rclone | |||
| volumeHandle: data-id | |||
| volumeAttributes: | |||
| remote: "s3" | |||
| remotePath: "projectname/pvname" | |||
| s3-provider: "Minio" | |||
| s3-endpoint: "http://minio.minio:9000" | |||
| s3-access-key-id: "ACCESS_KEY_ID" | |||
| s3-secret-access-key: "SECRET_ACCESS_KEY" | |||
| --- | |||
| apiVersion: v1 | |||
| kind: PersistentVolumeClaim | |||
| metadata: | |||
| name: data-rclone-example | |||
| spec: | |||
| accessModes: | |||
| - ReadWriteMany | |||
| resources: | |||
| requests: | |||
| storage: 10Gi | |||
| storageClassName: rclone | |||
| selector: | |||
| matchLabels: | |||
| name: data-rclone-example | |||
| --- | |||
| apiVersion: v1 | |||
| kind: Pod | |||
| metadata: | |||
| name: nginx-example | |||
| labels: | |||
| run: nginx-example | |||
| spec: | |||
| containers: | |||
| - image: nginx | |||
| imagePullPolicy: Always | |||
| name: nginx-example | |||
| ports: | |||
| - containerPort: 80 | |||
| protocol: TCP | |||
| volumeMounts: | |||
| - mountPath: /usr/share/nginx/html | |||
| name: data-rclone-example | |||
| volumes: | |||
| - name: data-rclone-example | |||
| persistentVolumeClaim: | |||
| claimName: data-rclone-example | |||
| --- | |||
| apiVersion: v1 | |||
| kind: Service | |||
| metadata: | |||
| name: nginx-example | |||
| labels: | |||
| run: nginx-example | |||
| spec: | |||
| ports: | |||
| - port: 80 | |||
| protocol: TCP | |||
| selector: | |||
| run: nginx-example | |||
| @@ -0,0 +1,13 @@ | |||
| apiVersion: v1 | |||
| kind: Secret | |||
| metadata: | |||
| name: rclone-secret | |||
| namespace: kube-system | |||
| type: Opaque | |||
| stringData: | |||
| remote: "s3" | |||
| remotePath: "projectname" | |||
| s3-provider: "Minio" | |||
| s3-endpoint: "http://minio.munio:9000" | |||
| s3-access-key-id: "ACCESS_KEY_ID" | |||
| s3-secret-access-key: "SECRET_ACCESS_KEY" | |||
| @@ -0,0 +1,16 @@ | |||
| apiVersion: v1 | |||
| kind: Secret | |||
| metadata: | |||
| name: rclone-secret | |||
| namespace: kube-system | |||
| type: Opaque | |||
| stringData: | |||
| remote: "my-s3" | |||
| remotePath: "projectname" | |||
| configData: | | |||
| [my-s3] | |||
| type = s3 | |||
| provider = Minio | |||
| access_key_id = ACCESS_KEY_ID | |||
| secret_access_key = SECRET_ACCESS_KEY | |||
| endpoint = http://minio-release.default:9000 | |||
| @@ -0,0 +1,53 @@ | |||
| module github.com/wunderio/csi-rclone | |||
| go 1.15 | |||
| require ( | |||
| github.com/container-storage-interface/spec v1.0.0 | |||
| github.com/davecgh/go-spew v1.1.1 // indirect | |||
| github.com/docker/distribution v2.7.1+incompatible // indirect | |||
| github.com/gogo/protobuf v1.2.1 // indirect | |||
| github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b | |||
| github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef // indirect | |||
| github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c // indirect | |||
| github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf // indirect | |||
| github.com/googleapis/gnostic v0.2.0 // indirect | |||
| github.com/gregjones/httpcache v0.0.0-20190212212710-3befbb6ad0cc // indirect | |||
| github.com/hashicorp/golang-lru v0.5.0 // indirect | |||
| github.com/imdario/mergo v0.3.7 // indirect | |||
| github.com/inconshreveable/mousetrap v1.0.0 // indirect | |||
| github.com/json-iterator/go v1.1.5 // indirect | |||
| github.com/kubernetes-csi/csi-lib-utils v0.3.1 // indirect | |||
| github.com/kubernetes-csi/drivers v1.0.2 | |||
| github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect | |||
| github.com/modern-go/reflect2 v1.0.1 // indirect | |||
| github.com/onsi/ginkgo v1.7.0 // indirect | |||
| github.com/onsi/gomega v1.4.3 // indirect | |||
| github.com/opencontainers/go-digest v1.0.0-rc1 // indirect | |||
| github.com/pborman/uuid v1.2.0 // indirect | |||
| github.com/peterbourgon/diskv v2.0.1+incompatible // indirect | |||
| github.com/prometheus/client_golang v0.9.2 // indirect | |||
| github.com/spf13/afero v1.2.1 // indirect | |||
| github.com/spf13/cobra v0.0.3 | |||
| github.com/spf13/pflag v1.0.3 // indirect | |||
| github.com/stretchr/objx v0.1.1 // indirect | |||
| github.com/stretchr/testify v1.3.0 // indirect | |||
| golang.org/x/crypto v0.0.0-20190222235706-ffb98f73852f // indirect | |||
| golang.org/x/net v0.0.0-20190213061140-3a22650c66bd | |||
| golang.org/x/time v0.0.0-20181108054448-85acf8d2951c // indirect | |||
| google.golang.org/grpc v1.18.0 | |||
| gopkg.in/inf.v0 v0.9.1 // indirect | |||
| gopkg.in/yaml.v2 v2.2.2 // indirect | |||
| k8s.io/api v0.0.0-20190111032252-67edc246be36 | |||
| k8s.io/apiextensions-apiserver v0.0.0-20190111034747-7d26de67f177 // indirect | |||
| k8s.io/apimachinery v0.0.0-20181127025237-2b1284ed4c93 | |||
| k8s.io/apiserver v0.0.0-20190111033246-d50e9ac5404f // indirect | |||
| k8s.io/client-go v10.0.0+incompatible | |||
| k8s.io/cloud-provider v0.0.0-20190223141949-e954a34baf43 // indirect | |||
| k8s.io/csi-api v0.0.0-20190223140843-b4e64dae0b19 // indirect | |||
| k8s.io/klog v0.2.0 | |||
| k8s.io/kube-openapi v0.0.0-20190222203931-aa8624f5a2df // indirect | |||
| k8s.io/kubernetes v1.13.2 | |||
| k8s.io/utils v0.0.0-20190221042446-c2654d5206da // indirect | |||
| sigs.k8s.io/yaml v1.1.0 // indirect | |||
| ) | |||
| @@ -0,0 +1,155 @@ | |||
| cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= | |||
| github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973 h1:xJ4a3vCFaGF/jqvzLMYoU8P317H5OQ+Via4RmuPwCS0= | |||
| github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= | |||
| github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= | |||
| github.com/container-storage-interface/spec v1.0.0 h1:3DyXuJgf9MU6kyULESegQUmozsSxhpyrrv9u5bfwA3E= | |||
| github.com/container-storage-interface/spec v1.0.0/go.mod h1:6URME8mwIBbpVyZV93Ce5St17xBiQJQY67NDsuohiy4= | |||
| github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= | |||
| github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | |||
| github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= | |||
| github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | |||
| github.com/docker/distribution v2.7.1+incompatible h1:a5mlkVzth6W5A4fOsS3D2EO5BUmsJpcB+cRlLU7cSug= | |||
| github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= | |||
| 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/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-20190129154638-5b532d6fd5ef h1:veQD95Isof8w9/WXiA+pa3tz3fJXkt5B7QaRBrM62gk= | |||
| github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= | |||
| github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= | |||
| github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM= | |||
| github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= | |||
| github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c h1:964Od4U6p2jUkFxvCydnIczKteheJEzHRToSGK3Bnlw= | |||
| github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= | |||
| github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf h1:+RRA9JqSOZFfKrOeqr2z77+8R2RKyh8PG66dcu1V0ck= | |||
| github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI= | |||
| github.com/google/uuid v1.0.0 h1:b4Gk+7WdP/d3HZH8EJsZpvV7EtDOgaZLtnaNGIu1adA= | |||
| github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= | |||
| github.com/googleapis/gnostic v0.2.0 h1:l6N3VoaVzTncYYW+9yOz2LJJammFZGBO13sqgEhpy9g= | |||
| github.com/googleapis/gnostic v0.2.0/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= | |||
| github.com/gregjones/httpcache v0.0.0-20190212212710-3befbb6ad0cc h1:f8eY6cV/x1x+HLjOp4r72s/31/V2aTUtg5oKRRPf8/Q= | |||
| github.com/gregjones/httpcache v0.0.0-20190212212710-3befbb6ad0cc/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= | |||
| github.com/hashicorp/golang-lru v0.5.0 h1:CL2msUPvZTLb5O648aiLNJw3hnBxN2+1Jq8rCOH9wdo= | |||
| github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= | |||
| github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= | |||
| github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= | |||
| github.com/imdario/mergo v0.3.7 h1:Y+UAYTZ7gDEuOfhxKWy+dvb5dRQ6rJjFSdX2HZY1/gI= | |||
| github.com/imdario/mergo v0.3.7/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= | |||
| github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= | |||
| github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= | |||
| github.com/json-iterator/go v1.1.5 h1:gL2yXlmiIo4+t+y32d4WGwOjKGYcGOuyrg46vadswDE= | |||
| github.com/json-iterator/go v1.1.5/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= | |||
| github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= | |||
| github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= | |||
| github.com/kubernetes-csi/csi-lib-utils v0.3.1 h1:EPE7WgaMx8XwfBIdxJns3B87V0x8TN1mWoZOVNliUaM= | |||
| github.com/kubernetes-csi/csi-lib-utils v0.3.1/go.mod h1:GVmlUmxZ+SUjVLXicRFjqWUUvWez0g0Y78zNV9t7KfQ= | |||
| github.com/kubernetes-csi/drivers v1.0.2 h1:kaEAMfo+W5YFr23yedBIY+NGnNjr6/PbPzx7N4GYgiQ= | |||
| github.com/kubernetes-csi/drivers v1.0.2/go.mod h1:V6rHbbSLCZGaQoIZ8MkyDtoXtcKXZM0F7N3bkloDCOY= | |||
| github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= | |||
| github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= | |||
| github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= | |||
| github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= | |||
| github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI= | |||
| github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= | |||
| 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 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 h1:WzifXhOVOEOuFYOJAW6aQqW0TooG2iki3E3Ii+WN7gQ= | |||
| github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= | |||
| github.com/pborman/uuid v1.2.0 h1:J7Q5mO4ysT1dv8hyrUGHb9+ooztCXu1D8MY8DZYsu3g= | |||
| github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= | |||
| github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI= | |||
| github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= | |||
| 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.9.2 h1:awm861/B8OKDd2I/6o1dy3ra4BamzKhYOiGItCeZ740= | |||
| github.com/prometheus/client_golang v0.9.2/go.mod h1:OsXs2jCmiKlQ1lTBmv21f2mNfw4xf/QclQDMrYNZzcM= | |||
| github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910 h1:idejC8f05m9MGOsuEi1ATq9shN03HrxNkD/luQvxCv8= | |||
| github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= | |||
| github.com/prometheus/common v0.0.0-20181126121408-4724e9255275 h1:PnBWHBf+6L0jOqq0gIVUe6Yk0/QMZ640k6NvkxcBf+8= | |||
| github.com/prometheus/common v0.0.0-20181126121408-4724e9255275/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= | |||
| github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a h1:9a8MnZMP0X2nLJdBg+pBmGgkJlSaKC2KaQmTCk1XDtE= | |||
| github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= | |||
| github.com/spf13/afero v1.2.1 h1:qgMbHoJbPbw579P+1zVY+6n4nIFuIchaIjzZ/I/Yq8M= | |||
| github.com/spf13/afero v1.2.1/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= | |||
| github.com/spf13/cobra v0.0.3 h1:ZlrZ4XsMRm04Fr5pSFxBgfND2EBVa1nLpiy1stUsX/8= | |||
| github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= | |||
| github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg= | |||
| github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= | |||
| github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4= | |||
| github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= | |||
| github.com/stretchr/objx v0.1.1 h1:2vfRuCMp5sSVIDSqO8oNnWJq7mPa6KVP3iPIwFBuy8A= | |||
| github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= | |||
| github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= | |||
| github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= | |||
| golang.org/x/crypto v0.0.0-20190222235706-ffb98f73852f h1:qWFY9ZxP3tfI37wYIs/MnIAqK0vlXp1xnYEa5HxFSSY= | |||
| golang.org/x/crypto v0.0.0-20190222235706-ffb98f73852f/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= | |||
| golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= | |||
| golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= | |||
| golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= | |||
| golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= | |||
| golang.org/x/net v0.0.0-20190213061140-3a22650c66bd h1:HuTn7WObtcDo9uEEU7rEqL0jYthdXAmZ6PP+meazmaU= | |||
| golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= | |||
| golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be h1:vEDujvNQGv4jgYKudGeI/+DAX4Jffq6hpD55MmoEvKs= | |||
| golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= | |||
| golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f h1:wMNYb4v58l5UBM7MYRLPG6ZhfOqbKu7X5eyFl8ZhKvA= | |||
| golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | |||
| golang.org/x/sync v0.0.0-20181108010431-42b317875d0f h1:Bl/8QSvNqXvPGPGXa2z5xUTmV7VDcZyvRZ+QQXkXTZQ= | |||
| golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | |||
| golang.org/x/sys v0.0.0-20180830151530-49385e6e1522 h1:Ve1ORMCxvRmSXBwJK+t3Oy+V2vRW2OetUQBq4rJIkZE= | |||
| golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | |||
| golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e h1:o3PsSEY8E4eXWkXrIP9YJALUkVZqzHJT5DOasTyn8Vs= | |||
| golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | |||
| golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= | |||
| golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= | |||
| golang.org/x/time v0.0.0-20181108054448-85acf8d2951c h1:fqgJT0MGcGpPgpWU7VRdRjuArfcOvC4AoJmILihzhDg= | |||
| golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= | |||
| golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= | |||
| golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= | |||
| google.golang.org/appengine v1.1.0 h1:igQkv0AAhEIvTEpD5LIpAfav2eeVO9HBTjvKHVJPRSs= | |||
| google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= | |||
| google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8 h1:Nw54tB0rB7hY/N0NQvRW8DG4Yk3Q6T9cu9RcFQDu1tc= | |||
| google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= | |||
| google.golang.org/grpc v1.18.0 h1:IZl7mfBGfbhYx2p2rKRtYgDFw6SBz+kclmxYrCksPPA= | |||
| google.golang.org/grpc v1.18.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= | |||
| gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= | |||
| gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= | |||
| 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.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= | |||
| gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= | |||
| 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.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE= | |||
| gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= | |||
| gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= | |||
| gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= | |||
| honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= | |||
| k8s.io/api v0.0.0-20190111032252-67edc246be36 h1:XrFGq/4TDgOxYOxtNROTyp2ASjHjBIITdk/+aJD+zyY= | |||
| k8s.io/api v0.0.0-20190111032252-67edc246be36/go.mod h1:iuAfoD4hCxJ8Onx9kaTIt30j7jUFS00AXQi6QMi99vA= | |||
| k8s.io/apiextensions-apiserver v0.0.0-20190111034747-7d26de67f177 h1:jtIDnyMLAy15hJmcjRMq3ia0LwHkQBLVo1IRXdDMS38= | |||
| k8s.io/apiextensions-apiserver v0.0.0-20190111034747-7d26de67f177/go.mod h1:IxkesAMoaCRoLrPJdZNZUQp9NfZnzqaVzLhb2VEQzXE= | |||
| k8s.io/apimachinery v0.0.0-20181127025237-2b1284ed4c93 h1:tT6oQBi0qwLbbZSfDkdIsb23EwaLY85hoAV4SpXfdao= | |||
| k8s.io/apimachinery v0.0.0-20181127025237-2b1284ed4c93/go.mod h1:ccL7Eh7zubPUSh9A3USN90/OzHNSVN6zxzde07TDCL0= | |||
| k8s.io/apiserver v0.0.0-20190111033246-d50e9ac5404f h1:jOhsBtH52EgxnCNJrCuToXFfQtb3nQDoBPzItfPmSsI= | |||
| k8s.io/apiserver v0.0.0-20190111033246-d50e9ac5404f/go.mod h1:6bqaTSOSJavUIXUtfaR9Os9JtTCm8ZqH2SUl2S60C4w= | |||
| k8s.io/client-go v10.0.0+incompatible h1:F1IqCqw7oMBzDkqlcBymRq1450wD0eNqLE9jzUrIi34= | |||
| k8s.io/client-go v10.0.0+incompatible/go.mod h1:7vJpHMYJwNQCWgzmNV+VYUl1zCObLyodBc8nIyt8L5s= | |||
| k8s.io/cloud-provider v0.0.0-20190223141949-e954a34baf43 h1:JRJFItrctyI8kGWwa9sqZ34eX84t3/D5fO119I4x3Cw= | |||
| k8s.io/cloud-provider v0.0.0-20190223141949-e954a34baf43/go.mod h1:LlIffnLBu+GG7d4ppPzC8UnA1Ex8S+ntmSRVsnr7Xy4= | |||
| k8s.io/csi-api v0.0.0-20190223140843-b4e64dae0b19 h1:RmLaI0waIeLhtsOQl8ekcCgbHRscA3+nQGSFf3qkbeA= | |||
| k8s.io/csi-api v0.0.0-20190223140843-b4e64dae0b19/go.mod h1:GH854hXKH+vaEO06X/DMiE/o3rVO1aw8dXJJpP7awjA= | |||
| k8s.io/klog v0.2.0 h1:0ElL0OHzF3N+OhoJTL0uca20SxtYt4X4+bzHeqrB83c= | |||
| k8s.io/klog v0.2.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= | |||
| k8s.io/kube-openapi v0.0.0-20190222203931-aa8624f5a2df h1:htvtrqyyVqMSYjR5bmmLx7RVu2+Rp5o1RVOc51x2YrQ= | |||
| k8s.io/kube-openapi v0.0.0-20190222203931-aa8624f5a2df/go.mod h1:BXM9ceUBTj2QnfH2MK1odQs778ajze1RxcmP6S8RVVc= | |||
| k8s.io/kubernetes v1.13.2 h1:rBz6dubDY4bfv85G6zo04v9G5wniTxvBI9yQ/QxJS3g= | |||
| k8s.io/kubernetes v1.13.2/go.mod h1:ocZa8+6APFNC2tX1DZASIbocyYT5jHzqFVsY5aoB7Jk= | |||
| k8s.io/utils v0.0.0-20190221042446-c2654d5206da h1:ElyM7RPonbKnQqOcw7dG2IK5uvQQn3b/WPHqD5mBvP4= | |||
| k8s.io/utils v0.0.0-20190221042446-c2654d5206da/go.mod h1:8k8uAuAQ0rXslZKaEWd0c3oVhZz7sSzSiPnVZayjIX0= | |||
| sigs.k8s.io/yaml v1.1.0 h1:4A07+ZFc2wgJwo8YNlQpr1rVlgUDlxXHhPJciaPY5gs= | |||
| sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= | |||
| @@ -0,0 +1,170 @@ | |||
| #!/usr/bin/env bash | |||
| # error codes | |||
| # 0 - exited without problems | |||
| # 1 - parameters not supported were used or some unexpected error occurred | |||
| # 2 - OS not supported by this script | |||
| # 3 - installed version of rclone is up to date | |||
| # 4 - supported unzip tools are not available | |||
| set -e | |||
| #when adding a tool to the list make sure to also add its corresponding command further in the script | |||
| unzip_tools_list=('unzip' '7z' 'busybox') | |||
| usage() { echo "Usage: sudo -v ; sudo bash install-dm.sh" 1>&2; exit 1; } | |||
| #check for beta flag | |||
| if [ -n "$1" ] && [ "$1" != "beta" ]; then | |||
| usage | |||
| fi | |||
| #create tmp directory and move to it with macOS compatibility fallback | |||
| tmp_dir=$(mktemp -d 2>/dev/null || mktemp -d -t 'rclone-install.XXXXXXXXXX') | |||
| cd "$tmp_dir" | |||
| #make sure unzip tool is available and choose one to work with | |||
| set +e | |||
| for tool in ${unzip_tools_list[*]}; do | |||
| trash=$(hash "$tool" 2>>errors) | |||
| if [ "$?" -eq 0 ]; then | |||
| unzip_tool="$tool" | |||
| break | |||
| fi | |||
| done | |||
| set -e | |||
| # exit if no unzip tools available | |||
| if [ -z "$unzip_tool" ]; then | |||
| printf "\nNone of the supported tools for extracting zip archives (${unzip_tools_list[*]}) were found. " | |||
| printf "Please install one of them and try again.\n\n" | |||
| exit 4 | |||
| fi | |||
| # Make sure we don't create a root owned .config/rclone directory #2127 | |||
| export XDG_CONFIG_HOME=config | |||
| #detect the platform | |||
| OS="$(uname)" | |||
| case $OS in | |||
| Linux) | |||
| OS='linux' | |||
| ;; | |||
| FreeBSD) | |||
| OS='freebsd' | |||
| ;; | |||
| NetBSD) | |||
| OS='netbsd' | |||
| ;; | |||
| OpenBSD) | |||
| OS='openbsd' | |||
| ;; | |||
| Darwin) | |||
| OS='osx' | |||
| binTgtDir=/usr/local/bin | |||
| man1TgtDir=/usr/local/share/man/man1 | |||
| ;; | |||
| SunOS) | |||
| OS='solaris' | |||
| echo 'OS not supported' | |||
| exit 2 | |||
| ;; | |||
| *) | |||
| echo 'OS not supported' | |||
| exit 2 | |||
| ;; | |||
| esac | |||
| OS_type="$(uname -m)" | |||
| case "$OS_type" in | |||
| x86_64|amd64) | |||
| OS_type='amd64' | |||
| ;; | |||
| i?86|x86) | |||
| OS_type='386' | |||
| ;; | |||
| aarch64|arm64) | |||
| OS_type='arm64' | |||
| ;; | |||
| arm*) | |||
| OS_type='arm' | |||
| ;; | |||
| *) | |||
| echo 'OS type not supported' | |||
| exit 2 | |||
| ;; | |||
| esac | |||
| #download and unzip | |||
| rclone_zip="/tmp/rclone-build/rclone-current-${OS}-${OS_type}.zip" | |||
| unzip_dir="tmp_unzip_dir_for_rclone" | |||
| # there should be an entry in this switch for each element of unzip_tools_list | |||
| case "$unzip_tool" in | |||
| 'unzip') | |||
| unzip -a "$rclone_zip" -d "$unzip_dir" | |||
| ;; | |||
| '7z') | |||
| 7z x "$rclone_zip" "-o$unzip_dir" | |||
| ;; | |||
| 'busybox') | |||
| mkdir -p "$unzip_dir" | |||
| busybox unzip "$rclone_zip" -d "$unzip_dir" | |||
| ;; | |||
| esac | |||
| cd $unzip_dir/* | |||
| #mounting rclone to environment | |||
| case "$OS" in | |||
| 'linux') | |||
| #binary | |||
| cp rclone /usr/bin/rclone.new | |||
| chmod 755 /usr/bin/rclone.new | |||
| chown root:root /usr/bin/rclone.new | |||
| mv /usr/bin/rclone.new /usr/bin/rclone | |||
| #manual | |||
| if ! [ -x "$(command -v mandb)" ]; then | |||
| echo 'mandb not found. The rclone man docs will not be installed.' | |||
| else | |||
| mkdir -p /usr/local/share/man/man1 | |||
| cp rclone.1 /usr/local/share/man/man1/ | |||
| mandb | |||
| fi | |||
| ;; | |||
| 'freebsd'|'openbsd'|'netbsd') | |||
| #binary | |||
| cp rclone /usr/bin/rclone.new | |||
| chown root:wheel /usr/bin/rclone.new | |||
| mv /usr/bin/rclone.new /usr/bin/rclone | |||
| #manual | |||
| mkdir -p /usr/local/man/man1 | |||
| cp rclone.1 /usr/local/man/man1/ | |||
| makewhatis | |||
| ;; | |||
| 'osx') | |||
| #binary | |||
| mkdir -m 0555 -p ${binTgtDir} | |||
| cp rclone ${binTgtDir}/rclone.new | |||
| mv ${binTgtDir}/rclone.new ${binTgtDir}/rclone | |||
| chmod a=x ${binTgtDir}/rclone | |||
| #manual | |||
| mkdir -m 0555 -p ${man1TgtDir} | |||
| cp rclone.1 ${man1TgtDir} | |||
| chmod a=r ${man1TgtDir}/rclone.1 | |||
| ;; | |||
| *) | |||
| echo 'OS not supported' | |||
| exit 2 | |||
| esac | |||
| #update version variable post install | |||
| version=$(rclone --version 2>>errors | head -n 1) | |||
| printf "\n${version} has successfully installed." | |||
| printf '\nNow run "rclone config" for setup. Check https://rclone.org/docs/ for more details.\n\n' | |||
| exit 0 | |||
| @@ -0,0 +1,50 @@ | |||
| package rclone | |||
| import ( | |||
| "github.com/container-storage-interface/spec/lib/go/csi" | |||
| csicommon "github.com/kubernetes-csi/drivers/pkg/csi-common" | |||
| "k8s.io/klog" | |||
| ) | |||
| type driver struct { | |||
| csiDriver *csicommon.CSIDriver | |||
| endpoint string | |||
| ns *nodeServer | |||
| cap []*csi.VolumeCapability_AccessMode | |||
| cscap []*csi.ControllerServiceCapability | |||
| } | |||
| var ( | |||
| DriverName = "csi-rclone" | |||
| DriverVersion = "latest" | |||
| ) | |||
| func NewDriver(nodeID, endpoint string) *driver { | |||
| klog.Infof("Starting new %s driver in version %s", DriverName, DriverVersion) | |||
| d := &driver{} | |||
| d.endpoint = endpoint | |||
| d.csiDriver = csicommon.NewCSIDriver(DriverName, DriverVersion, nodeID) | |||
| d.csiDriver.AddVolumeCapabilityAccessModes([]csi.VolumeCapability_AccessMode_Mode{csi.VolumeCapability_AccessMode_MULTI_NODE_MULTI_WRITER}) | |||
| d.csiDriver.AddControllerServiceCapabilities([]csi.ControllerServiceCapability_RPC_Type{csi.ControllerServiceCapability_RPC_UNKNOWN}) | |||
| return d | |||
| } | |||
| func NewNodeServer(d *driver) *nodeServer { | |||
| return &nodeServer{ | |||
| DefaultNodeServer: csicommon.NewDefaultNodeServer(d.csiDriver), | |||
| } | |||
| } | |||
| func (d *driver) Run() { | |||
| s := csicommon.NewNonBlockingGRPCServer() | |||
| s.Start(d.endpoint, | |||
| csicommon.NewDefaultIdentityServer(d.csiDriver), | |||
| csicommon.NewDefaultControllerServer(d.csiDriver), | |||
| NewNodeServer(d)) | |||
| s.Wait() | |||
| } | |||
| @@ -0,0 +1,25 @@ | |||
| package rclone | |||
| import ( | |||
| "k8s.io/client-go/kubernetes" | |||
| "k8s.io/client-go/rest" | |||
| ) | |||
| var clientset *kubernetes.Clientset | |||
| func GetK8sClient() (*kubernetes.Clientset, error) { | |||
| if clientset != nil { | |||
| return clientset, nil | |||
| } | |||
| config, e := rest.InClusterConfig() | |||
| if e != nil { | |||
| return nil, e | |||
| } | |||
| clientset, e = kubernetes.NewForConfig(config) | |||
| if e != nil { | |||
| return nil, e | |||
| } | |||
| return clientset, nil | |||
| } | |||
| @@ -0,0 +1,326 @@ | |||
| package rclone | |||
| import ( | |||
| "fmt" | |||
| "io/ioutil" | |||
| "os" | |||
| "os/exec" | |||
| "strings" | |||
| v1 "k8s.io/api/core/v1" | |||
| metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | |||
| "k8s.io/klog" | |||
| "github.com/container-storage-interface/spec/lib/go/csi" | |||
| "golang.org/x/net/context" | |||
| "google.golang.org/grpc/codes" | |||
| "google.golang.org/grpc/status" | |||
| "k8s.io/client-go/tools/clientcmd" | |||
| "k8s.io/kubernetes/pkg/util/mount" | |||
| "k8s.io/kubernetes/pkg/volume/util" | |||
| csicommon "github.com/kubernetes-csi/drivers/pkg/csi-common" | |||
| ) | |||
| type nodeServer struct { | |||
| *csicommon.DefaultNodeServer | |||
| mounter *mount.SafeFormatAndMount | |||
| } | |||
| type mountPoint struct { | |||
| VolumeId string | |||
| MountPath string | |||
| } | |||
| func (ns *nodeServer) NodePublishVolume(ctx context.Context, req *csi.NodePublishVolumeRequest) (*csi.NodePublishVolumeResponse, error) { | |||
| klog.Infof("NodePublishVolume: called with args %+v", *req) | |||
| targetPath := req.GetTargetPath() | |||
| notMnt, err := mount.New("").IsLikelyNotMountPoint(targetPath) | |||
| if err != nil { | |||
| if os.IsNotExist(err) { | |||
| if err := os.MkdirAll(targetPath, 0750); err != nil { | |||
| return nil, status.Error(codes.Internal, err.Error()) | |||
| } | |||
| notMnt = true | |||
| } else { | |||
| return nil, status.Error(codes.Internal, err.Error()) | |||
| } | |||
| } | |||
| if !notMnt { | |||
| // testing original mount point, make sure the mount link is valid | |||
| if _, err := ioutil.ReadDir(targetPath); err == nil { | |||
| klog.Infof("already mounted to target %s", targetPath) | |||
| return &csi.NodePublishVolumeResponse{}, nil | |||
| } | |||
| // todo: mount link is invalid, now unmount and remount later (built-in functionality) | |||
| klog.Warningf("ReadDir %s failed with %v, unmount this directory", targetPath, err) | |||
| ns.mounter = &mount.SafeFormatAndMount{ | |||
| Interface: mount.New(""), | |||
| Exec: mount.NewOsExec(), | |||
| } | |||
| if err := ns.mounter.Unmount(targetPath); err != nil { | |||
| klog.Errorf("Unmount directory %s failed with %v", targetPath, err) | |||
| return nil, err | |||
| } | |||
| } | |||
| mountOptions := req.GetVolumeCapability().GetMount().GetMountFlags() | |||
| if req.GetReadonly() { | |||
| mountOptions = append(mountOptions, "ro") | |||
| } | |||
| remote, remotePath, configData, flags, e := extractFlags(req.GetVolumeContext()) | |||
| if e != nil { | |||
| klog.Warningf("storage parameter error: %s", e) | |||
| return nil, e | |||
| } | |||
| e = Mount(remote, remotePath, targetPath, configData, flags) | |||
| if e != nil { | |||
| if os.IsPermission(e) { | |||
| return nil, status.Error(codes.PermissionDenied, e.Error()) | |||
| } | |||
| if strings.Contains(e.Error(), "invalid argument") { | |||
| return nil, status.Error(codes.InvalidArgument, e.Error()) | |||
| } | |||
| return nil, status.Error(codes.Internal, e.Error()) | |||
| } | |||
| return &csi.NodePublishVolumeResponse{}, nil | |||
| } | |||
| // extractFlags extracts the flags from the given volumeContext | |||
| // Retturns: remote, remotePath, configData, flags, error | |||
| func extractFlags(volumeContext map[string]string) (string, string, string, map[string]string, error) { | |||
| // Load default connection settings from secret | |||
| var secret *v1.Secret | |||
| if secretName, ok := volumeContext["secretName"]; ok { | |||
| // Load the secret that the PV spec defines | |||
| var e error | |||
| secret, e = getSecret(secretName) | |||
| if e != nil { | |||
| // if the user explicitly requested a secret and there is an error fetching it, bail with an error | |||
| return "", "", "", nil, e | |||
| } | |||
| } else { | |||
| // use rclone-secret as the default secret if none was defined | |||
| secret, _ = getSecret("rclone-secret") | |||
| } | |||
| // Empty argument list | |||
| flags := make(map[string]string) | |||
| // Secret values are default, gets merged and overriden by corresponding PV values | |||
| if secret != nil && secret.Data != nil && len(secret.Data) > 0 { | |||
| // Needs byte to string casting for map values | |||
| for k, v := range secret.Data { | |||
| flags[k] = string(v) | |||
| } | |||
| } else { | |||
| klog.Infof("No csi-rclone connection defaults secret found.") | |||
| } | |||
| if len(volumeContext) > 0 { | |||
| for k, v := range volumeContext { | |||
| flags[k] = v | |||
| } | |||
| } | |||
| if e := validateFlags(flags); e != nil { | |||
| return "", "", "", flags, e | |||
| } | |||
| remote := flags["remote"] | |||
| remotePath := flags["remotePath"] | |||
| if remotePathSuffix, ok := flags["remotePathSuffix"]; ok { | |||
| remotePath = remotePath + remotePathSuffix | |||
| delete(flags, "remotePathSuffix") | |||
| } | |||
| configData := "" | |||
| ok := false | |||
| if configData, ok = flags["configData"]; ok { | |||
| delete(flags, "configData") | |||
| } | |||
| delete(flags, "remote") | |||
| delete(flags, "remotePath") | |||
| delete(flags, "secretName") | |||
| return remote, remotePath, configData, flags, nil | |||
| } | |||
| func (ns *nodeServer) NodeUnpublishVolume(ctx context.Context, req *csi.NodeUnpublishVolumeRequest) (*csi.NodeUnpublishVolumeResponse, error) { | |||
| klog.Infof("NodeUnPublishVolume: called with args %+v", *req) | |||
| targetPath := req.GetTargetPath() | |||
| if len(targetPath) == 0 { | |||
| return nil, status.Error(codes.InvalidArgument, "NodeUnpublishVolume Target Path must be provided") | |||
| } | |||
| m := mount.New("") | |||
| notMnt, err := m.IsLikelyNotMountPoint(targetPath) | |||
| if err != nil && !mount.IsCorruptedMnt(err) { | |||
| return nil, status.Error(codes.Internal, err.Error()) | |||
| } | |||
| if notMnt && !mount.IsCorruptedMnt(err) { | |||
| klog.Infof("Volume not mounted") | |||
| } else { | |||
| err = util.UnmountPath(req.GetTargetPath(), m) | |||
| if err != nil { | |||
| klog.Infof("Error while unmounting path: %s", err) | |||
| // This will exit and fail the NodeUnpublishVolume making it to retry unmount on the next api schedule trigger. | |||
| // Since we mount the volume with allow-non-empty now, we could skip this one too. | |||
| return nil, status.Error(codes.Internal, err.Error()) | |||
| } | |||
| klog.Infof("Volume %s unmounted successfully", req.VolumeId) | |||
| } | |||
| return &csi.NodeUnpublishVolumeResponse{}, nil | |||
| } | |||
| func (ns *nodeServer) NodeUnstageVolume(ctx context.Context, req *csi.NodeUnstageVolumeRequest) (*csi.NodeUnstageVolumeResponse, error) { | |||
| klog.Infof("NodeUnstageVolume: called with args %+v", *req) | |||
| return &csi.NodeUnstageVolumeResponse{}, nil | |||
| } | |||
| func (ns *nodeServer) NodeStageVolume(ctx context.Context, req *csi.NodeStageVolumeRequest) (*csi.NodeStageVolumeResponse, error) { | |||
| klog.Infof("NodeStageVolume: called with args %+v", *req) | |||
| return &csi.NodeStageVolumeResponse{}, nil | |||
| } | |||
| func validateFlags(flags map[string]string) error { | |||
| if _, ok := flags["remote"]; !ok { | |||
| return status.Errorf(codes.InvalidArgument, "missing volume context value: remote") | |||
| } | |||
| if _, ok := flags["remotePath"]; !ok { | |||
| return status.Errorf(codes.InvalidArgument, "missing volume context value: remotePath") | |||
| } | |||
| return nil | |||
| } | |||
| func getSecret(secretName string) (*v1.Secret, error) { | |||
| clientset, e := GetK8sClient() | |||
| if e != nil { | |||
| return nil, status.Errorf(codes.Internal, "can not create kubernetes client: %s", e) | |||
| } | |||
| kubeconfig := clientcmd.NewNonInteractiveDeferredLoadingClientConfig( | |||
| clientcmd.NewDefaultClientConfigLoadingRules(), | |||
| &clientcmd.ConfigOverrides{}, | |||
| ) | |||
| namespace, _, err := kubeconfig.Namespace() | |||
| if err != nil { | |||
| return nil, status.Errorf(codes.Internal, "can't get current namespace, error %s", secretName, err) | |||
| } | |||
| klog.Infof("Loading csi-rclone connection defaults from secret %s/%s", namespace, secretName) | |||
| secret, e := clientset.CoreV1(). | |||
| Secrets(namespace). | |||
| Get(secretName, metav1.GetOptions{}) | |||
| if e != nil { | |||
| return nil, status.Errorf(codes.Internal, "can't load csi-rclone settings from secret %s: %s", secretName, e) | |||
| } | |||
| return secret, nil | |||
| } | |||
| // Mount routine. | |||
| func Mount(remote string, remotePath string, targetPath string, configData string, flags map[string]string) error { | |||
| mountCmd := "rclone" | |||
| mountArgs := []string{} | |||
| defaultFlags := map[string]string{} | |||
| defaultFlags["cache-info-age"] = "72h" | |||
| defaultFlags["cache-chunk-clean-interval"] = "15m" | |||
| defaultFlags["dir-cache-time"] = "5s" | |||
| defaultFlags["vfs-cache-mode"] = "writes" | |||
| defaultFlags["allow-non-empty"] = "true" | |||
| defaultFlags["allow-other"] = "true" | |||
| remoteWithPath := fmt.Sprintf(":%s:%s", remote, remotePath) | |||
| if strings.Contains(configData, "["+remote+"]") { | |||
| remoteWithPath = fmt.Sprintf("%s:%s", remote, remotePath) | |||
| klog.Infof("remote %s found in configData, remoteWithPath set to %s", remote, remoteWithPath) | |||
| } | |||
| // rclone mount remote:path /path/to/mountpoint [flags] | |||
| mountArgs = append( | |||
| mountArgs, | |||
| "mount", | |||
| remoteWithPath, | |||
| targetPath, | |||
| "--daemon", | |||
| ) | |||
| // If a custom flag configData is defined, | |||
| // create a temporary file, fill it with configData content, | |||
| // and run rclone with --config <tmpfile> flag | |||
| if configData != "" { | |||
| configFile, err := ioutil.TempFile("", "rclone.conf") | |||
| if err != nil { | |||
| return err | |||
| } | |||
| // Normally, a defer os.Remove(configFile.Name()) should be placed here. | |||
| // However, due to a rclone mount --daemon flag, rclone forks and creates a race condition | |||
| // with this nodeplugin proceess. As a result, the config file gets deleted | |||
| // before it's reread by a forked process. | |||
| if _, err := configFile.Write([]byte(configData)); err != nil { | |||
| return err | |||
| } | |||
| if err := configFile.Close(); err != nil { | |||
| return err | |||
| } | |||
| mountArgs = append(mountArgs, "--config", configFile.Name()) | |||
| } | |||
| // Add default flags | |||
| for k, v := range defaultFlags { | |||
| // Exclude overriden flags | |||
| if _, ok := flags[k]; !ok { | |||
| mountArgs = append(mountArgs, fmt.Sprintf("--%s=%s", k, v)) | |||
| } | |||
| } | |||
| // Add user supplied flags | |||
| for k, v := range flags { | |||
| mountArgs = append(mountArgs, fmt.Sprintf("--%s=%s", k, v)) | |||
| } | |||
| // create target, os.Mkdirall is noop if it exists | |||
| err := os.MkdirAll(targetPath, 0750) | |||
| if err != nil { | |||
| return err | |||
| } | |||
| klog.Infof("executing mount command cmd=%s, remote=%s, targetpath=%s", mountCmd, remoteWithPath, targetPath) | |||
| out, err := exec.Command(mountCmd, mountArgs...).CombinedOutput() | |||
| if err != nil { | |||
| return fmt.Errorf("mounting failed: %v cmd: '%s' remote: '%s' targetpath: %s output: %q", | |||
| err, mountCmd, remoteWithPath, targetPath, string(out)) | |||
| } | |||
| return nil | |||
| } | |||
| @@ -0,0 +1,5 @@ | |||
| apiVersion: storage.k8s.io/v1 | |||
| kind: StorageClass | |||
| metadata: | |||
| name: rclone | |||
| provisioner: kubernetes.io/no-provisioner | |||
| @@ -0,0 +1,109 @@ | |||
| #!/bin/bash | |||
| # 配置文件路径 | |||
| config_file="config.ini" | |||
| # YAML 模板文件路径 | |||
| agent_template_file="template/rclone-agent.yaml.template" | |||
| rclone_pv_template_file="template/rclone-pv.yaml.template" | |||
| coordinator_template_file="template/coordinator.yaml.template" | |||
| scanner_template_file="template/scanner.yaml.template" | |||
| client_template_file="template/client.yaml.template" | |||
| image_registry_address=$(awk -F "=" '/\[General\]/{f=1} f==1 && /image_registry/{print $2; exit}' "$config_file") | |||
| # 逐行读取文件 | |||
| while IFS= read -r line; do | |||
| # 判断是否是标题行 | |||
| if [[ $line == \[*] ]]; then | |||
| current_section=$(echo "$line" | tr -d '[]') | |||
| case $current_section in | |||
| agent*) | |||
| echo "读取agent配置" | |||
| while IFS= read -r next_line && [[ $next_line ]]; do | |||
| case "$next_line" in | |||
| label=*) label=$(echo "$next_line" | cut -d '=' -f 2) ;; | |||
| port=*) port=$(echo "$next_line" | cut -d '=' -f 2) ;; | |||
| node=*) node=$(echo "$next_line" | cut -d '=' -f 2) ;; | |||
| esac | |||
| done | |||
| if [[ -n $label && -n $port && -n $node ]]; then | |||
| # 创建并替换 YAML 文件 | |||
| agent_yaml_file="rclone_agent_$label.yaml" | |||
| #pv_yaml_file="rclone_pv_$label.yaml" | |||
| if [ ! -f "$agent_yaml_file" ]; then | |||
| sed "s/{{NODE_NAME}}/$label/g; | |||
| s/{{NODE_PORT}}/$port/g; | |||
| s/{{NODE_ID}}/$node/g; | |||
| s/{{IMAGE_REGISTRY_ADDRESS}}/$image_registry_address/g" "$agent_template_file" > "$agent_yaml_file" | |||
| fi | |||
| #if [ ! -f "$pv_yaml_file" ]; then | |||
| # sed "s/{{NODE_NAME}}/$label/g" "$rclone_pv_template_file" > "$pv_yaml_file" | |||
| #fi | |||
| # 清空变量,以便下一个节点的处理 | |||
| label="" | |||
| port="" | |||
| node="" | |||
| fi | |||
| ;; | |||
| coordinator) | |||
| echo "读取coordinator配置" | |||
| while IFS= read -r next_line && [[ $next_line ]]; do | |||
| case "$next_line" in | |||
| label=*) coor_label=$(echo "$next_line" | cut -d '=' -f 2) ;; | |||
| node=*) coor_node=$(echo "$next_line" | cut -d '=' -f 2) ;; | |||
| esac | |||
| done | |||
| if [[ -n $coor_label && -n $coor_node ]]; then | |||
| coor_yaml_file="coordinator.yaml" | |||
| if [ ! -f "$coor_yaml_file" ]; then | |||
| sed "s/{{NODE_NAME}}/$coor_label/g; | |||
| s/{{IMAGE_REGISTRY_ADDRESS}}/$image_registry_address/g" "$coordinator_template_file" > "$coor_yaml_file" | |||
| fi | |||
| fi | |||
| ;; | |||
| scanner) | |||
| echo "读取scanner配置" | |||
| while IFS= read -r next_line && [[ $next_line ]]; do | |||
| case "$next_line" in | |||
| label=*) scan_label=$(echo "$next_line" | cut -d '=' -f 2) ;; | |||
| node=*) scan_node=$(echo "$next_line" | cut -d '=' -f 2) ;; | |||
| esac | |||
| done | |||
| if [[ -n $scan_label && -n $scan_node ]]; then | |||
| scan_yaml_file="scanner.yaml" | |||
| if [ ! -f "$scan_yaml_file" ]; then | |||
| sed "s/{{NODE_NAME}}/$scan_label/g; | |||
| s/{{IMAGE_REGISTRY_ADDRESS}}/$image_registry_address/g" "$scanner_template_file" > "$scan_yaml_file" | |||
| fi | |||
| fi | |||
| ;; | |||
| client) | |||
| echo "读取client配置" | |||
| while IFS= read -r next_line && [[ $next_line ]]; do | |||
| case "$next_line" in | |||
| label=*) cli_label=$(echo "$next_line" | cut -d '=' -f 2) ;; | |||
| port=*) cli_port=$(echo "$next_line" | cut -d '=' -f 2) ;; | |||
| node=*) cli_node=$(echo "$next_line" | cut -d '=' -f 2) ;; | |||
| esac | |||
| done | |||
| if [[ -n $cli_label && -n $cli_port && -n $cli_node ]]; then | |||
| cli_yaml_file="client.yaml" | |||
| if [ ! -f "$cli_yaml_file" ]; then | |||
| sed "s/{{NODE_NAME}}/$cli_label/g; | |||
| s/{{NODE_PORT}}/$cli_port/g; | |||
| s/{{IMAGE_REGISTRY_ADDRESS}}/$image_registry_address/g" "$client_template_file" > "$cli_yaml_file" | |||
| fi | |||
| fi | |||
| ;; | |||
| esac | |||
| fi | |||
| done < "$config_file" | |||
| @@ -0,0 +1,41 @@ | |||
| #!/bin/bash | |||
| #!/bin/bash | |||
| # 获取当前路径 | |||
| current_path=$(pwd) | |||
| # 拉起configmap | |||
| cd $current_path/config | |||
| config_files=$(ls *.json 2>/dev/null) | |||
| if [ -z "$config_files" ]; then | |||
| echo "当前路径下没有.config.json文件。" | |||
| exit 1 | |||
| fi | |||
| for file in $config_files; do | |||
| if [[ -f "$file" ]]; then | |||
| name=$(echo "$file" | cut -d '.' -f1) | |||
| service_name=$(echo "$name" | cut -d '-' -f1) | |||
| kubectl create cm $name-config --from-file=$service_name.config.json=./$file | |||
| fi | |||
| done | |||
| # 拉起pod | |||
| pv_yaml_files=$(ls rclone_pv_*.yaml 2>/dev/null) | |||
| for pv_yaml_file in $pv_yaml_files; do | |||
| echo "Applying $pv_yaml_file ..." | |||
| kubectl apply -f $pv_yaml_file | |||
| done | |||
| cd $current_path | |||
| yaml_files=$(ls *.yaml 2>/dev/null) | |||
| for yaml_file in $yaml_files; do | |||
| echo "Applying $yaml_file ..." | |||
| kubectl apply -f $yaml_file | |||
| done | |||
| @@ -0,0 +1,38 @@ | |||
| #!/bin/bash | |||
| # 获取当前路径 | |||
| current_path=$(pwd) | |||
| # 删除configmap | |||
| cd $current_path/config | |||
| config_files=$(ls *.json 2>/dev/null) | |||
| if [ -z "$config_files" ]; then | |||
| echo "当前路径下没有.config.json文件。" | |||
| exit 1 | |||
| fi | |||
| for file in $config_files; do | |||
| if [[ -f "$file" ]]; then | |||
| name=$(echo "$file" | cut -d '.' -f1) | |||
| kubectl delete cm $name-config | |||
| fi | |||
| done | |||
| # 删除pod | |||
| cd $current_path | |||
| yaml_files=$(ls *.yaml 2>/dev/null) | |||
| for yaml_file in $yaml_files; do | |||
| echo "Delete $yaml_file ..." | |||
| kubectl delete -f $yaml_file | |||
| done | |||
| # 删除pv | |||
| cd $current_path/config | |||
| pv_yaml_files=$(ls *.yaml 2>/dev/null) | |||
| for pv_yaml_file in $pv_yaml_files; do | |||
| echo "Delete $pv_yaml_file ..." | |||
| kubectl delete -f $pv_yaml_file | |||
| done | |||
| @@ -0,0 +1,49 @@ | |||
| apiVersion: apps/v1 | |||
| kind: Deployment | |||
| metadata: | |||
| labels: | |||
| app: client | |||
| name: client | |||
| namespace: default | |||
| spec: | |||
| selector: | |||
| matchLabels: | |||
| app: client | |||
| template: | |||
| metadata: | |||
| labels: | |||
| app: client | |||
| spec: | |||
| containers: | |||
| - name: clientservice | |||
| image: {{IMAGE_REGISTRY_ADDRESS}}/clientservice-x86:latest | |||
| imagePullPolicy: Always | |||
| volumeMounts: | |||
| - name: clientconfig | |||
| mountPath: /opt/confs | |||
| volumes: | |||
| - name: clientconfig | |||
| configMap: | |||
| name: client-config | |||
| nodeSelector: | |||
| nodetype: {{NODE_NAME}} | |||
| restartPolicy: Always | |||
| --- | |||
| apiVersion: v1 | |||
| kind: Service | |||
| metadata: | |||
| labels: | |||
| app: client | |||
| name: client | |||
| namespace: default | |||
| spec: | |||
| ports: | |||
| - port: 7890 | |||
| protocol: TCP | |||
| targetPort: 7890 | |||
| nodePort: {{NODE_PORT}} | |||
| selector: | |||
| app: client | |||
| type: NodePort | |||
| @@ -0,0 +1,31 @@ | |||
| apiVersion: apps/v1 | |||
| kind: Deployment | |||
| metadata: | |||
| labels: | |||
| app: coordinator | |||
| name: coordinator | |||
| namespace: default | |||
| spec: | |||
| selector: | |||
| matchLabels: | |||
| app: coordinator | |||
| template: | |||
| metadata: | |||
| labels: | |||
| app: coordinator | |||
| spec: | |||
| containers: | |||
| - name: coordinatorservice | |||
| image: {{IMAGE_REGISTRY_ADDRESS}}/coordinatorservice-x86:latest | |||
| imagePullPolicy: Always | |||
| volumeMounts: | |||
| - name: coordinatorconfig | |||
| mountPath: /opt/confs | |||
| volumes: | |||
| - name: coordinatorconfig | |||
| configMap: | |||
| name: coordinator-config | |||
| nodeSelector: | |||
| nodetype: {{NODE_NAME}} | |||
| restartPolicy: Always | |||
| @@ -0,0 +1,75 @@ | |||
| apiVersion: v1 | |||
| kind: PersistentVolumeClaim | |||
| metadata: | |||
| name: rclone-{{NODE_NAME}} | |||
| spec: | |||
| accessModes: | |||
| - ReadWriteMany | |||
| storageClassName: rclone | |||
| resources: | |||
| requests: | |||
| storage: 10Gi | |||
| selector: | |||
| matchLabels: | |||
| name: rclone-{{NODE_NAME}} | |||
| --- | |||
| apiVersion: apps/v1 | |||
| kind: DaemonSet | |||
| metadata: | |||
| labels: | |||
| app: agent-{{NODE_NAME}} | |||
| name: agent-{{NODE_NAME}} | |||
| namespace: default | |||
| spec: | |||
| selector: | |||
| matchLabels: | |||
| app: agent-{{NODE_NAME}} | |||
| template: | |||
| metadata: | |||
| labels: | |||
| app: agent-{{NODE_NAME}} | |||
| spec: | |||
| containers: | |||
| - name: agentservice | |||
| image: {{IMAGE_REGISTRY_ADDRESS}}/agentservice-x86:latest | |||
| imagePullPolicy: Always | |||
| #command: ["tail","-f","/etc/hosts"] | |||
| ports: | |||
| - containerPort: 5010 | |||
| protocol: TCP | |||
| volumeMounts: | |||
| - name: agentconfig | |||
| mountPath: /opt/confs | |||
| - name: rclone-pvc | |||
| mountPath: /opt/storage | |||
| volumes: | |||
| - name: agentconfig | |||
| configMap: | |||
| name: agent-{{NODE_NAME}}-config | |||
| - name: rclone-pvc | |||
| persistentVolumeClaim: | |||
| claimName: rclone-{{NODE_NAME}} | |||
| dnsPolicy: Default | |||
| nodeSelector: | |||
| nodetype: {{NODE_NAME}} | |||
| restartPolicy: Always | |||
| --- | |||
| apiVersion: v1 | |||
| kind: Service | |||
| metadata: | |||
| labels: | |||
| app: agent-{{NODE_NAME}} | |||
| name: agent-{{NODE_NAME}} | |||
| namespace: default | |||
| spec: | |||
| ports: | |||
| - port: 5010 | |||
| protocol: TCP | |||
| targetPort: 5010 | |||
| nodePort: {{NODE_PORT}} | |||
| selector: | |||
| app: agent-{{NODE_NAME}} | |||
| type: NodePort | |||
| @@ -0,0 +1,26 @@ | |||
| apiVersion: v1 | |||
| kind: PersistentVolume | |||
| metadata: | |||
| name: rclone-{{NODE_NAME}} | |||
| labels: | |||
| name: rclone-{{NODE_NAME}} | |||
| spec: | |||
| capacity: | |||
| storage: 10Gi | |||
| accessModes: | |||
| - ReadWriteMany | |||
| storageClassName: rclone | |||
| csi: | |||
| driver: csi-rclone | |||
| volumeHandle: rclone-data-id | |||
| volumeAttributes: | |||
| remote: "xxxx" | |||
| remotePath: "xxxx" | |||
| configData: | | |||
| [xxxx] | |||
| type = s3 | |||
| provider = xxxx | |||
| access_key_id = xxxx | |||
| secret_access_key = xxxx | |||
| endpoint = xxxx | |||
| @@ -0,0 +1,32 @@ | |||
| apiVersion: apps/v1 | |||
| kind: Deployment | |||
| metadata: | |||
| labels: | |||
| app: scanner | |||
| name: scanner | |||
| namespace: default | |||
| spec: | |||
| selector: | |||
| matchLabels: | |||
| app: scanner | |||
| template: | |||
| metadata: | |||
| labels: | |||
| app: scanner | |||
| spec: | |||
| containers: | |||
| - name: scannerservice | |||
| image: {{IMAGE_REGISTRY_ADDRESS}}/scannerservice-x86:latest | |||
| #command: ["tail","-f","/etc/hosts"] | |||
| imagePullPolicy: Always | |||
| volumeMounts: | |||
| - name: scannerconfig | |||
| mountPath: /opt/confs | |||
| volumes: | |||
| - name: scannerconfig | |||
| configMap: | |||
| name: scanner-config | |||
| nodeSelector: | |||
| nodetype: {{NODE_NAME}} | |||
| restartPolicy: Always | |||