├── .circleci
├── build.config
└── config.yml
├── .github
├── ISSUE_TEMPLATE
│ ├── bug.yaml
│ ├── feature_request.md
│ └── other.md
├── dependabot.yml
├── pull_request_template.md
└── workflows
│ └── stale.yml
├── .gitignore
├── .goreleaser.yml.envsubst
├── .tool-versions
├── CODEOWNERS
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── Dockerfile
├── LICENSE
├── README.md
├── codecov.yml
├── examples
├── bash
│ ├── 01-create-namespace.yaml
│ ├── 02-create-storageclass.yaml
│ ├── 03-create-volumesnapshotclass.yaml
│ ├── 04-create-snapshotgroup.yaml
│ ├── 05-create-pod.yaml
│ ├── README.md
│ └── course.yaml
└── codimd
│ └── README.md
├── go.mod
├── go.sum
├── logo.png
├── main.go
├── pkg
├── controller
│ ├── controller.go
│ └── controller_test.go
├── kube
│ ├── client.go
│ └── fake_client.go
├── snapshots
│ ├── consts.go
│ ├── groups.go
│ ├── pvc.go
│ ├── scheduler.go
│ ├── scheduler_test.go
│ └── snapshots.go
└── types
│ └── snapshotgroup
│ └── v1
│ ├── apis
│ ├── clientset
│ │ └── versioned
│ │ │ ├── clientset.go
│ │ │ ├── doc.go
│ │ │ ├── fake
│ │ │ ├── clientset_generated.go
│ │ │ ├── doc.go
│ │ │ └── register.go
│ │ │ ├── scheme
│ │ │ ├── doc.go
│ │ │ └── register.go
│ │ │ └── typed
│ │ │ └── snapshotgroup
│ │ │ └── v1
│ │ │ ├── doc.go
│ │ │ ├── fake
│ │ │ ├── doc.go
│ │ │ ├── fake_snapshotgroup.go
│ │ │ └── fake_snapshotgroup_client.go
│ │ │ ├── generated_expansion.go
│ │ │ ├── snapshotgroup.go
│ │ │ └── snapshotgroup_client.go
│ ├── informers
│ │ └── externalversions
│ │ │ ├── factory.go
│ │ │ ├── generic.go
│ │ │ ├── internalinterfaces
│ │ │ └── factory_interfaces.go
│ │ │ └── snapshotgroup
│ │ │ ├── interface.go
│ │ │ └── v1
│ │ │ ├── interface.go
│ │ │ └── snapshotgroup.go
│ └── listers
│ │ └── snapshotgroup
│ │ └── v1
│ │ ├── expansion_generated.go
│ │ └── snapshotgroup.go
│ ├── crd-with-beta1.yaml
│ ├── crd.go
│ ├── crd.yaml
│ ├── deepcopy.go
│ ├── register.go
│ └── snapshotgroup.go
└── scripts
└── goreleaser.sh
/.circleci/build.config:
--------------------------------------------------------------------------------
1 | DOCKERFILE='Dockerfile'
2 |
3 | EXTERNAL_REGISTRY_BASE_DOMAIN=quay.io
4 | REPOSITORY_NAME=fairwinds/gemini
5 | DOCKERTAG=${EXTERNAL_REGISTRY_BASE_DOMAIN}/${REPOSITORY_NAME}
6 | if [[ -n $CI_TAG ]]; then
7 | ADDITIONAL_DOCKER_TAG_VERSIONS=()
8 | ADDITIONAL_DOCKER_TAG_VERSIONS+=(`echo $CI_TAG | sed -e 's/\(\w\+\)\..*$/\1/'`)
9 | ADDITIONAL_DOCKER_TAG_VERSIONS+=(`echo $CI_TAG | sed -e 's/\(\w\+\.\w\+\)\..*$/\1/'`)
10 | fi
11 |
--------------------------------------------------------------------------------
/.circleci/config.yml:
--------------------------------------------------------------------------------
1 | version: 2.1
2 |
3 | orbs:
4 | rok8s: fairwinds/rok8s-scripts@11
5 |
6 | executors:
7 | golang-exec:
8 | docker:
9 | - image: cimg/go:1.20
10 |
11 | references:
12 | install_vault: &install_vault
13 | run:
14 | name: install hashicorp vault
15 | command: |
16 | apk --update add curl yq
17 | cd /tmp
18 | curl -LO https://releases.hashicorp.com/vault/1.9.2/vault_1.9.2_linux_amd64.zip
19 | unzip vault_1.9.2_linux_amd64.zip
20 | mv vault /usr/bin/vault
21 |
22 | set_environment_variables: &set_environment_variables
23 | run:
24 | name: Set Environment Variables
25 | command: |
26 | echo 'export CI_SHA1=$CIRCLE_SHA1' >> ${BASH_ENV}
27 | echo 'export CI_BRANCH=$CIRCLE_BRANCH' >> ${BASH_ENV}
28 | echo 'export CI_BUILD_NUM=$CIRCLE_BUILD_NUM' >> ${BASH_ENV}
29 | echo 'export CI_TAG=$CIRCLE_TAG' >> ${BASH_ENV}
30 | echo 'export PUSH_ALL_VERSION_TAGS=true' >> ${BASH_ENV}
31 | echo 'export GOPROXY=https://proxy.golang.org' >> ${BASH_ENV}
32 | echo 'export GO111MODULE=on' >> ${BASH_ENV}
33 | echo 'export GOFLAGS=-mod=mod' >> ${BASH_ENV}
34 | echo 'export GORELEASER_CURRENT_TAG="${CIRCLE_TAG}"' >> $BASH_ENV
35 |
36 | commands:
37 | install_goreleaser_dependencies:
38 | description: Installs dependencies for CI scripts
39 | steps:
40 | - run: apk update
41 | # gettext provides envsubst
42 | - run: apk add gettext
43 | # Register other docker platforms, to build arm64.
44 | # This shouldn't be needed, why TBD.
45 | - run: docker run --privileged --rm tonistiigi/binfmt --install all
46 |
47 | jobs:
48 | test:
49 | working_directory: /home/circleci/go/src/github.com/fairwindsops/gemini
50 |
51 | docker:
52 | - image: cimg/go:1.20
53 | steps:
54 | - checkout
55 | - run: |
56 | go install gotest.tools/gotestsum@latest
57 | mkdir -p /tmp/test-results/go
58 | gotestsum --junitfile /tmp/test-results/go/results.xml -- ./pkg/... -cover -covermode atomic -coverpkg=./... -coverprofile=coverage.txt
59 | build_and_push:
60 | working_directory: /go/src/github.com/fairwindsops/polaris/
61 | resource_class: large
62 | shell: /bin/bash
63 | docker:
64 | # The goreleaser image tag determins the version of Go.
65 | # Manually check goreleaser images for their version of Go.
66 | # Ref: https://hub.docker.com/r/goreleaser/goreleaser/tags
67 | - image: goreleaser/goreleaser:v1.11.4
68 | steps:
69 | - checkout
70 | - setup_remote_docker
71 | - *install_vault
72 | - rok8s/get_vault_env:
73 | vault_path: repo/global/env
74 | - *set_environment_variables
75 | - run: docker login quay.io -u="${FAIRWINDS_QUAY_USER}" -p="${FAIRWINDS_QUAY_TOKEN}"
76 | - install_goreleaser_dependencies
77 | - run: scripts/goreleaser.sh
78 |
79 | workflows:
80 | version: 2
81 | build_and_push:
82 | jobs:
83 | - test
84 | - build_and_push:
85 | context: org-global
86 | filters:
87 | branches:
88 | ignore: /pull\/[0-9]+/
89 | tags:
90 | ignore: /^testing-.*/
91 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug.yaml:
--------------------------------------------------------------------------------
1 | name: Bug Report
2 | description: File a bug report
3 | labels: [bug, triage]
4 | body:
5 | - type: markdown
6 | attributes:
7 | value: |
8 | Thanks for taking the time to fill out this bug report! Please fill the form below.
9 | - type: textarea
10 | id: what-happened
11 | attributes:
12 | label: What happened?
13 | description: What happened?
14 | validations:
15 | required: true
16 | - type: textarea
17 | id: expected
18 | attributes:
19 | label: What did you expect to happen?
20 | description: What is the expected or desired behavior?
21 | validations:
22 | required: true
23 | - type: textarea
24 | id: reproducible
25 | attributes:
26 | label: How can we reproduce this?
27 | description: Please share the steps that we can take to reproduce this. Also include any relevant configuration.
28 | validations:
29 | required: true
30 | - type: input
31 | id: version
32 | attributes:
33 | label: Version
34 | description: The version of the tool that you are using. If a helm chart, please share the name of the chart.
35 | validations:
36 | required: true
37 | - type: checkboxes
38 | id: search
39 | attributes:
40 | label: Search
41 | options:
42 | - label: I did search for other open and closed issues before opening this.
43 | required: true
44 | - type: checkboxes
45 | id: terms
46 | attributes:
47 | label: Code of Conduct
48 | description: By submitting this issue, you agree to follow the CODE_OF_CONDUCT in this repository.
49 | options:
50 | - label: I agree to follow this project's Code of Conduct
51 | required: true
52 | - type: textarea
53 | id: ctx
54 | attributes:
55 | label: Additional context
56 | description: Anything else you would like to add
57 | validations:
58 | required: false
59 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Feature request
3 | about: Suggest an idea for this project
4 | title: ''
5 | labels: [triage, enhancement]
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Is your feature request related to a problem? Please describe.**
11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
12 |
13 | **Describe the solution you'd like**
14 | A clear and concise description of what you want to happen.
15 |
16 | **Describe alternatives you've considered**
17 | A clear and concise description of any alternative solutions or features you've considered.
18 |
19 | **Additional context**
20 | Add any other context or screenshots about the feature request here.
21 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/other.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Other
3 | about: For misc. tasks like research or continued conversation
4 | title: ''
5 | labels: [triage]
6 | assignees: ''
7 |
8 | ---
9 |
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | ## DO NOT EDIT - Managed by Terraform
2 | version: 2
3 | updates:
4 | - package-ecosystem: "docker"
5 | directory: "/"
6 | schedule:
7 | interval: "weekly"
8 |
9 | - package-ecosystem: "npm"
10 | directory: "/docs"
11 | schedule:
12 | interval: "weekly"
13 | open-pull-requests-limit: 0
14 | ignore:
15 | - dependency-name: "*"
16 |
17 | - package-ecosystem: "gomod"
18 | directory: "/"
19 | schedule:
20 | interval: "weekly"
21 |
--------------------------------------------------------------------------------
/.github/pull_request_template.md:
--------------------------------------------------------------------------------
1 |
2 | This PR fixes #
3 |
4 | ## Checklist
5 | * [ ] I have signed the CLA
6 | * [ ] I have updated/added any relevant documentation
7 |
8 | ## Description
9 | ### What's the goal of this PR?
10 |
11 | ### What changes did you make?
12 |
13 | ### What alternative solution should we consider, if any?
14 |
15 |
--------------------------------------------------------------------------------
/.github/workflows/stale.yml:
--------------------------------------------------------------------------------
1 | name: 'Close stale issues and PRs'
2 | on:
3 | schedule:
4 | - cron: '32 1 * * *'
5 |
6 | permissions:
7 | issues: write
8 | pull-requests: write
9 |
10 | jobs:
11 | stale:
12 | runs-on: ubuntu-latest
13 | steps:
14 | - uses: actions/stale@v4
15 | with:
16 | exempt-issue-labels: pinned
17 | stale-pr-label: stale
18 | stale-issue-label: stale
19 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | kubeconfig.yaml
2 | gemini
3 | results.xml
4 | coverage.txt
5 | .goreleaser.yml
6 |
--------------------------------------------------------------------------------
/.goreleaser.yml.envsubst:
--------------------------------------------------------------------------------
1 | checksum:
2 | name_template: 'checksums.txt'
3 | changelog:
4 | sort: asc
5 | filters:
6 | exclude:
7 | - '^docs:'
8 | - '^test:'
9 | env:
10 | - GOBIN={{ .Env.TMPDIR }}/go-bin
11 | before:
12 | hooks:
13 | - go mod download
14 | builds:
15 | - id: gemini
16 | ldflags:
17 | - -X main.Version={{.Version}} -X main.Commit={{.Commit}} -s -w
18 | env:
19 | - CGO_ENABLED=0
20 | - GO111MODULE=on
21 | goos:
22 | - linux
23 | - darwin
24 | - windows
25 | goarch:
26 | - amd64
27 | - arm
28 | - arm64
29 | goarm:
30 | - 6
31 | - 7
32 | archives:
33 | - id: gemini
34 | builds: ["gemini"]
35 | name_template: "{{ .ProjectName }}_{{ .Os }}_{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}{{ if .Mips }}_{{ .Mips }}{{ end }}"
36 | signs:
37 | - cmd: cosign
38 | args: ["sign-blob", "--key=hashivault://cosign", "-output-signature=${signature}", "${artifact}"]
39 | artifacts: checksum
40 | release:
41 | # This is replaced using `envsubst`, depending on the git branch.
42 | disable: ${skip_release}
43 | prerelease: auto
44 | footer: |
45 | You can verify the signature of the checksums.txt file using [cosign](https://github.com/sigstore/cosign).
46 |
47 | ```
48 | cosign verify-blob checksums.txt --signature=checksums.txt.sig --key https://artifacts.fairwinds.com/cosign.pub
49 | ```
50 | brews:
51 | - name: gemini
52 | # This is replaced using `envsubst`, depending on the git branch.
53 | skip_upload: ${skip_release}
54 | tap:
55 | owner: FairwindsOps
56 | name: homebrew-tap
57 | folder: Formula
58 | description: Open Source Best Practices for Kubernetes
59 | test: |
60 | system "#{bin}/gemini version"
61 | dockers:
62 | # There are multiple images to match the `--platform` docker build flag with
63 | # combinations of `GOOS`, `GOARCH`, and `GOARM`
64 | - image_templates:
65 | - "quay.io/fairwinds/gemini:{{ .FullCommit }}-amd64"
66 | use: buildx
67 | build_flag_templates:
68 | - "--platform=linux/amd64"
69 | - image_templates:
70 | - "quay.io/fairwinds/gemini:{{ .FullCommit }}-arm64"
71 | use: buildx
72 | goarch: arm64
73 | goos: linux
74 | build_flag_templates:
75 | - "--platform=linux/arm64"
76 | docker_manifests:
77 | # Create DOcker manifests that make multiple architectures available within a tag,
78 | # and provide partial-version tags like 2, and 2.2.
79 | - name_template: quay.io/fairwinds/gemini:{{ .FullCommit }}
80 | image_templates:
81 | - "quay.io/fairwinds/gemini:{{ .FullCommit }}-amd64"
82 | - "quay.io/fairwinds/gemini:{{ .FullCommit }}-arm64"
83 | - name_template: quay.io/fairwinds/gemini:{{ .Env.feature_docker_tag }}
84 | # This is replaced using `envsubst`, depending on the git branch.
85 | skip_push: ${skip_feature_docker_tags}
86 | image_templates:
87 | - "quay.io/fairwinds/gemini:{{ .FullCommit }}-amd64"
88 | - "quay.io/fairwinds/gemini:{{ .FullCommit }}-arm64"
89 | - name_template: quay.io/fairwinds/gemini:latest
90 | # This is replaced using `envsubst`, depending on the git branch.
91 | skip_push: ${skip_release}
92 | image_templates:
93 | - "quay.io/fairwinds/gemini:{{ .FullCommit }}-amd64"
94 | - "quay.io/fairwinds/gemini:{{ .FullCommit }}-arm64"
95 | - name_template: quay.io/fairwinds/gemini:{{ .Tag }}
96 | # This is replaced using `envsubst`, depending on the git branch.
97 | skip_push: ${skip_release}
98 | image_templates:
99 | - "quay.io/fairwinds/gemini:{{ .FullCommit }}-amd64"
100 | - "quay.io/fairwinds/gemini:{{ .FullCommit }}-arm64"
101 | - name_template: quay.io/fairwinds/gemini:{{ .Major }}
102 | # This is replaced using `envsubst`, depending on the git branch.
103 | skip_push: ${skip_release}
104 | image_templates:
105 | - "quay.io/fairwinds/gemini:{{ .FullCommit }}-amd64"
106 | - "quay.io/fairwinds/gemini:{{ .FullCommit }}-arm64"
107 | - name_template: quay.io/fairwinds/gemini:{{ .Major }}.{{ .Minor }}
108 | # This is replaced using `envsubst`, depending on the git branch.
109 | skip_push: ${skip_release}
110 | image_templates:
111 | - "quay.io/fairwinds/gemini:{{ .FullCommit }}-amd64"
112 | - "quay.io/fairwinds/gemini:{{ .FullCommit }}-arm64"
113 |
--------------------------------------------------------------------------------
/.tool-versions:
--------------------------------------------------------------------------------
1 | golang 1.20
2 |
--------------------------------------------------------------------------------
/CODEOWNERS:
--------------------------------------------------------------------------------
1 | ## DO NOT EDIT - Managed by Terraform
2 | * @sudermanjr @azahorscak @TheCubicleJockey
3 |
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Contributor Covenant Code of Conduct
2 |
3 | ## Our Pledge
4 |
5 | In the interest of fostering an open and welcoming environment, we as
6 | contributors and maintainers pledge to making participation in our project and
7 | our community a harassment-free experience for everyone, regardless of age, body
8 | size, disability, ethnicity, gender identity and expression, level of experience,
9 | nationality, personal appearance, race, religion, or sexual identity and
10 | orientation.
11 |
12 | ## Our Standards
13 |
14 | Examples of behavior that contributes to creating a positive environment
15 | include:
16 |
17 | * Using welcoming and inclusive language
18 | * Being respectful of differing viewpoints and experiences
19 | * Gracefully accepting constructive criticism
20 | * Focusing on what is best for the community
21 | * Showing empathy towards other community members
22 |
23 | Examples of unacceptable behavior by participants include:
24 |
25 | * The use of sexualized language or imagery and unwelcome sexual attention or
26 | advances
27 | * Trolling, insulting/derogatory comments, and personal or political attacks
28 | * Public or private harassment
29 | * Publishing others' private information, such as a physical or electronic
30 | address, without explicit permission
31 | * Other conduct which could reasonably be considered inappropriate in a
32 | professional setting
33 |
34 | ## Our Responsibilities
35 |
36 | Project maintainers are responsible for clarifying the standards of acceptable
37 | behavior and are expected to take appropriate and fair corrective action in
38 | response to any instances of unacceptable behavior.
39 |
40 | Project maintainers have the right and responsibility to remove, edit, or
41 | reject comments, commits, code, wiki edits, issues, and other contributions
42 | that are not aligned to this Code of Conduct, or to ban temporarily or
43 | permanently any contributor for other behaviors that they deem inappropriate,
44 | threatening, offensive, or harmful.
45 |
46 | ## Scope
47 |
48 | This Code of Conduct applies both within project spaces and in public spaces
49 | when an individual is representing the project or its community. Examples of
50 | representing a project or community include using an official project e-mail
51 | address, posting via an official social media account, or acting as an appointed
52 | representative at an online or offline event. Representation of a project may be
53 | further defined and clarified by project maintainers.
54 |
55 | ## Enforcement
56 |
57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be
58 | reported by contacting the project team at opensource@fairwinds.com. All
59 | complaints will be reviewed and investigated and will result in a response that
60 | is deemed necessary and appropriate to the circumstances. The project team is
61 | obligated to maintain confidentiality with regard to the reporter of an incident.
62 | Further details of specific enforcement policies may be posted separately.
63 |
64 | Project maintainers who do not follow or enforce the Code of Conduct in good
65 | faith may face temporary or permanent repercussions as determined by other
66 | members of the project's leadership.
67 |
68 | ## Attribution
69 |
70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
71 | available at [http://contributor-covenant.org/version/1/4][version]
72 |
73 | [homepage]: http://contributor-covenant.org
74 | [version]: http://contributor-covenant.org/version/1/4/
75 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing
2 |
3 | Issues, whether bugs, tasks, or feature requests are essential for keeping Gemini great. We believe it should be as easy as possible to contribute changes that get things working in your environment. There are a few guidelines that we need contributors to follow so that we can keep on top of things.
4 |
5 | ## Code of Conduct
6 |
7 | This project adheres to a [code of conduct](CODE_OF_CONDUCT.md). Please review this document before contributing to this project.
8 |
9 | ## Sign the CLA
10 | Before you can contribute, you will need to sign the [Contributor License Agreement](https://cla-assistant.io/fairwindsops/gemini).
11 |
12 | ## Quickstart
13 | > Note: haven't managed to get KIND working with VolumeSnapshots
14 | > See https://github.com/rancher/local-path-provisioner/issues/81
15 |
16 | ```
17 | go run main.go &
18 | kubectl apply -f examples/hackmd/snapshotgroup.yaml
19 | kubectl get volumesnapshot --watch
20 | ```
21 |
22 | ## Development
23 |
24 | ### Project structure
25 | * `pkg/controller` - watches SnapshotGroup resources
26 | * `pkg/kube` - client for interacting with the Kubernetes API
27 | * `pkg/snapshots` - contains most of the logic for Gemini:
28 | * `pkg/snapshots/groups.go` - high-level logic for handling updates to SnapshotGroups
29 | * `pkg/snapshots/snapshots.go` - create, delete, and update VolumeSnapshots based on SnapshotGroups
30 | * `pkg/snapshots/pvc.go` - create, delete, and update PVCs based on changes to SnapshotGroups
31 | * `pkg/snapshots/scheduler.go` - logic for scheduling creation/deletion of VolumeSnapshots
32 |
33 | ### Generated files
34 | CRD generation mostly follows [this example](https://github.com/jinghzhu/KubernetesCRD)
35 | ```
36 | $GOPATH/src/k8s.io/code-generator/generate-groups.sh all \
37 | github.com/fairwindsops/gemini/pkg/types/snapshotgroup/v1beta1/apis \
38 | github.com/fairwindsops/gemini/pkg/types \
39 | "snapshotgroup:v1beta1"
40 | ```
41 |
42 | I had to manually edit
43 | pkg/types/snapshotgroup/v1beta1/apis/clientset/versioned/typed/snapshotgroup/v1beta1/snapshotgroup.go
44 | due to some complaints about a `context` argument getting passed in.
45 |
46 | ## Releases
47 | To release a new version of Gemini, tag the master branch with the format `x.x.x`,
48 | and push your tags.
49 |
50 | For minor/major upgrades, please update the
51 | [helm chart](https://github.com/FairwindsOps/charts/tree/master/stable/goldilocks) as well
52 |
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM alpine:3.17
2 |
3 | LABEL org.opencontainers.image.authors="FairwindsOps, Inc." \
4 | org.opencontainers.image.vendor="FairwindsOps, Inc." \
5 | org.opencontainers.image.title="gemini" \
6 | org.opencontainers.image.description="Automated backups of PersistentVolumeClaims in Kubernetes using VolumeSnapshots" \
7 | org.opencontainers.image.documentation="https://github.com/FairwindsOps/gemini" \
8 | org.opencontainers.image.source="https://github.com/FairwindsOps/gemini" \
9 | org.opencontainers.image.url="https://github.com/FairwindsOps/gemini" \
10 | org.opencontainers.image.licenses="Apache License 2.0"
11 |
12 | WORKDIR /usr/local/bin
13 | RUN apk -U upgrade
14 | RUN apk --no-cache add ca-certificates
15 |
16 | RUN addgroup -S gemini && adduser -u 1200 -S gemini -G gemini
17 | USER 1200
18 | COPY gemini .
19 |
20 | WORKDIR /opt/app
21 |
22 | CMD ["gemini"]
23 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "{}"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright 2019 FairwindsOps Inc
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |

3 |
4 |
5 | [![Version][version-image]][version-link] [![CircleCI][circleci-image]][circleci-link] [![Go Report Card][goreport-image]][goreport-link] [![Codecov][codecov-image]][codecov-link]
6 |
7 |
8 | [version-image]: https://img.shields.io/static/v1.svg?label=Version&message=0.0.1&color=239922
9 | [version-link]: https://github.com/FairwindsOps/gemini
10 |
11 | [goreport-image]: https://goreportcard.com/badge/github.com/FairwindsOps/gemini
12 | [goreport-link]: https://goreportcard.com/report/github.com/FairwindsOps/gemini
13 |
14 | [circleci-image]: https://circleci.com/gh/FairwindsOps/gemini.svg?style=svg
15 | [circleci-link]: https://circleci.com/gh/FairwindsOps/gemini
16 |
17 | [codecov-image]: https://codecov.io/gh/FairwindsOps/gemini/branch/master/graph/badge.svg?token=7C20K7SYNR
18 | [codecov-link]: https://codecov.io/gh/FairwindsOps/gemini
19 |
20 | Gemini is a Kubernetes CRD and operator for managing `VolumeSnapshots`. This allows you
21 | to create a snapshot of the data on your `PersistentVolumes` on a regular schedule,
22 | retire old snapshots, and restore snapshots with minimal downtime.
23 |
24 | ## Installation
25 | The Gemini Helm chart will install both the CRD and the operator into your cluster
26 |
27 | ```bash
28 | kubectl create ns gemini
29 | helm repo add fairwinds-stable https://charts.fairwinds.com/stable
30 | helm install gemini fairwinds-stable/gemini --namespace gemini
31 | ```
32 |
33 | ### Prerequisites
34 | You'll need to have the `VolumeSnapshot` API available in your cluster. This API is in
35 | [beta as of Kubernetes 1.17](https://kubernetes.io/docs/concepts/storage/volume-snapshots/),
36 | and was introduced as alpha in 1.12.
37 |
38 | To check if your cluster has `VolumeSnapshots` available, you can run
39 | ```bash
40 | kubectl api-resources | grep volumesnapshots
41 | ```
42 |
43 | * To enable on v1.12-16, set the flag `--feature-gates=VolumeSnapshotDataSource=true` on the API server binary [source](https://kubernetes.io/blog/2018/10/09/introducing-volume-snapshot-alpha-for-kubernetes/#kubernetes-snapshots-requirements)
44 | * To enable VolumeSnapshots on kops, see our [instructions here](/examples/bash)
45 | * Depending on your environment, you may need to configure the VolumeSnapshot API as well as the CSI. Fortunately, some managed Kubernetes providers like DigitalOcean support VolumeSnapshots by default, even on older versions
46 |
47 | Before getting started with Gemini, it's a good idea to make sure you're able to
48 | [create a VolumeSnapshot manually](https://kubernetes.io/docs/concepts/storage/volume-snapshots/#volumesnapshots).
49 |
50 | ### Upgrading to V2
51 | Version 2.0 of Gemini updates the CRD from `v1beta1` to `v1`. There are no substantial
52 | changes, but `v1` adds better support for PersistentVolumeClaims on Kubernetes 1.25.
53 |
54 | If you want to keep the v1beta1 CRD available, you can run:
55 | ```
56 | kubectl apply -f https://raw.githubusercontent.com/FairwindsOps/gemini/main/pkg/types/snapshotgroup/v1beta1/crd-with-beta1.yaml
57 | ```
58 | before upgrading, and add `--skip-crds` when running `helm install`.
59 |
60 | ## Usage
61 |
62 | ### Snapshots
63 | Gemini can schedule snapshots for an existing PVC, or create a new PVC to back up.
64 |
65 | #### Schedules
66 |
67 | The `schedule` parameter tells Gemini how often to create snapshots, and how many historical snapshots to keep.
68 |
69 | For example, the following schedule tells Gemini to create a snapshot every day, keeping two weeks worth of history:
70 | ```yaml
71 | apiVersion: gemini.fairwinds.com/v1
72 | kind: SnapshotGroup
73 | metadata:
74 | name: test-volume
75 | spec:
76 | persistentVolumeClaim:
77 | claimName: postgres
78 | schedule:
79 | - every: day
80 | keep: 14
81 | ```
82 |
83 | For a more complex example, Gemini can create new snapshots every 10 minutes,
84 | always keep the last 3 snapshots, and preserve historical hourly, daily, monthly, and yearly snapshots.
85 |
86 | ```yaml
87 | apiVersion: gemini.fairwinds.com/v1
88 | kind: SnapshotGroup
89 | metadata:
90 | name: test-volume
91 | spec:
92 | persistentVolumeClaim:
93 | claimName: postgres
94 | schedule:
95 | - every: 10 minutes
96 | keep: 3
97 | - every: hour
98 | keep: 1
99 | - every: day
100 | keep: 1
101 | - every: month
102 | keep: 1
103 | - every: year
104 | keep: 1
105 | ```
106 |
107 | Note that `keep` specifies how many historical snapshots you want, _in addition_ to the most recent snapshot.
108 | This way the schedule
109 | ```yaml
110 | - every: 10 minutes
111 | keep: 3
112 | ```
113 | will always give you _at least_ 30 minutes of snapshot coverage. But you will see four snapshots at any given time.
114 | E.g. right after a new snapshot is created, you'll see snapshots for
115 | * 0m ago
116 | * 10m ago
117 | * 20m ago
118 | * 30m ago
119 |
120 |
121 | #### Using an Existing PVC
122 | > See the [extended example](/examples/codimd/README.md)
123 | The following example schedules snapshots every 10 minutes for a pre-existing PVC named `postgres`.
124 |
125 | ```yaml
126 | apiVersion: gemini.fairwinds.com/v1
127 | kind: SnapshotGroup
128 | metadata:
129 | name: test-volume
130 | spec:
131 | persistentVolumeClaim:
132 | claimName: postgres
133 | schedule:
134 | - every: 10 minutes
135 | keep: 3
136 | ```
137 |
138 | #### Creating a New PVC
139 | You can also specify an entire PVC spec inside the SnapshotGroup if you'd like Gemini to create
140 | the PVC for you.
141 | ```yaml
142 | apiVersion: gemini.fairwinds.com/v1
143 | kind: SnapshotGroup
144 | metadata:
145 | name: test-volume
146 | spec:
147 | persistentVolumeClaim:
148 | spec:
149 | accessModes:
150 | - ReadWriteOnce
151 | resources:
152 | requests:
153 | storage: 1Gi
154 | schedule:
155 | - every: 10 minutes
156 | keep: 3
157 | ```
158 |
159 | The PVC will have the same name as the SnapshotGroup, (in this example, `test-volume`)
160 |
161 | #### Snapshot Spec
162 | You can use the `spec.template` field to set the template for any `VolumeSnapshots` that get created,
163 | most notably the name of the [snapshot class](https://kubernetes.io/docs/concepts/storage/volume-snapshot-classes/)
164 | you want to use.
165 |
166 | ```yaml
167 | apiVersion: gemini.fairwinds.com/v1
168 | kind: SnapshotGroup
169 | metadata:
170 | name: test-volume
171 | spec:
172 | persistentVolumeClaim:
173 | claimName: postgres
174 | schedule:
175 | - every: "10 minutes"
176 | keep: 3
177 | template:
178 | spec:
179 | volumeSnapshotClassName: test-snapshot-class
180 | ```
181 |
182 | ### Restore
183 | > Caution: you cannot alter a PVC without some downtime!
184 | You can restore your PVC to a particular point in time using an annotation.
185 |
186 | First, check out what `VolumeSnapshots` are available:
187 | ```bash
188 | $ kubectl get volumesnapshot
189 | NAME AGE
190 | test-volume-1585945609 15s
191 | ```
192 |
193 | Next, you'll need to remove any Pods that are using the PVC:
194 | ```bash
195 | $ kubectl scale all --all --replicas=0
196 | ```
197 |
198 | Then, copy the timestamp from the first step, and use that to annotate the `SnapshotGroup`:
199 | ```bash
200 | $ kubectl annotate snapshotgroup/test-volume --overwrite \
201 | "gemini.fairwinds.com/restore=1585945609"
202 | ```
203 |
204 | Finally, you can scale your Pods back up:
205 | ```bash
206 | $ kubectl scale all --all --replicas=1
207 | ```
208 |
209 | ## End-to-End Example
210 | To see gemini working end-to-end, check out [the CodiMD example](examples/codimd)
211 |
212 | ## Caveats
213 | * Like the VolumeSnapshot API it builds on, Gemini is **currently in beta**
214 | * Be sure to test out both the snapshot and restore process to ensure Gemini is working properly
215 | * VolumeSnapshots simply grab the current state of the volume, without respect for things like in-flight database transactions. You may find you need to stop the application in order to get a consistently usable VolumeSnapshot.
216 |
217 |
218 | ## Join the Fairwinds Open Source Community
219 |
220 | The goal of the Fairwinds Community is to exchange ideas, influence the open source roadmap,
221 | and network with fellow Kubernetes users.
222 | [Chat with us on Slack](https://join.slack.com/t/fairwindscommunity/shared_invite/zt-e3c6vj4l-3lIH6dvKqzWII5fSSFDi1g)
223 | [join the user group](https://www.fairwinds.com/open-source-software-user-group) to get involved!
224 |
225 |
226 |
227 |
228 |
229 | ## Other Projects from Fairwinds
230 |
231 | Enjoying Gemini? Check out some of our other projects:
232 | * [Polaris](https://github.com/FairwindsOps/Polaris) - Audit, enforce, and build policies for Kubernetes resources, including over 20 built-in checks for best practices
233 | * [Goldilocks](https://github.com/FairwindsOps/Goldilocks) - Right-size your Kubernetes Deployments by compare your memory and CPU settings against actual usage
234 | * [Pluto](https://github.com/FairwindsOps/Pluto) - Detect Kubernetes resources that have been deprecated or removed in future versions
235 | * [Nova](https://github.com/FairwindsOps/Nova) - Check to see if any of your Helm charts have updates available
236 | * [rbac-manager](https://github.com/FairwindsOps/rbac-manager) - Simplify the management of RBAC in your Kubernetes clusters
237 |
--------------------------------------------------------------------------------
/codecov.yml:
--------------------------------------------------------------------------------
1 | comment: false
2 | coverage:
3 | range: 50...80
4 | ignore:
5 | - pkg/types
6 | - pkg/kube/client.go
7 |
--------------------------------------------------------------------------------
/examples/bash/01-create-namespace.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Namespace
3 | metadata:
4 | name: ebs-gemini-testing
--------------------------------------------------------------------------------
/examples/bash/02-create-storageclass.yaml:
--------------------------------------------------------------------------------
1 | kind: StorageClass
2 | apiVersion: storage.k8s.io/v1
3 | metadata:
4 | name: ebs-sc
5 | provisioner: ebs.csi.aws.com
6 | volumeBindingMode: WaitForFirstConsumer
7 |
--------------------------------------------------------------------------------
/examples/bash/03-create-volumesnapshotclass.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: snapshot.storage.k8s.io/v1
2 | kind: VolumeSnapshotClass
3 | metadata:
4 | name: aws-ebs-snapclass
5 | annotations:
6 | snapshot.storage.kubernetes.io/is-default-class: "true"
7 | driver: ebs.csi.aws.com #AWS EBS
8 | deletionPolicy: Delete
--------------------------------------------------------------------------------
/examples/bash/04-create-snapshotgroup.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: gemini.fairwinds.com/v1
2 | kind: SnapshotGroup
3 | metadata:
4 | name: ebs-gemini-testing
5 | namespace: ebs-gemini-testing
6 | spec:
7 | template:
8 | spec:
9 | volumeSnapshotClassName: aws-ebs-snapclass
10 | persistentVolumeClaim:
11 | spec:
12 | storageClassName: ebs-sc
13 | accessModes:
14 | - ReadWriteOnce
15 | resources:
16 | requests:
17 | storage: 1Gi
18 | schedule:
19 | - every: "10 minutes"
20 | keep: 3
21 | - every: hour
22 | keep: 1
23 |
--------------------------------------------------------------------------------
/examples/bash/05-create-pod.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Pod
3 | metadata:
4 | name: app
5 | namespace: ebs-gemini-testing
6 | spec:
7 | containers:
8 | - name: app
9 | image: centos
10 | command: ["/bin/sh"]
11 | args: ["-c", "while true; do echo $(date -u) >> /data/out.txt; sleep 5; done"]
12 | volumeMounts:
13 | - name: persistent-storage
14 | mountPath: /data
15 | volumes:
16 | - name: persistent-storage
17 | persistentVolumeClaim:
18 | claimName: ebs-gemini-testing
19 | ## after pod is provisioned, you can see it writing to EBS volume
20 | ## kubectl exec -it -n ebs-gemini-testing app cat /data/out.txt
--------------------------------------------------------------------------------
/examples/bash/README.md:
--------------------------------------------------------------------------------
1 | # Gemini Example: bash timestamping
2 | > Note: this is a work in progress. Adding this as a simple test case that illustrates the steps and components necessary to demonstrate a Gemini SnapshotGroup. This example creates a SnapshotGroup in a namespace where no previous PersistentVolumeClaims or PersistentVolumes exist; the SnapshotGroup generates a PVC based on the details specified in the SnapshotGroup's `spec.claim.spec`, and then starts creating VolumeSnapshots of that volume every 10 minutes. An example pod mounts the PVC.
3 |
4 | Before you can work with Gemini and Gemini's SnapshotGroups, you need to ensure that you have an appropriate CSI driver installed for your particular environment, as well as the CSI snapshotter and associated APIs. DigitalOcean clusters seem to have this included. Kops clusters do not.
5 |
6 |
7 |
8 | ## Gemini Installation on clusters that already have CSI configured
9 |
10 | ```
11 | kubectl create ns gemini
12 | helm install gemini deploy/charts/gemini --namespace gemini
13 | ```
14 |
15 | ## Gemini Installation on Kops 1.17+ clusters that do not have CSI configured
16 |
17 | Run the provided `course.yaml` file with [Reckoner](https://github.com/fairwindsops/reckoner) to install all the prerequisites for Gemini (such as the EBS CSI Driver and external-snapshotter), as well as Gemini itself.
18 |
19 | ## Deploy the demo resources
20 |
21 | Apply the provided Kubernetes manifests in the number in which they're ordered: `01-create-namespace.yaml`, `02-create-storage-class.yaml`, and so on. You'll be creating the temporary demo namespace, the StorageClass to be utilized by the volume, the VolumeSnapshotClass to be utilized by the VolumeSnapshots, the Gemini SnapshotGroup, and a test pod that will mount the example Volume. Soon after applying, you'll be able to see that gemini is successfully generating VolumeSnapshots for you!
22 |
23 | ```kubectl get volumesnapshot
24 | NAME READYTOUSE SOURCEPVC SOURCESNAPSHOTCONTENT RESTORESIZE SNAPSHOTCLASS SNAPSHOTCONTENT CREATIONTIME AGE
25 | ebs-gemini-testing-1591205245 true ebs-gemini-testing 1Gi aws-ebs-snapclass snapcontent-96ab9a23-0d60-413d-af0f-b01d3880f3e7 83m 83m
26 | ```
27 |
28 | Accordingly, you'll see the associated snapshots on your cloud provider of choice. For example, with AWS:
29 |
30 | ```
31 | aws ec2 describe-snapshots --owner-ids
32 | {
33 | "Snapshots": [
34 | {
35 | "Description": "Created by AWS EBS CSI driver for volume ",
36 | "Encrypted": false,
37 | "OwnerId": "",
38 | "Progress": "100%",
39 | "SnapshotId": "snap-0224fb2ee42613b56",
40 | "StartTime": "2020-06-03T17:27:25.362Z",
41 | "State": "completed",
42 | "VolumeId": "",
43 | "VolumeSize": 1,
44 | "Tags": [
45 | {
46 | "Key": "CSIVolumeSnapshotName",
47 | "Value": "snapshot-96ab9a23-0d60-413d-af0f-b01d3880f3e7"
48 | }
49 | ]
50 | }
51 | ]
52 | }
53 | ```
54 |
--------------------------------------------------------------------------------
/examples/bash/course.yaml:
--------------------------------------------------------------------------------
1 | namespace: gemini
2 | charts:
3 | gemini:
4 | chart: gemini
5 | version: 0.0.1
6 | repository: ../../deploy/charts/
7 | hooks:
8 | pre_install:
9 | # install the AWS EBS CSI driver, the snapshotter, its controller, and associated CRDs first
10 | - kubectl apply -k "github.com/kubernetes-sigs/aws-ebs-csi-driver/deploy/kubernetes/overlays/stable/?ref=master"
11 | - kubectl apply -f https://raw.githubusercontent.com/kubernetes-csi/external-snapshotter/master/client/config/crd/snapshot.storage.k8s.io_volumesnapshotclasses.yaml
12 | - kubectl apply -f https://raw.githubusercontent.com/kubernetes-csi/external-snapshotter/master/client/config/crd/snapshot.storage.k8s.io_volumesnapshots.yaml
13 | - kubectl apply -f https://raw.githubusercontent.com/kubernetes-csi/external-snapshotter/master/client/config/crd/snapshot.storage.k8s.io_volumesnapshotcontents.yaml
--------------------------------------------------------------------------------
/examples/codimd/README.md:
--------------------------------------------------------------------------------
1 | # Gemini Example: CodiMD
2 | > Note: this will not work in a KIND cluster. It has been tested on DigitalOcean.
3 |
4 | ### Install the controller
5 | ```bash
6 | helm repo add fairwinds-stable https://charts.fairwinds.com/stable
7 | helm install gemini fairwinds-stable/gemini --namespace gemini --create-namespace
8 | ```
9 |
10 | ### Install CodiMD
11 | ```bash
12 | helm repo add codimd https://helm.codimd.dev/
13 | helm upgrade --install codimd codimd/codimd -n codimd --create-namespace --set codimd.imageStorePersistentVolume.enabled=false
14 | ```
15 |
16 | This will create a PVC for the Postgres instance that drives CodiMD.
17 |
18 | ### Set up the Backup Schedule
19 | ```bash
20 | cat < 0 {
61 | if configShallowCopy.Burst <= 0 {
62 | return nil, fmt.Errorf("burst is required to be greater than 0 when RateLimiter is not set and QPS is set to greater than 0")
63 | }
64 | configShallowCopy.RateLimiter = flowcontrol.NewTokenBucketRateLimiter(configShallowCopy.QPS, configShallowCopy.Burst)
65 | }
66 | var cs Clientset
67 | var err error
68 | cs.snapshotgroupV1, err = snapshotgroupv1.NewForConfig(&configShallowCopy)
69 | if err != nil {
70 | return nil, err
71 | }
72 |
73 | cs.DiscoveryClient, err = discovery.NewDiscoveryClientForConfig(&configShallowCopy)
74 | if err != nil {
75 | return nil, err
76 | }
77 | return &cs, nil
78 | }
79 |
80 | // NewForConfigOrDie creates a new Clientset for the given config and
81 | // panics if there is an error in the config.
82 | func NewForConfigOrDie(c *rest.Config) *Clientset {
83 | var cs Clientset
84 | cs.snapshotgroupV1 = snapshotgroupv1.NewForConfigOrDie(c)
85 |
86 | cs.DiscoveryClient = discovery.NewDiscoveryClientForConfigOrDie(c)
87 | return &cs
88 | }
89 |
90 | // New creates a new Clientset for the given RESTClient.
91 | func New(c rest.Interface) *Clientset {
92 | var cs Clientset
93 | cs.snapshotgroupV1 = snapshotgroupv1.New(c)
94 |
95 | cs.DiscoveryClient = discovery.NewDiscoveryClient(c)
96 | return &cs
97 | }
98 |
--------------------------------------------------------------------------------
/pkg/types/snapshotgroup/v1/apis/clientset/versioned/doc.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright The Kubernetes Authors.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | // Code generated by client-gen. DO NOT EDIT.
18 |
19 | // This package has the automatically generated clientset.
20 | package versioned
21 |
--------------------------------------------------------------------------------
/pkg/types/snapshotgroup/v1/apis/clientset/versioned/fake/clientset_generated.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright The Kubernetes Authors.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | // Code generated by client-gen. DO NOT EDIT.
18 |
19 | package fake
20 |
21 | import (
22 | clientset "github.com/fairwindsops/gemini/pkg/types/snapshotgroup/v1/apis/clientset/versioned"
23 | snapshotgroupv1 "github.com/fairwindsops/gemini/pkg/types/snapshotgroup/v1/apis/clientset/versioned/typed/snapshotgroup/v1"
24 | fakesnapshotgroupv1 "github.com/fairwindsops/gemini/pkg/types/snapshotgroup/v1/apis/clientset/versioned/typed/snapshotgroup/v1/fake"
25 | "k8s.io/apimachinery/pkg/runtime"
26 | "k8s.io/apimachinery/pkg/watch"
27 | "k8s.io/client-go/discovery"
28 | fakediscovery "k8s.io/client-go/discovery/fake"
29 | "k8s.io/client-go/testing"
30 | )
31 |
32 | // NewSimpleClientset returns a clientset that will respond with the provided objects.
33 | // It's backed by a very simple object tracker that processes creates, updates and deletions as-is,
34 | // without applying any validations and/or defaults. It shouldn't be considered a replacement
35 | // for a real clientset and is mostly useful in simple unit tests.
36 | func NewSimpleClientset(objects ...runtime.Object) *Clientset {
37 | o := testing.NewObjectTracker(scheme, codecs.UniversalDecoder())
38 | for _, obj := range objects {
39 | if err := o.Add(obj); err != nil {
40 | panic(err)
41 | }
42 | }
43 |
44 | cs := &Clientset{tracker: o}
45 | cs.discovery = &fakediscovery.FakeDiscovery{Fake: &cs.Fake}
46 | cs.AddReactor("*", "*", testing.ObjectReaction(o))
47 | cs.AddWatchReactor("*", func(action testing.Action) (handled bool, ret watch.Interface, err error) {
48 | gvr := action.GetResource()
49 | ns := action.GetNamespace()
50 | watch, err := o.Watch(gvr, ns)
51 | if err != nil {
52 | return false, nil, err
53 | }
54 | return true, watch, nil
55 | })
56 |
57 | return cs
58 | }
59 |
60 | // Clientset implements clientset.Interface. Meant to be embedded into a
61 | // struct to get a default implementation. This makes faking out just the method
62 | // you want to test easier.
63 | type Clientset struct {
64 | testing.Fake
65 | discovery *fakediscovery.FakeDiscovery
66 | tracker testing.ObjectTracker
67 | }
68 |
69 | func (c *Clientset) Discovery() discovery.DiscoveryInterface {
70 | return c.discovery
71 | }
72 |
73 | func (c *Clientset) Tracker() testing.ObjectTracker {
74 | return c.tracker
75 | }
76 |
77 | var _ clientset.Interface = &Clientset{}
78 |
79 | // SnapshotgroupV1 retrieves the SnapshotgroupV1Client
80 | func (c *Clientset) SnapshotgroupV1() snapshotgroupv1.SnapshotgroupV1Interface {
81 | return &fakesnapshotgroupv1.FakeSnapshotgroupV1{Fake: &c.Fake}
82 | }
83 |
--------------------------------------------------------------------------------
/pkg/types/snapshotgroup/v1/apis/clientset/versioned/fake/doc.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright The Kubernetes Authors.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | // Code generated by client-gen. DO NOT EDIT.
18 |
19 | // This package has the automatically generated fake clientset.
20 | package fake
21 |
--------------------------------------------------------------------------------
/pkg/types/snapshotgroup/v1/apis/clientset/versioned/fake/register.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright The Kubernetes Authors.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | // Code generated by client-gen. DO NOT EDIT.
18 |
19 | package fake
20 |
21 | import (
22 | snapshotgroupv1 "github.com/fairwindsops/gemini/pkg/types/snapshotgroup/v1"
23 | v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
24 | runtime "k8s.io/apimachinery/pkg/runtime"
25 | schema "k8s.io/apimachinery/pkg/runtime/schema"
26 | serializer "k8s.io/apimachinery/pkg/runtime/serializer"
27 | utilruntime "k8s.io/apimachinery/pkg/util/runtime"
28 | )
29 |
30 | var scheme = runtime.NewScheme()
31 | var codecs = serializer.NewCodecFactory(scheme)
32 |
33 | var localSchemeBuilder = runtime.SchemeBuilder{
34 | snapshotgroupv1.AddToScheme,
35 | }
36 |
37 | // AddToScheme adds all types of this clientset into the given scheme. This allows composition
38 | // of clientsets, like in:
39 | //
40 | // import (
41 | // "k8s.io/client-go/kubernetes"
42 | // clientsetscheme "k8s.io/client-go/kubernetes/scheme"
43 | // aggregatorclientsetscheme "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/scheme"
44 | // )
45 | //
46 | // kclientset, _ := kubernetes.NewForConfig(c)
47 | // _ = aggregatorclientsetscheme.AddToScheme(clientsetscheme.Scheme)
48 | //
49 | // After this, RawExtensions in Kubernetes types will serialize kube-aggregator types
50 | // correctly.
51 | var AddToScheme = localSchemeBuilder.AddToScheme
52 |
53 | func init() {
54 | v1.AddToGroupVersion(scheme, schema.GroupVersion{Version: "v1"})
55 | utilruntime.Must(AddToScheme(scheme))
56 | }
57 |
--------------------------------------------------------------------------------
/pkg/types/snapshotgroup/v1/apis/clientset/versioned/scheme/doc.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright The Kubernetes Authors.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | // Code generated by client-gen. DO NOT EDIT.
18 |
19 | // This package contains the scheme of the automatically generated clientset.
20 | package scheme
21 |
--------------------------------------------------------------------------------
/pkg/types/snapshotgroup/v1/apis/clientset/versioned/scheme/register.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright The Kubernetes Authors.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | // Code generated by client-gen. DO NOT EDIT.
18 |
19 | package scheme
20 |
21 | import (
22 | snapshotgroupv1 "github.com/fairwindsops/gemini/pkg/types/snapshotgroup/v1"
23 | v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
24 | runtime "k8s.io/apimachinery/pkg/runtime"
25 | schema "k8s.io/apimachinery/pkg/runtime/schema"
26 | serializer "k8s.io/apimachinery/pkg/runtime/serializer"
27 | utilruntime "k8s.io/apimachinery/pkg/util/runtime"
28 | )
29 |
30 | var Scheme = runtime.NewScheme()
31 | var Codecs = serializer.NewCodecFactory(Scheme)
32 | var ParameterCodec = runtime.NewParameterCodec(Scheme)
33 | var localSchemeBuilder = runtime.SchemeBuilder{
34 | snapshotgroupv1.AddToScheme,
35 | }
36 |
37 | // AddToScheme adds all types of this clientset into the given scheme. This allows composition
38 | // of clientsets, like in:
39 | //
40 | // import (
41 | // "k8s.io/client-go/kubernetes"
42 | // clientsetscheme "k8s.io/client-go/kubernetes/scheme"
43 | // aggregatorclientsetscheme "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/scheme"
44 | // )
45 | //
46 | // kclientset, _ := kubernetes.NewForConfig(c)
47 | // _ = aggregatorclientsetscheme.AddToScheme(clientsetscheme.Scheme)
48 | //
49 | // After this, RawExtensions in Kubernetes types will serialize kube-aggregator types
50 | // correctly.
51 | var AddToScheme = localSchemeBuilder.AddToScheme
52 |
53 | func init() {
54 | v1.AddToGroupVersion(Scheme, schema.GroupVersion{Version: "v1"})
55 | utilruntime.Must(AddToScheme(Scheme))
56 | }
57 |
--------------------------------------------------------------------------------
/pkg/types/snapshotgroup/v1/apis/clientset/versioned/typed/snapshotgroup/v1/doc.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright The Kubernetes Authors.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | // Code generated by client-gen. DO NOT EDIT.
18 |
19 | // This package has the automatically generated typed clients.
20 | package v1
21 |
--------------------------------------------------------------------------------
/pkg/types/snapshotgroup/v1/apis/clientset/versioned/typed/snapshotgroup/v1/fake/doc.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright The Kubernetes Authors.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | // Code generated by client-gen. DO NOT EDIT.
18 |
19 | // Package fake has the automatically generated clients.
20 | package fake
21 |
--------------------------------------------------------------------------------
/pkg/types/snapshotgroup/v1/apis/clientset/versioned/typed/snapshotgroup/v1/fake/fake_snapshotgroup.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright The Kubernetes Authors.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | // Code generated by client-gen. DO NOT EDIT.
18 |
19 | package fake
20 |
21 | import (
22 | "context"
23 |
24 | v1 "github.com/fairwindsops/gemini/pkg/types/snapshotgroup/v1"
25 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
26 | labels "k8s.io/apimachinery/pkg/labels"
27 | schema "k8s.io/apimachinery/pkg/runtime/schema"
28 | types "k8s.io/apimachinery/pkg/types"
29 | watch "k8s.io/apimachinery/pkg/watch"
30 | testing "k8s.io/client-go/testing"
31 | )
32 |
33 | // FakeSnapshotGroups implements SnapshotGroupInterface
34 | type FakeSnapshotGroups struct {
35 | Fake *FakeSnapshotgroupV1
36 | ns string
37 | }
38 |
39 | var snapshotgroupsResource = schema.GroupVersionResource{Group: "snapshotgroup", Version: "v1", Resource: "snapshotgroups"}
40 |
41 | var snapshotgroupsKind = schema.GroupVersionKind{Group: "snapshotgroup", Version: "v1", Kind: "SnapshotGroup"}
42 |
43 | // Get takes name of the snapshotGroup, and returns the corresponding snapshotGroup object, and an error if there is any.
44 | func (c *FakeSnapshotGroups) Get(ctx context.Context, name string, options metav1.GetOptions) (result *v1.SnapshotGroup, err error) {
45 | obj, err := c.Fake.
46 | Invokes(testing.NewGetAction(snapshotgroupsResource, c.ns, name), &v1.SnapshotGroup{})
47 |
48 | if obj == nil {
49 | return nil, err
50 | }
51 | return obj.(*v1.SnapshotGroup), err
52 | }
53 |
54 | // List takes label and field selectors, and returns the list of SnapshotGroups that match those selectors.
55 | func (c *FakeSnapshotGroups) List(ctx context.Context, opts metav1.ListOptions) (result *v1.SnapshotGroupList, err error) {
56 | obj, err := c.Fake.
57 | Invokes(testing.NewListAction(snapshotgroupsResource, snapshotgroupsKind, c.ns, opts), &v1.SnapshotGroupList{})
58 |
59 | if obj == nil {
60 | return nil, err
61 | }
62 |
63 | label, _, _ := testing.ExtractFromListOptions(opts)
64 | if label == nil {
65 | label = labels.Everything()
66 | }
67 | list := &v1.SnapshotGroupList{ListMeta: obj.(*v1.SnapshotGroupList).ListMeta}
68 | for _, item := range obj.(*v1.SnapshotGroupList).Items {
69 | if label.Matches(labels.Set(item.Labels)) {
70 | list.Items = append(list.Items, item)
71 | }
72 | }
73 | return list, err
74 | }
75 |
76 | // Watch returns a watch.Interface that watches the requested snapshotGroups.
77 | func (c *FakeSnapshotGroups) Watch(ctx context.Context, opts metav1.ListOptions) (watch.Interface, error) {
78 | return c.Fake.
79 | InvokesWatch(testing.NewWatchAction(snapshotgroupsResource, c.ns, opts))
80 |
81 | }
82 |
83 | // Create takes the representation of a snapshotGroup and creates it. Returns the server's representation of the snapshotGroup, and an error, if there is any.
84 | func (c *FakeSnapshotGroups) Create(ctx context.Context, snapshotGroup *v1.SnapshotGroup, opts metav1.CreateOptions) (result *v1.SnapshotGroup, err error) {
85 | obj, err := c.Fake.
86 | Invokes(testing.NewCreateAction(snapshotgroupsResource, c.ns, snapshotGroup), &v1.SnapshotGroup{})
87 |
88 | if obj == nil {
89 | return nil, err
90 | }
91 | return obj.(*v1.SnapshotGroup), err
92 | }
93 |
94 | // Update takes the representation of a snapshotGroup and updates it. Returns the server's representation of the snapshotGroup, and an error, if there is any.
95 | func (c *FakeSnapshotGroups) Update(ctx context.Context, snapshotGroup *v1.SnapshotGroup, opts metav1.UpdateOptions) (result *v1.SnapshotGroup, err error) {
96 | obj, err := c.Fake.
97 | Invokes(testing.NewUpdateAction(snapshotgroupsResource, c.ns, snapshotGroup), &v1.SnapshotGroup{})
98 |
99 | if obj == nil {
100 | return nil, err
101 | }
102 | return obj.(*v1.SnapshotGroup), err
103 | }
104 |
105 | // Delete takes name of the snapshotGroup and deletes it. Returns an error if one occurs.
106 | func (c *FakeSnapshotGroups) Delete(ctx context.Context, name string, opts metav1.DeleteOptions) error {
107 | _, err := c.Fake.
108 | Invokes(testing.NewDeleteAction(snapshotgroupsResource, c.ns, name), &v1.SnapshotGroup{})
109 |
110 | return err
111 | }
112 |
113 | // DeleteCollection deletes a collection of objects.
114 | func (c *FakeSnapshotGroups) DeleteCollection(ctx context.Context, opts metav1.DeleteOptions, listOpts metav1.ListOptions) error {
115 | action := testing.NewDeleteCollectionAction(snapshotgroupsResource, c.ns, listOpts)
116 |
117 | _, err := c.Fake.Invokes(action, &v1.SnapshotGroupList{})
118 | return err
119 | }
120 |
121 | // Patch applies the patch and returns the patched snapshotGroup.
122 | func (c *FakeSnapshotGroups) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts metav1.PatchOptions, subresources ...string) (result *v1.SnapshotGroup, err error) {
123 | obj, err := c.Fake.
124 | Invokes(testing.NewPatchSubresourceAction(snapshotgroupsResource, c.ns, name, pt, data, subresources...), &v1.SnapshotGroup{})
125 |
126 | if obj == nil {
127 | return nil, err
128 | }
129 | return obj.(*v1.SnapshotGroup), err
130 | }
131 |
--------------------------------------------------------------------------------
/pkg/types/snapshotgroup/v1/apis/clientset/versioned/typed/snapshotgroup/v1/fake/fake_snapshotgroup_client.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright The Kubernetes Authors.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | // Code generated by client-gen. DO NOT EDIT.
18 |
19 | package fake
20 |
21 | import (
22 | v1 "github.com/fairwindsops/gemini/pkg/types/snapshotgroup/v1/apis/clientset/versioned/typed/snapshotgroup/v1"
23 | rest "k8s.io/client-go/rest"
24 | testing "k8s.io/client-go/testing"
25 | )
26 |
27 | type FakeSnapshotgroupV1 struct {
28 | *testing.Fake
29 | }
30 |
31 | func (c *FakeSnapshotgroupV1) SnapshotGroups(namespace string) v1.SnapshotGroupInterface {
32 | return &FakeSnapshotGroups{c, namespace}
33 | }
34 |
35 | // RESTClient returns a RESTClient that is used to communicate
36 | // with API server by this client implementation.
37 | func (c *FakeSnapshotgroupV1) RESTClient() rest.Interface {
38 | var ret *rest.RESTClient
39 | return ret
40 | }
41 |
--------------------------------------------------------------------------------
/pkg/types/snapshotgroup/v1/apis/clientset/versioned/typed/snapshotgroup/v1/generated_expansion.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright The Kubernetes Authors.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | // Code generated by client-gen. DO NOT EDIT.
18 |
19 | package v1
20 |
21 | type SnapshotGroupExpansion interface{}
22 |
--------------------------------------------------------------------------------
/pkg/types/snapshotgroup/v1/apis/clientset/versioned/typed/snapshotgroup/v1/snapshotgroup.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright The Kubernetes Authors.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | // Code generated by client-gen. DO NOT EDIT.
18 |
19 | package v1
20 |
21 | import (
22 | "context"
23 | "time"
24 |
25 | snapshotgroupv1 "github.com/fairwindsops/gemini/pkg/types/snapshotgroup/v1"
26 | scheme "github.com/fairwindsops/gemini/pkg/types/snapshotgroup/v1/apis/clientset/versioned/scheme"
27 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
28 | types "k8s.io/apimachinery/pkg/types"
29 | watch "k8s.io/apimachinery/pkg/watch"
30 | rest "k8s.io/client-go/rest"
31 | )
32 |
33 | // SnapshotGroupsGetter has a method to return a SnapshotGroupInterface.
34 | // A group's client should implement this interface.
35 | type SnapshotGroupsGetter interface {
36 | SnapshotGroups(namespace string) SnapshotGroupInterface
37 | }
38 |
39 | // SnapshotGroupInterface has methods to work with SnapshotGroup resources.
40 | type SnapshotGroupInterface interface {
41 | Create(ctx context.Context, snapshotGroup *snapshotgroupv1.SnapshotGroup, opts metav1.CreateOptions) (*snapshotgroupv1.SnapshotGroup, error)
42 | Update(ctx context.Context, snapshotGroup *snapshotgroupv1.SnapshotGroup, opts metav1.UpdateOptions) (*snapshotgroupv1.SnapshotGroup, error)
43 | Delete(ctx context.Context, name string, opts metav1.DeleteOptions) error
44 | DeleteCollection(ctx context.Context, opts metav1.DeleteOptions, listOpts metav1.ListOptions) error
45 | Get(ctx context.Context, name string, opts metav1.GetOptions) (*snapshotgroupv1.SnapshotGroup, error)
46 | List(ctx context.Context, opts metav1.ListOptions) (*snapshotgroupv1.SnapshotGroupList, error)
47 | Watch(ctx context.Context, opts metav1.ListOptions) (watch.Interface, error)
48 | Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts metav1.PatchOptions, subresources ...string) (result *snapshotgroupv1.SnapshotGroup, err error)
49 | SnapshotGroupExpansion
50 | }
51 |
52 | // snapshotGroups implements SnapshotGroupInterface
53 | type snapshotGroups struct {
54 | client rest.Interface
55 | ns string
56 | }
57 |
58 | // newSnapshotGroups returns a SnapshotGroups
59 | func newSnapshotGroups(c *SnapshotgroupV1Client, namespace string) *snapshotGroups {
60 | return &snapshotGroups{
61 | client: c.RESTClient(),
62 | ns: namespace,
63 | }
64 | }
65 |
66 | // Get takes name of the snapshotGroup, and returns the corresponding snapshotGroup object, and an error if there is any.
67 | func (c *snapshotGroups) Get(ctx context.Context, name string, options metav1.GetOptions) (result *snapshotgroupv1.SnapshotGroup, err error) {
68 | result = &snapshotgroupv1.SnapshotGroup{}
69 | err = c.client.Get().
70 | Namespace(c.ns).
71 | Resource("snapshotgroups").
72 | Name(name).
73 | VersionedParams(&options, scheme.ParameterCodec).
74 | Do(ctx).
75 | Into(result)
76 | return
77 | }
78 |
79 | // List takes label and field selectors, and returns the list of SnapshotGroups that match those selectors.
80 | func (c *snapshotGroups) List(ctx context.Context, opts metav1.ListOptions) (result *snapshotgroupv1.SnapshotGroupList, err error) {
81 | var timeout time.Duration
82 | if opts.TimeoutSeconds != nil {
83 | timeout = time.Duration(*opts.TimeoutSeconds) * time.Second
84 | }
85 | result = &snapshotgroupv1.SnapshotGroupList{}
86 | err = c.client.Get().
87 | Namespace(c.ns).
88 | Resource("snapshotgroups").
89 | VersionedParams(&opts, scheme.ParameterCodec).
90 | Timeout(timeout).
91 | Do(ctx).
92 | Into(result)
93 | return
94 | }
95 |
96 | // Watch returns a watch.Interface that watches the requested snapshotGroups.
97 | func (c *snapshotGroups) Watch(ctx context.Context, opts metav1.ListOptions) (watch.Interface, error) {
98 | var timeout time.Duration
99 | if opts.TimeoutSeconds != nil {
100 | timeout = time.Duration(*opts.TimeoutSeconds) * time.Second
101 | }
102 | opts.Watch = true
103 | return c.client.Get().
104 | Namespace(c.ns).
105 | Resource("snapshotgroups").
106 | VersionedParams(&opts, scheme.ParameterCodec).
107 | Timeout(timeout).
108 | Watch(ctx)
109 | }
110 |
111 | // Create takes the representation of a snapshotGroup and creates it. Returns the server's representation of the snapshotGroup, and an error, if there is any.
112 | func (c *snapshotGroups) Create(ctx context.Context, snapshotGroup *snapshotgroupv1.SnapshotGroup, opts metav1.CreateOptions) (result *snapshotgroupv1.SnapshotGroup, err error) {
113 | result = &snapshotgroupv1.SnapshotGroup{}
114 | err = c.client.Post().
115 | Namespace(c.ns).
116 | Resource("snapshotgroups").
117 | VersionedParams(&opts, scheme.ParameterCodec).
118 | Body(snapshotGroup).
119 | Do(ctx).
120 | Into(result)
121 | return
122 | }
123 |
124 | // Update takes the representation of a snapshotGroup and updates it. Returns the server's representation of the snapshotGroup, and an error, if there is any.
125 | func (c *snapshotGroups) Update(ctx context.Context, snapshotGroup *snapshotgroupv1.SnapshotGroup, opts metav1.UpdateOptions) (result *snapshotgroupv1.SnapshotGroup, err error) {
126 | result = &snapshotgroupv1.SnapshotGroup{}
127 | err = c.client.Put().
128 | Namespace(c.ns).
129 | Resource("snapshotgroups").
130 | Name(snapshotGroup.Name).
131 | VersionedParams(&opts, scheme.ParameterCodec).
132 | Body(snapshotGroup).
133 | Do(ctx).
134 | Into(result)
135 | return
136 | }
137 |
138 | // Delete takes name of the snapshotGroup and deletes it. Returns an error if one occurs.
139 | func (c *snapshotGroups) Delete(ctx context.Context, name string, opts metav1.DeleteOptions) error {
140 | return c.client.Delete().
141 | Namespace(c.ns).
142 | Resource("snapshotgroups").
143 | Name(name).
144 | Body(&opts).
145 | Do(ctx).
146 | Error()
147 | }
148 |
149 | // DeleteCollection deletes a collection of objects.
150 | func (c *snapshotGroups) DeleteCollection(ctx context.Context, opts metav1.DeleteOptions, listOpts metav1.ListOptions) error {
151 | var timeout time.Duration
152 | if listOpts.TimeoutSeconds != nil {
153 | timeout = time.Duration(*listOpts.TimeoutSeconds) * time.Second
154 | }
155 | return c.client.Delete().
156 | Namespace(c.ns).
157 | Resource("snapshotgroups").
158 | VersionedParams(&listOpts, scheme.ParameterCodec).
159 | Timeout(timeout).
160 | Body(&opts).
161 | Do(ctx).
162 | Error()
163 | }
164 |
165 | // Patch applies the patch and returns the patched snapshotGroup.
166 | func (c *snapshotGroups) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts metav1.PatchOptions, subresources ...string) (result *snapshotgroupv1.SnapshotGroup, err error) {
167 | result = &snapshotgroupv1.SnapshotGroup{}
168 | err = c.client.Patch(pt).
169 | Namespace(c.ns).
170 | Resource("snapshotgroups").
171 | Name(name).
172 | SubResource(subresources...).
173 | VersionedParams(&opts, scheme.ParameterCodec).
174 | Body(data).
175 | Do(ctx).
176 | Into(result)
177 | return
178 | }
179 |
--------------------------------------------------------------------------------
/pkg/types/snapshotgroup/v1/apis/clientset/versioned/typed/snapshotgroup/v1/snapshotgroup_client.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright The Kubernetes Authors.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | // Code generated by client-gen. DO NOT EDIT.
18 |
19 | package v1
20 |
21 | import (
22 | v1 "github.com/fairwindsops/gemini/pkg/types/snapshotgroup/v1"
23 | "github.com/fairwindsops/gemini/pkg/types/snapshotgroup/v1/apis/clientset/versioned/scheme"
24 | rest "k8s.io/client-go/rest"
25 | )
26 |
27 | type SnapshotgroupV1Interface interface {
28 | RESTClient() rest.Interface
29 | SnapshotGroupsGetter
30 | }
31 |
32 | // SnapshotgroupV1Client is used to interact with features provided by the snapshotgroup group.
33 | type SnapshotgroupV1Client struct {
34 | restClient rest.Interface
35 | }
36 |
37 | func (c *SnapshotgroupV1Client) SnapshotGroups(namespace string) SnapshotGroupInterface {
38 | return newSnapshotGroups(c, namespace)
39 | }
40 |
41 | // NewForConfig creates a new SnapshotgroupV1Client for the given config.
42 | func NewForConfig(c *rest.Config) (*SnapshotgroupV1Client, error) {
43 | config := *c
44 | if err := setConfigDefaults(&config); err != nil {
45 | return nil, err
46 | }
47 | client, err := rest.RESTClientFor(&config)
48 | if err != nil {
49 | return nil, err
50 | }
51 | return &SnapshotgroupV1Client{client}, nil
52 | }
53 |
54 | // NewForConfigOrDie creates a new SnapshotgroupV1Client for the given config and
55 | // panics if there is an error in the config.
56 | func NewForConfigOrDie(c *rest.Config) *SnapshotgroupV1Client {
57 | client, err := NewForConfig(c)
58 | if err != nil {
59 | panic(err)
60 | }
61 | return client
62 | }
63 |
64 | // New creates a new SnapshotgroupV1Client for the given RESTClient.
65 | func New(c rest.Interface) *SnapshotgroupV1Client {
66 | return &SnapshotgroupV1Client{c}
67 | }
68 |
69 | func setConfigDefaults(config *rest.Config) error {
70 | gv := v1.SchemeGroupVersion
71 | config.GroupVersion = &gv
72 | config.APIPath = "/apis"
73 | config.NegotiatedSerializer = scheme.Codecs.WithoutConversion()
74 |
75 | if config.UserAgent == "" {
76 | config.UserAgent = rest.DefaultKubernetesUserAgent()
77 | }
78 |
79 | return nil
80 | }
81 |
82 | // RESTClient returns a RESTClient that is used to communicate
83 | // with API server by this client implementation.
84 | func (c *SnapshotgroupV1Client) RESTClient() rest.Interface {
85 | if c == nil {
86 | return nil
87 | }
88 | return c.restClient
89 | }
90 |
--------------------------------------------------------------------------------
/pkg/types/snapshotgroup/v1/apis/informers/externalversions/factory.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright The Kubernetes Authors.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | // Code generated by informer-gen. DO NOT EDIT.
18 |
19 | package externalversions
20 |
21 | import (
22 | reflect "reflect"
23 | sync "sync"
24 | time "time"
25 |
26 | versioned "github.com/fairwindsops/gemini/pkg/types/snapshotgroup/v1/apis/clientset/versioned"
27 | internalinterfaces "github.com/fairwindsops/gemini/pkg/types/snapshotgroup/v1/apis/informers/externalversions/internalinterfaces"
28 | snapshotgroup "github.com/fairwindsops/gemini/pkg/types/snapshotgroup/v1/apis/informers/externalversions/snapshotgroup"
29 | v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
30 | runtime "k8s.io/apimachinery/pkg/runtime"
31 | schema "k8s.io/apimachinery/pkg/runtime/schema"
32 | cache "k8s.io/client-go/tools/cache"
33 | )
34 |
35 | // SharedInformerOption defines the functional option type for SharedInformerFactory.
36 | type SharedInformerOption func(*sharedInformerFactory) *sharedInformerFactory
37 |
38 | type sharedInformerFactory struct {
39 | client versioned.Interface
40 | namespace string
41 | tweakListOptions internalinterfaces.TweakListOptionsFunc
42 | lock sync.Mutex
43 | defaultResync time.Duration
44 | customResync map[reflect.Type]time.Duration
45 |
46 | informers map[reflect.Type]cache.SharedIndexInformer
47 | // startedInformers is used for tracking which informers have been started.
48 | // This allows Start() to be called multiple times safely.
49 | startedInformers map[reflect.Type]bool
50 | }
51 |
52 | // WithCustomResyncConfig sets a custom resync period for the specified informer types.
53 | func WithCustomResyncConfig(resyncConfig map[v1.Object]time.Duration) SharedInformerOption {
54 | return func(factory *sharedInformerFactory) *sharedInformerFactory {
55 | for k, v := range resyncConfig {
56 | factory.customResync[reflect.TypeOf(k)] = v
57 | }
58 | return factory
59 | }
60 | }
61 |
62 | // WithTweakListOptions sets a custom filter on all listers of the configured SharedInformerFactory.
63 | func WithTweakListOptions(tweakListOptions internalinterfaces.TweakListOptionsFunc) SharedInformerOption {
64 | return func(factory *sharedInformerFactory) *sharedInformerFactory {
65 | factory.tweakListOptions = tweakListOptions
66 | return factory
67 | }
68 | }
69 |
70 | // WithNamespace limits the SharedInformerFactory to the specified namespace.
71 | func WithNamespace(namespace string) SharedInformerOption {
72 | return func(factory *sharedInformerFactory) *sharedInformerFactory {
73 | factory.namespace = namespace
74 | return factory
75 | }
76 | }
77 |
78 | // NewSharedInformerFactory constructs a new instance of sharedInformerFactory for all namespaces.
79 | func NewSharedInformerFactory(client versioned.Interface, defaultResync time.Duration) SharedInformerFactory {
80 | return NewSharedInformerFactoryWithOptions(client, defaultResync)
81 | }
82 |
83 | // NewFilteredSharedInformerFactory constructs a new instance of sharedInformerFactory.
84 | // Listers obtained via this SharedInformerFactory will be subject to the same filters
85 | // as specified here.
86 | // Deprecated: Please use NewSharedInformerFactoryWithOptions instead
87 | func NewFilteredSharedInformerFactory(client versioned.Interface, defaultResync time.Duration, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) SharedInformerFactory {
88 | return NewSharedInformerFactoryWithOptions(client, defaultResync, WithNamespace(namespace), WithTweakListOptions(tweakListOptions))
89 | }
90 |
91 | // NewSharedInformerFactoryWithOptions constructs a new instance of a SharedInformerFactory with additional options.
92 | func NewSharedInformerFactoryWithOptions(client versioned.Interface, defaultResync time.Duration, options ...SharedInformerOption) SharedInformerFactory {
93 | factory := &sharedInformerFactory{
94 | client: client,
95 | namespace: v1.NamespaceAll,
96 | defaultResync: defaultResync,
97 | informers: make(map[reflect.Type]cache.SharedIndexInformer),
98 | startedInformers: make(map[reflect.Type]bool),
99 | customResync: make(map[reflect.Type]time.Duration),
100 | }
101 |
102 | // Apply all options
103 | for _, opt := range options {
104 | factory = opt(factory)
105 | }
106 |
107 | return factory
108 | }
109 |
110 | // Start initializes all requested informers.
111 | func (f *sharedInformerFactory) Start(stopCh <-chan struct{}) {
112 | f.lock.Lock()
113 | defer f.lock.Unlock()
114 |
115 | for informerType, informer := range f.informers {
116 | if !f.startedInformers[informerType] {
117 | go informer.Run(stopCh)
118 | f.startedInformers[informerType] = true
119 | }
120 | }
121 | }
122 |
123 | // WaitForCacheSync waits for all started informers' cache were synced.
124 | func (f *sharedInformerFactory) WaitForCacheSync(stopCh <-chan struct{}) map[reflect.Type]bool {
125 | informers := func() map[reflect.Type]cache.SharedIndexInformer {
126 | f.lock.Lock()
127 | defer f.lock.Unlock()
128 |
129 | informers := map[reflect.Type]cache.SharedIndexInformer{}
130 | for informerType, informer := range f.informers {
131 | if f.startedInformers[informerType] {
132 | informers[informerType] = informer
133 | }
134 | }
135 | return informers
136 | }()
137 |
138 | res := map[reflect.Type]bool{}
139 | for informType, informer := range informers {
140 | res[informType] = cache.WaitForCacheSync(stopCh, informer.HasSynced)
141 | }
142 | return res
143 | }
144 |
145 | // InternalInformerFor returns the SharedIndexInformer for obj using an internal
146 | // client.
147 | func (f *sharedInformerFactory) InformerFor(obj runtime.Object, newFunc internalinterfaces.NewInformerFunc) cache.SharedIndexInformer {
148 | f.lock.Lock()
149 | defer f.lock.Unlock()
150 |
151 | informerType := reflect.TypeOf(obj)
152 | informer, exists := f.informers[informerType]
153 | if exists {
154 | return informer
155 | }
156 |
157 | resyncPeriod, exists := f.customResync[informerType]
158 | if !exists {
159 | resyncPeriod = f.defaultResync
160 | }
161 |
162 | informer = newFunc(f.client, resyncPeriod)
163 | f.informers[informerType] = informer
164 |
165 | return informer
166 | }
167 |
168 | // SharedInformerFactory provides shared informers for resources in all known
169 | // API group versions.
170 | type SharedInformerFactory interface {
171 | internalinterfaces.SharedInformerFactory
172 | ForResource(resource schema.GroupVersionResource) (GenericInformer, error)
173 | WaitForCacheSync(stopCh <-chan struct{}) map[reflect.Type]bool
174 |
175 | Snapshotgroup() snapshotgroup.Interface
176 | }
177 |
178 | func (f *sharedInformerFactory) Snapshotgroup() snapshotgroup.Interface {
179 | return snapshotgroup.New(f, f.namespace, f.tweakListOptions)
180 | }
181 |
--------------------------------------------------------------------------------
/pkg/types/snapshotgroup/v1/apis/informers/externalversions/generic.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright The Kubernetes Authors.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | // Code generated by informer-gen. DO NOT EDIT.
18 |
19 | package externalversions
20 |
21 | import (
22 | "fmt"
23 |
24 | v1 "github.com/fairwindsops/gemini/pkg/types/snapshotgroup/v1"
25 | schema "k8s.io/apimachinery/pkg/runtime/schema"
26 | cache "k8s.io/client-go/tools/cache"
27 | )
28 |
29 | // GenericInformer is type of SharedIndexInformer which will locate and delegate to other
30 | // sharedInformers based on type
31 | type GenericInformer interface {
32 | Informer() cache.SharedIndexInformer
33 | Lister() cache.GenericLister
34 | }
35 |
36 | type genericInformer struct {
37 | informer cache.SharedIndexInformer
38 | resource schema.GroupResource
39 | }
40 |
41 | // Informer returns the SharedIndexInformer.
42 | func (f *genericInformer) Informer() cache.SharedIndexInformer {
43 | return f.informer
44 | }
45 |
46 | // Lister returns the GenericLister.
47 | func (f *genericInformer) Lister() cache.GenericLister {
48 | return cache.NewGenericLister(f.Informer().GetIndexer(), f.resource)
49 | }
50 |
51 | // ForResource gives generic access to a shared informer of the matching type
52 | // TODO extend this to unknown resources with a client pool
53 | func (f *sharedInformerFactory) ForResource(resource schema.GroupVersionResource) (GenericInformer, error) {
54 | switch resource {
55 | // Group=snapshotgroup, Version=v1
56 | case v1.SchemeGroupVersion.WithResource("snapshotgroups"):
57 | return &genericInformer{resource: resource.GroupResource(), informer: f.Snapshotgroup().V1().SnapshotGroups().Informer()}, nil
58 |
59 | }
60 |
61 | return nil, fmt.Errorf("no informer found for %v", resource)
62 | }
63 |
--------------------------------------------------------------------------------
/pkg/types/snapshotgroup/v1/apis/informers/externalversions/internalinterfaces/factory_interfaces.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright The Kubernetes Authors.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | // Code generated by informer-gen. DO NOT EDIT.
18 |
19 | package internalinterfaces
20 |
21 | import (
22 | time "time"
23 |
24 | versioned "github.com/fairwindsops/gemini/pkg/types/snapshotgroup/v1/apis/clientset/versioned"
25 | v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
26 | runtime "k8s.io/apimachinery/pkg/runtime"
27 | cache "k8s.io/client-go/tools/cache"
28 | )
29 |
30 | // NewInformerFunc takes versioned.Interface and time.Duration to return a SharedIndexInformer.
31 | type NewInformerFunc func(versioned.Interface, time.Duration) cache.SharedIndexInformer
32 |
33 | // SharedInformerFactory a small interface to allow for adding an informer without an import cycle
34 | type SharedInformerFactory interface {
35 | Start(stopCh <-chan struct{})
36 | InformerFor(obj runtime.Object, newFunc NewInformerFunc) cache.SharedIndexInformer
37 | }
38 |
39 | // TweakListOptionsFunc is a function that transforms a v1.ListOptions.
40 | type TweakListOptionsFunc func(*v1.ListOptions)
41 |
--------------------------------------------------------------------------------
/pkg/types/snapshotgroup/v1/apis/informers/externalversions/snapshotgroup/interface.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright The Kubernetes Authors.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | // Code generated by informer-gen. DO NOT EDIT.
18 |
19 | package snapshotgroup
20 |
21 | import (
22 | internalinterfaces "github.com/fairwindsops/gemini/pkg/types/snapshotgroup/v1/apis/informers/externalversions/internalinterfaces"
23 | v1 "github.com/fairwindsops/gemini/pkg/types/snapshotgroup/v1/apis/informers/externalversions/snapshotgroup/v1"
24 | )
25 |
26 | // Interface provides access to each of this group's versions.
27 | type Interface interface {
28 | // V1 provides access to shared informers for resources in V1.
29 | V1() v1.Interface
30 | }
31 |
32 | type group struct {
33 | factory internalinterfaces.SharedInformerFactory
34 | namespace string
35 | tweakListOptions internalinterfaces.TweakListOptionsFunc
36 | }
37 |
38 | // New returns a new Interface.
39 | func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface {
40 | return &group{factory: f, namespace: namespace, tweakListOptions: tweakListOptions}
41 | }
42 |
43 | // V1 returns a new v1.Interface.
44 | func (g *group) V1() v1.Interface {
45 | return v1.New(g.factory, g.namespace, g.tweakListOptions)
46 | }
47 |
--------------------------------------------------------------------------------
/pkg/types/snapshotgroup/v1/apis/informers/externalversions/snapshotgroup/v1/interface.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright The Kubernetes Authors.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | // Code generated by informer-gen. DO NOT EDIT.
18 |
19 | package v1
20 |
21 | import (
22 | internalinterfaces "github.com/fairwindsops/gemini/pkg/types/snapshotgroup/v1/apis/informers/externalversions/internalinterfaces"
23 | )
24 |
25 | // Interface provides access to all the informers in this group version.
26 | type Interface interface {
27 | // SnapshotGroups returns a SnapshotGroupInformer.
28 | SnapshotGroups() SnapshotGroupInformer
29 | }
30 |
31 | type version struct {
32 | factory internalinterfaces.SharedInformerFactory
33 | namespace string
34 | tweakListOptions internalinterfaces.TweakListOptionsFunc
35 | }
36 |
37 | // New returns a new Interface.
38 | func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface {
39 | return &version{factory: f, namespace: namespace, tweakListOptions: tweakListOptions}
40 | }
41 |
42 | // SnapshotGroups returns a SnapshotGroupInformer.
43 | func (v *version) SnapshotGroups() SnapshotGroupInformer {
44 | return &snapshotGroupInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions}
45 | }
46 |
--------------------------------------------------------------------------------
/pkg/types/snapshotgroup/v1/apis/informers/externalversions/snapshotgroup/v1/snapshotgroup.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright The Kubernetes Authors.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | // Code generated by informer-gen. DO NOT EDIT.
18 |
19 | package v1
20 |
21 | import (
22 | "context"
23 | time "time"
24 |
25 | snapshotgroupv1 "github.com/fairwindsops/gemini/pkg/types/snapshotgroup/v1"
26 | versioned "github.com/fairwindsops/gemini/pkg/types/snapshotgroup/v1/apis/clientset/versioned"
27 | internalinterfaces "github.com/fairwindsops/gemini/pkg/types/snapshotgroup/v1/apis/informers/externalversions/internalinterfaces"
28 | v1 "github.com/fairwindsops/gemini/pkg/types/snapshotgroup/v1/apis/listers/snapshotgroup/v1"
29 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
30 | runtime "k8s.io/apimachinery/pkg/runtime"
31 | watch "k8s.io/apimachinery/pkg/watch"
32 | cache "k8s.io/client-go/tools/cache"
33 | )
34 |
35 | // SnapshotGroupInformer provides access to a shared informer and lister for
36 | // SnapshotGroups.
37 | type SnapshotGroupInformer interface {
38 | Informer() cache.SharedIndexInformer
39 | Lister() v1.SnapshotGroupLister
40 | }
41 |
42 | type snapshotGroupInformer struct {
43 | factory internalinterfaces.SharedInformerFactory
44 | tweakListOptions internalinterfaces.TweakListOptionsFunc
45 | namespace string
46 | }
47 |
48 | // NewSnapshotGroupInformer constructs a new informer for SnapshotGroup type.
49 | // Always prefer using an informer factory to get a shared informer instead of getting an independent
50 | // one. This reduces memory footprint and number of connections to the server.
51 | func NewSnapshotGroupInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer {
52 | return NewFilteredSnapshotGroupInformer(client, namespace, resyncPeriod, indexers, nil)
53 | }
54 |
55 | // NewFilteredSnapshotGroupInformer constructs a new informer for SnapshotGroup type.
56 | // Always prefer using an informer factory to get a shared informer instead of getting an independent
57 | // one. This reduces memory footprint and number of connections to the server.
58 | func NewFilteredSnapshotGroupInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer {
59 | return cache.NewSharedIndexInformer(
60 | &cache.ListWatch{
61 | ListFunc: func(options metav1.ListOptions) (runtime.Object, error) {
62 | if tweakListOptions != nil {
63 | tweakListOptions(&options)
64 | }
65 | return client.SnapshotgroupV1().SnapshotGroups(namespace).List(context.TODO(), options)
66 | },
67 | WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) {
68 | if tweakListOptions != nil {
69 | tweakListOptions(&options)
70 | }
71 | return client.SnapshotgroupV1().SnapshotGroups(namespace).Watch(context.TODO(), options)
72 | },
73 | },
74 | &snapshotgroupv1.SnapshotGroup{},
75 | resyncPeriod,
76 | indexers,
77 | )
78 | }
79 |
80 | func (f *snapshotGroupInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer {
81 | return NewFilteredSnapshotGroupInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions)
82 | }
83 |
84 | func (f *snapshotGroupInformer) Informer() cache.SharedIndexInformer {
85 | return f.factory.InformerFor(&snapshotgroupv1.SnapshotGroup{}, f.defaultInformer)
86 | }
87 |
88 | func (f *snapshotGroupInformer) Lister() v1.SnapshotGroupLister {
89 | return v1.NewSnapshotGroupLister(f.Informer().GetIndexer())
90 | }
91 |
--------------------------------------------------------------------------------
/pkg/types/snapshotgroup/v1/apis/listers/snapshotgroup/v1/expansion_generated.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright The Kubernetes Authors.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | // Code generated by lister-gen. DO NOT EDIT.
18 |
19 | package v1
20 |
21 | // SnapshotGroupListerExpansion allows custom methods to be added to
22 | // SnapshotGroupLister.
23 | type SnapshotGroupListerExpansion interface{}
24 |
25 | // SnapshotGroupNamespaceListerExpansion allows custom methods to be added to
26 | // SnapshotGroupNamespaceLister.
27 | type SnapshotGroupNamespaceListerExpansion interface{}
28 |
--------------------------------------------------------------------------------
/pkg/types/snapshotgroup/v1/apis/listers/snapshotgroup/v1/snapshotgroup.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright The Kubernetes Authors.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | // Code generated by lister-gen. DO NOT EDIT.
18 |
19 | package v1
20 |
21 | import (
22 | v1 "github.com/fairwindsops/gemini/pkg/types/snapshotgroup/v1"
23 | "k8s.io/apimachinery/pkg/api/errors"
24 | "k8s.io/apimachinery/pkg/labels"
25 | "k8s.io/client-go/tools/cache"
26 | )
27 |
28 | // SnapshotGroupLister helps list SnapshotGroups.
29 | // All objects returned here must be treated as read-only.
30 | type SnapshotGroupLister interface {
31 | // List lists all SnapshotGroups in the indexer.
32 | // Objects returned here must be treated as read-only.
33 | List(selector labels.Selector) (ret []*v1.SnapshotGroup, err error)
34 | // SnapshotGroups returns an object that can list and get SnapshotGroups.
35 | SnapshotGroups(namespace string) SnapshotGroupNamespaceLister
36 | SnapshotGroupListerExpansion
37 | }
38 |
39 | // snapshotGroupLister implements the SnapshotGroupLister interface.
40 | type snapshotGroupLister struct {
41 | indexer cache.Indexer
42 | }
43 |
44 | // NewSnapshotGroupLister returns a new SnapshotGroupLister.
45 | func NewSnapshotGroupLister(indexer cache.Indexer) SnapshotGroupLister {
46 | return &snapshotGroupLister{indexer: indexer}
47 | }
48 |
49 | // List lists all SnapshotGroups in the indexer.
50 | func (s *snapshotGroupLister) List(selector labels.Selector) (ret []*v1.SnapshotGroup, err error) {
51 | err = cache.ListAll(s.indexer, selector, func(m interface{}) {
52 | ret = append(ret, m.(*v1.SnapshotGroup))
53 | })
54 | return ret, err
55 | }
56 |
57 | // SnapshotGroups returns an object that can list and get SnapshotGroups.
58 | func (s *snapshotGroupLister) SnapshotGroups(namespace string) SnapshotGroupNamespaceLister {
59 | return snapshotGroupNamespaceLister{indexer: s.indexer, namespace: namespace}
60 | }
61 |
62 | // SnapshotGroupNamespaceLister helps list and get SnapshotGroups.
63 | // All objects returned here must be treated as read-only.
64 | type SnapshotGroupNamespaceLister interface {
65 | // List lists all SnapshotGroups in the indexer for a given namespace.
66 | // Objects returned here must be treated as read-only.
67 | List(selector labels.Selector) (ret []*v1.SnapshotGroup, err error)
68 | // Get retrieves the SnapshotGroup from the indexer for a given namespace and name.
69 | // Objects returned here must be treated as read-only.
70 | Get(name string) (*v1.SnapshotGroup, error)
71 | SnapshotGroupNamespaceListerExpansion
72 | }
73 |
74 | // snapshotGroupNamespaceLister implements the SnapshotGroupNamespaceLister
75 | // interface.
76 | type snapshotGroupNamespaceLister struct {
77 | indexer cache.Indexer
78 | namespace string
79 | }
80 |
81 | // List lists all SnapshotGroups in the indexer for a given namespace.
82 | func (s snapshotGroupNamespaceLister) List(selector labels.Selector) (ret []*v1.SnapshotGroup, err error) {
83 | err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) {
84 | ret = append(ret, m.(*v1.SnapshotGroup))
85 | })
86 | return ret, err
87 | }
88 |
89 | // Get retrieves the SnapshotGroup from the indexer for a given namespace and name.
90 | func (s snapshotGroupNamespaceLister) Get(name string) (*v1.SnapshotGroup, error) {
91 | obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name)
92 | if err != nil {
93 | return nil, err
94 | }
95 | if !exists {
96 | return nil, errors.NewNotFound(v1.Resource("snapshotgroup"), name)
97 | }
98 | return obj.(*v1.SnapshotGroup), nil
99 | }
100 |
--------------------------------------------------------------------------------
/pkg/types/snapshotgroup/v1/crd-with-beta1.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: apiextensions.k8s.io/v1
2 | kind: CustomResourceDefinition
3 | metadata:
4 | name: snapshotgroups.gemini.fairwinds.com
5 | spec:
6 | group: gemini.fairwinds.com
7 | names:
8 | plural: snapshotgroups
9 | singular: snapshotgroup
10 | kind: SnapshotGroup
11 | listKind: SnapshotGroupList
12 | scope: Namespaced
13 | conversion:
14 | strategy: None
15 | versions:
16 | - name: v1beta1
17 | served: true
18 | storage: false
19 | schema:
20 | openAPIV3Schema:
21 | type: object
22 | properties:
23 | spec:
24 | type: object
25 | properties:
26 | persistentVolumeClaim:
27 | type: object
28 | properties:
29 | claimName:
30 | description: PersistentVolumeClaim name to backup
31 | type: string
32 | spec:
33 | description: PersistentVolumeClaim spec to create and backup
34 | type: object
35 | schedule:
36 | type: array
37 | items:
38 | type: object
39 | properties:
40 | every:
41 | description: Interval for creating new backups
42 | type: string
43 | keep:
44 | description: Number of historical backups to keep
45 | type: integer
46 | template:
47 | type: object
48 | properties:
49 | spec:
50 | description: VolumeSnapshot spec
51 | type: object
52 | properties:
53 | volumeSnapshotClassName:
54 | description: 'VolumeSnapshotClassName is the name of the VolumeSnapshotClass requested by the VolumeSnapshot. VolumeSnapshotClassName may be left nil to indicate that the default SnapshotClass should be used. A given cluster may have multiple default Volume SnapshotClasses: one default per CSI Driver. If a VolumeSnapshot does not specify a SnapshotClass, VolumeSnapshotSource will be checked to figure out what the associated CSI Driver is, and the default VolumeSnapshotClass associated with that CSI Driver will be used. If more than one VolumeSnapshotClass exist for a given CSI Driver and more than one have been marked as default, CreateSnapshot will fail and generate an event. Empty string is not allowed for this field.'
55 | type: string
56 | - name: v1
57 | served: true
58 | storage: true
59 | schema:
60 | openAPIV3Schema:
61 | type: object
62 | properties:
63 | spec:
64 | type: object
65 | properties:
66 | persistentVolumeClaim:
67 | type: object
68 | properties:
69 | claimName:
70 | description: PersistentVolumeClaim name to backup
71 | type: string
72 | spec:
73 | description: PersistentVolumeClaim spec to create and backup
74 | type: object
75 | properties:
76 | storageClassName:
77 | type: string
78 | accessModes:
79 | type: array
80 | items:
81 | type: string
82 | volumeName:
83 | type: string
84 | resources:
85 | type: object
86 | properties:
87 | requests:
88 | type: object
89 | additionalProperties: true
90 | limits:
91 | type: object
92 | properties:
93 | storageClassName:
94 | type: string
95 | additionalProperties: true
96 | selector:
97 | type: object
98 | properties:
99 | matchLabels:
100 | type: object
101 | additionalProperties: true
102 | matchExpressions:
103 | type: array
104 | items:
105 | type: object
106 | additionalProperties: true
107 | schedule:
108 | type: array
109 | items:
110 | type: object
111 | properties:
112 | every:
113 | description: Interval for creating new backups
114 | type: string
115 | keep:
116 | description: Number of historical backups to keep
117 | type: integer
118 | template:
119 | type: object
120 | properties:
121 | spec:
122 | description: VolumeSnapshot spec
123 | type: object
124 | properties:
125 | volumeSnapshotClassName:
126 | description: 'VolumeSnapshotClassName is the name of the VolumeSnapshotClass requested by the VolumeSnapshot. VolumeSnapshotClassName may be left nil to indicate that the default SnapshotClass should be used. A given cluster may have multiple default Volume SnapshotClasses: one default per CSI Driver. If a VolumeSnapshot does not specify a SnapshotClass, VolumeSnapshotSource will be checked to figure out what the associated CSI Driver is, and the default VolumeSnapshotClass associated with that CSI Driver will be used. If more than one VolumeSnapshotClass exist for a given CSI Driver and more than one have been marked as default, CreateSnapshot will fail and generate an event. Empty string is not allowed for this field.'
127 | type: string
128 |
--------------------------------------------------------------------------------
/pkg/types/snapshotgroup/v1/crd.go:
--------------------------------------------------------------------------------
1 | package v1
2 |
3 | import (
4 | "os"
5 | "context"
6 | "fmt"
7 | "time"
8 | _ "embed"
9 |
10 | apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
11 | apiextensionsclientset "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"
12 | apierrors "k8s.io/apimachinery/pkg/api/errors"
13 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
14 |
15 | "gopkg.in/yaml.v2"
16 | "k8s.io/apimachinery/pkg/util/errors"
17 | "k8s.io/apimachinery/pkg/util/wait"
18 | )
19 |
20 | //go:embed crd.yaml
21 | var crdYAML string
22 |
23 | //go:embed crd-with-beta1.yaml
24 | var crdWithBeta1YAML string
25 |
26 | // CreateCustomResourceDefinition creates the CRD and add it into Kubernetes. If there is error,
27 | // it will do some clean up.
28 | func CreateCustomResourceDefinition(namespace string, clientSet apiextensionsclientset.Interface) (*apiextensionsv1.CustomResourceDefinition, error) {
29 | crd := &apiextensionsv1.CustomResourceDefinition{}
30 | yamlToParse := crdYAML
31 | if os.Getenv("INCLUDE_GEMINI_BETA_CRD") != "" {
32 | yamlToParse = crdWithBeta1YAML
33 | }
34 | fmt.Println("CRD yaml", yamlToParse)
35 | err := yaml.Unmarshal([]byte(yamlToParse), crd)
36 | if err != nil {
37 | return nil, err
38 | }
39 | fmt.Printf("Parsed CRD: %#v", crd)
40 |
41 | _, err = clientSet.ApiextensionsV1().CustomResourceDefinitions().Create(context.TODO(), crd, metav1.CreateOptions{})
42 | if err == nil {
43 | fmt.Println("CRD SnapshotGroup is created")
44 | } else if apierrors.IsAlreadyExists(err) {
45 | fmt.Println("CRD SnapshotGroup already exists, trying update")
46 | _, err = clientSet.ApiextensionsV1().CustomResourceDefinitions().Update(context.TODO(), crd, metav1.UpdateOptions{})
47 | }
48 | if err != nil {
49 | fmt.Printf("Failed to create CRD SnapshotGroup: %+v\n", err)
50 | return nil, err
51 | }
52 |
53 | // Wait for CRD creation.
54 | err = wait.Poll(5*time.Second, 60*time.Second, func() (bool, error) {
55 | crd, err = clientSet.ApiextensionsV1().CustomResourceDefinitions().Get(context.TODO(), CRDName, metav1.GetOptions{})
56 | if err != nil {
57 | fmt.Printf("Fail to wait for CRD SnapshotGroup creation: %+v\n", err)
58 |
59 | return false, err
60 | }
61 | for _, cond := range crd.Status.Conditions {
62 | switch cond.Type {
63 | case apiextensionsv1.Established:
64 | if cond.Status == apiextensionsv1.ConditionTrue {
65 | return true, err
66 | }
67 | case apiextensionsv1.NamesAccepted:
68 | if cond.Status == apiextensionsv1.ConditionFalse {
69 | fmt.Printf("Name conflict while wait for CRD SnapshotGroup creation: %s, %+v\n", cond.Reason, err)
70 | }
71 | }
72 | }
73 |
74 | return false, err
75 | })
76 |
77 | // If there is an error, delete the object to keep it clean.
78 | if err != nil {
79 | fmt.Println("Try to cleanup")
80 | deleteErr := clientSet.ApiextensionsV1().CustomResourceDefinitions().Delete(context.TODO(), CRDName, metav1.DeleteOptions{})
81 | if deleteErr != nil {
82 | fmt.Printf("Fail to delete CRD SnapshotGroup: %+v\n", deleteErr)
83 |
84 | return nil, errors.NewAggregate([]error{err, deleteErr})
85 | }
86 |
87 | return nil, err
88 | }
89 |
90 | return crd, nil
91 | }
92 |
--------------------------------------------------------------------------------
/pkg/types/snapshotgroup/v1/crd.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: apiextensions.k8s.io/v1
2 | kind: CustomResourceDefinition
3 | metadata:
4 | name: snapshotgroups.gemini.fairwinds.com
5 | spec:
6 | group: gemini.fairwinds.com
7 | names:
8 | plural: snapshotgroups
9 | singular: snapshotgroup
10 | kind: SnapshotGroup
11 | listKind: SnapshotGroupList
12 | scope: Namespaced
13 | versions:
14 | - name: v1
15 | served: true
16 | storage: true
17 | schema:
18 | openAPIV3Schema:
19 | type: object
20 | properties:
21 | spec:
22 | type: object
23 | properties:
24 | persistentVolumeClaim:
25 | type: object
26 | properties:
27 | claimName:
28 | description: PersistentVolumeClaim name to backup
29 | type: string
30 | spec:
31 | description: PersistentVolumeClaim spec to create and backup
32 | type: object
33 | properties:
34 | storageClassName:
35 | type: string
36 | accessModes:
37 | type: array
38 | items:
39 | type: string
40 | volumeName:
41 | type: string
42 | resources:
43 | type: object
44 | properties:
45 | requests:
46 | type: object
47 | additionalProperties: true
48 | limits:
49 | type: object
50 | properties:
51 | storageClassName:
52 | type: string
53 | additionalProperties: true
54 | selector:
55 | type: object
56 | properties:
57 | matchLabels:
58 | type: object
59 | additionalProperties: true
60 | matchExpressions:
61 | type: array
62 | items:
63 | type: object
64 | additionalProperties: true
65 | schedule:
66 | type: array
67 | items:
68 | type: object
69 | properties:
70 | every:
71 | description: Interval for creating new backups
72 | type: string
73 | keep:
74 | description: Number of historical backups to keep
75 | type: integer
76 | template:
77 | type: object
78 | properties:
79 | spec:
80 | description: VolumeSnapshot spec
81 | type: object
82 | properties:
83 | volumeSnapshotClassName:
84 | description: 'VolumeSnapshotClassName is the name of the VolumeSnapshotClass requested by the VolumeSnapshot. VolumeSnapshotClassName may be left nil to indicate that the default SnapshotClass should be used. A given cluster may have multiple default Volume SnapshotClasses: one default per CSI Driver. If a VolumeSnapshot does not specify a SnapshotClass, VolumeSnapshotSource will be checked to figure out what the associated CSI Driver is, and the default VolumeSnapshotClass associated with that CSI Driver will be used. If more than one VolumeSnapshotClass exist for a given CSI Driver and more than one have been marked as default, CreateSnapshot will fail and generate an event. Empty string is not allowed for this field.'
85 | type: string
86 | conversion:
87 | strategy: None
88 |
--------------------------------------------------------------------------------
/pkg/types/snapshotgroup/v1/deepcopy.go:
--------------------------------------------------------------------------------
1 | package v1
2 |
3 | import (
4 | runtime "k8s.io/apimachinery/pkg/runtime"
5 | )
6 |
7 | // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
8 | func (in *SnapshotGroup) DeepCopyInto(out *SnapshotGroup) {
9 | *out = *in
10 | out.TypeMeta = in.TypeMeta
11 | in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
12 | out.Spec = in.Spec
13 | out.Status = in.Status
14 | }
15 |
16 | // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SnapshotGroup.
17 | func (in *SnapshotGroup) DeepCopy() *SnapshotGroup {
18 | if in == nil {
19 | return nil
20 | }
21 | out := new(SnapshotGroup)
22 | in.DeepCopyInto(out)
23 | return out
24 | }
25 |
26 | // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
27 | func (in *SnapshotGroup) DeepCopyObject() runtime.Object {
28 | if c := in.DeepCopy(); c != nil {
29 | return c
30 | } else {
31 | return nil
32 | }
33 | }
34 |
35 | // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
36 | func (in *SnapshotGroupList) DeepCopyInto(out *SnapshotGroupList) {
37 | *out = *in
38 | out.TypeMeta = in.TypeMeta
39 | out.ListMeta = in.ListMeta
40 | if in.Items != nil {
41 | in, out := &in.Items, &out.Items
42 | *out = make([]SnapshotGroup, len(*in))
43 | for i := range *in {
44 | (*in)[i].DeepCopyInto(&(*out)[i])
45 | }
46 | }
47 | }
48 |
49 | // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SnapshotGroupList.
50 | func (in *SnapshotGroupList) DeepCopy() *SnapshotGroupList {
51 | if in == nil {
52 | return nil
53 | }
54 | out := new(SnapshotGroupList)
55 | in.DeepCopyInto(out)
56 | return out
57 | }
58 |
59 | // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
60 | func (in *SnapshotGroupList) DeepCopyObject() runtime.Object {
61 | if c := in.DeepCopy(); c != nil {
62 | return c
63 | } else {
64 | return nil
65 | }
66 | }
67 |
68 | // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
69 | func (in *SnapshotGroupSpec) DeepCopyInto(out *SnapshotGroupSpec) {
70 | *out = *in
71 | }
72 |
73 | // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SnapshotGroupSpec.
74 | func (in *SnapshotGroupSpec) DeepCopy() *SnapshotGroupSpec {
75 | if in == nil {
76 | return nil
77 | }
78 | out := new(SnapshotGroupSpec)
79 | in.DeepCopyInto(out)
80 | return out
81 | }
82 |
83 | // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
84 | func (in *SnapshotGroupStatus) DeepCopyInto(out *SnapshotGroupStatus) {
85 | *out = *in
86 | }
87 |
88 | // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SnapshotGroupStatus.
89 | func (in *SnapshotGroupStatus) DeepCopy() *SnapshotGroupStatus {
90 | if in == nil {
91 | return nil
92 | }
93 | out := new(SnapshotGroupStatus)
94 | in.DeepCopyInto(out)
95 | return out
96 | }
97 |
--------------------------------------------------------------------------------
/pkg/types/snapshotgroup/v1/register.go:
--------------------------------------------------------------------------------
1 | package v1
2 |
3 | import (
4 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
5 |
6 | "k8s.io/apimachinery/pkg/runtime"
7 | "k8s.io/apimachinery/pkg/runtime/schema"
8 | )
9 |
10 | const (
11 | GroupName string = "gemini.fairwinds.com"
12 | Kind string = "SnapshotGroup"
13 | GroupVersion string = "v1"
14 | Plural string = "snapshotgroups"
15 | Singular string = "snapshotgroup"
16 | CRDName string = Plural + "." + GroupName
17 | )
18 |
19 | var (
20 | // SchemeGroupVersion is the group version used to register these objects.
21 | SchemeGroupVersion = schema.GroupVersion{
22 | Group: GroupName,
23 | Version: GroupVersion,
24 | }
25 | SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes)
26 | AddToScheme = SchemeBuilder.AddToScheme
27 | )
28 |
29 | // Resource takes an unqualified resource and returns a Group qualified GroupResource
30 | func Resource(resource string) schema.GroupResource {
31 | return SchemeGroupVersion.WithResource(resource).GroupResource()
32 | }
33 |
34 | // addKnownTypes adds the set of types defined in this package to the supplied scheme.
35 | func addKnownTypes(scheme *runtime.Scheme) error {
36 | scheme.AddKnownTypes(SchemeGroupVersion,
37 | &SnapshotGroup{},
38 | &SnapshotGroupList{},
39 | )
40 | metav1.AddToGroupVersion(scheme, SchemeGroupVersion)
41 | return nil
42 | }
43 |
--------------------------------------------------------------------------------
/pkg/types/snapshotgroup/v1/snapshotgroup.go:
--------------------------------------------------------------------------------
1 | package v1
2 |
3 | import (
4 | snapshotsv1 "github.com/kubernetes-csi/external-snapshotter/client/v4/apis/volumesnapshot/v1"
5 | corev1 "k8s.io/api/core/v1"
6 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
7 | )
8 |
9 | // +genclient
10 | // +genclient:noStatus
11 | // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
12 | // +resource:path=snapshotgroup
13 |
14 | // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
15 | type SnapshotGroup struct {
16 | metav1.TypeMeta `json:",inline"`
17 | metav1.ObjectMeta `json:"metadata"`
18 | Spec SnapshotGroupSpec `json:"spec"`
19 | Status SnapshotGroupStatus `json:"status"`
20 | }
21 |
22 | type SnapshotGroupSpec struct {
23 | Claim SnapshotClaim `json:"persistentVolumeClaim"`
24 | Template SnapshotTemplate `json:"template"`
25 | Schedule []SnapshotSchedule `json:"schedule"`
26 | }
27 |
28 | type SnapshotClaim struct {
29 | Spec corev1.PersistentVolumeClaimSpec `json:"spec"`
30 | Name string `json:"claimName"`
31 | }
32 |
33 | type SnapshotTemplate struct {
34 | Spec snapshotsv1.VolumeSnapshotSpec `json:"spec"`
35 | }
36 |
37 | type SnapshotSchedule struct {
38 | Every string `json:"every"`
39 | Keep int `json:"keep"`
40 | }
41 |
42 | type SnapshotGroupStatus struct{}
43 |
44 | // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
45 | // +resource:path=snapshotgroup
46 |
47 | // SnapshotGroupList is the list of SnapshotGroups.
48 | type SnapshotGroupList struct {
49 | metav1.TypeMeta `json:",inline"`
50 | metav1.ListMeta `json:"metadata"`
51 | Items []SnapshotGroup `json:"items"`
52 | }
53 |
--------------------------------------------------------------------------------
/scripts/goreleaser.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 | # Wrap goreleaser by using envsubst on .goreleaser.yml,
3 | # and creating a temporary git tag.
4 |
5 | function cleanup {
6 | if [ "${CIRCLE_TAG}" == "" ] ; then
7 | echo "${this_script} deleting git tag ${temporary_git_tag} for goreleaser"
8 | unset GORELEASER_CURRENT_TAG
9 | git tag -d ${temporary_git_tag}
10 | fi
11 | }
12 |
13 | set -eE # errexit and errtrace
14 | trap 'cleanup' ERR
15 | this_script="$(basename $0)"
16 | hash envsubst
17 | hash goreleaser
18 | if [ "${TMPDIR}" == "" ] ; then
19 | export TMPDIR="/tmp"
20 | echo "${this_script} temporarily set the TMPDIR environment variable to ${TMPDIR}, used for a temporary GOBIN environment variable"
21 | fi
22 |
23 | export skip_feature_docker_tags=false
24 | export skip_release=true
25 | if [ "${CIRCLE_TAG}" == "" ] ; then
26 | # Create a temporary tag for goreleaser, incrementing the last tag.
27 | last_git_tag="$(git describe --tags --abbrev=0 2>/dev/null)"
28 | if [ "${last_git_tag}" == "" ] ; then
29 | echo "${this_script} is unable to determine the last git tag so a temporary tag can be created, using: git describe --tags --abbrev=0"
30 | exit 1
31 | fi
32 | if [ "$(git config user.email)" == "" ] ; then
33 | # git will use this env var as its user.email.
34 | # git tag -m is used in case tags are manually pushed by accident,
35 | # however git tag -m requires an email.
36 | export EMAIL='goreleaser_ci@fairwinds.com'
37 | echo "${this_script} using ${EMAIL} temporarily as the git user.email"
38 | fi
39 | temporary_git_tag=$(echo "${last_git_tag}" | awk -F. '{$NF = $NF + 1;} 1' | sed 's/ /./g')-rc
40 | echo "${this_script} creating temporary git tag ${temporary_git_tag} for goreleaser, the last real tag is ${last_git_tag}"
41 | # The -f is included to overwrite existing tags, perhaps from previous CI jobs.
42 | git tag -f -m "temporary local tag for goreleaser" ${temporary_git_tag}
43 | export GORELEASER_CURRENT_TAG=${temporary_git_tag}
44 | # Use an adjusted git feature branch name as a docker tag.
45 | export feature_docker_tag=$(echo "${CIRCLE_BRANCH:0:26}" | sed 's/[^a-zA-Z0-9]/-/g' | sed 's/-\+$//')
46 | echo "${this_script} also using docker tag ${feature_docker_tag} since ${CIRCLE_BRANCH} is a feature branch"
47 | else
48 | export GORELEASER_CURRENT_TAG=${CIRCLE_TAG}
49 | echo "${this_script} setting skip_release to false, and skip_feature_docker_tags to true, because CIRCLE_TAG is set"
50 | export skip_feature_docker_tags=true
51 | export skip_release=false
52 | fi
53 |
54 | echo "${this_script} using git tag ${GORELEASER_CURRENT_TAG}"
55 | # Only substitute specific variables, as goreleaser uses shell variable syntax
56 | # for its `signs` section `signature` and `artifact` variables.
57 | cat .goreleaser.yml.envsubst |envsubst '${skip_release} ${skip_feature_docker_tags} ${feature_docker_tag}' >.goreleaser.yml
58 | goreleaser $@
59 | if [ $? -eq 0 ] ; then
60 | echo "${this_script} removing the temporary .goreleaser.yml since goreleaser was successful"
61 | rm .goreleaser.yml # Keep git clean for additional goreleaser runs
62 | fi
63 | cleanup
64 |
--------------------------------------------------------------------------------