Skip to content

Commit

Permalink
Create repository crd for each Restic repository (#394)
Browse files Browse the repository at this point in the history
  • Loading branch information
Md. Emruz Hossain authored and tamalsaha committed Mar 31, 2018
1 parent f2e78da commit 7568e62
Show file tree
Hide file tree
Showing 40 changed files with 1,388 additions and 590 deletions.
2 changes: 1 addition & 1 deletion apis/stash/v1alpha1/crd.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ func (c Repository) CustomResourceDefinition() *apiextensions.CustomResourceDefi
Singular: ResourceNameRepository,
Plural: ResourceTypeRepository,
Kind: ResourceKindRepository,
ShortNames: []string{"rec"},
ShortNames: []string{"repo"},
},
},
}
Expand Down
54 changes: 36 additions & 18 deletions apis/stash/v1alpha1/crds.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,21 +15,39 @@ spec:
singular: restic
scope: Namespaced
version: v1alpha1
---
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
name: recoveries.stash.appscode.com
labels:
app: stash
spec:
group: stash.appscode.com
names:
kind: Recovery
listKind: RecoveryList
plural: recoveries
shortNames:
- rec
singular: recovery
scope: Namespaced
version: v1alpha1
---
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
name: recoveries.stash.appscode.com
labels:
app: stash
spec:
group: stash.appscode.com
names:
kind: Recovery
listKind: RecoveryList
plural: recoveries
shortNames:
- rec
singular: recovery
scope: Namespaced
version: v1alpha1
---
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
name: repositories.stash.appscode.com
labels:
app: stash
spec:
group: stash.appscode.com
names:
kind: Repository
listKind: RepositoryList
plural: repositories
shortNames:
- repo
singular: repository
scope: Namespaced
version: v1alpha1
2 changes: 1 addition & 1 deletion apis/stash/v1alpha1/helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import (
func (l LocalSpec) ToVolumeAndMount(volName string) (core.Volume, core.VolumeMount) {
vol := core.Volume{
Name: volName,
VolumeSource: l.VolumeSource,
VolumeSource: *l.VolumeSource.DeepCopy(), // avoid defaulting in MutatingWebhook
}
mnt := core.VolumeMount{
Name: volName,
Expand Down
11 changes: 11 additions & 0 deletions apis/stash/v1alpha1/objectref.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,14 @@ func (r Recovery) ObjectReference() *core.ObjectReference {
ResourceVersion: r.ResourceVersion,
}
}

func (r Repository) ObjectReference() *core.ObjectReference {
return &core.ObjectReference{
APIVersion: SchemeGroupVersion.String(),
Kind: ResourceKindRepository,
Namespace: r.Namespace,
Name: r.Name,
UID: r.UID,
ResourceVersion: r.ResourceVersion,
}
}
16 changes: 6 additions & 10 deletions apis/stash/v1alpha1/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,7 @@ const (
type Restic struct {
metav1.TypeMeta `json:",inline,omitempty"`
metav1.ObjectMeta `json:"metadata,omitempty"`
Spec ResticSpec `json:"spec,omitempty"`
Status ResticStatus `json:"status,omitempty"`
Spec ResticSpec `json:"spec,omitempty"`
}

type ResticSpec struct {
Expand All @@ -49,14 +48,6 @@ type ResticSpec struct {
ImagePullSecrets []core.LocalObjectReference `json:"imagePullSecrets,omitempty"`
}

type ResticStatus struct {
FirstBackupTime *metav1.Time `json:"firstBackupTime,omitempty"`
LastBackupTime *metav1.Time `json:"lastBackupTime,omitempty"`
LastSuccessfulBackupTime *metav1.Time `json:"lastSuccessfulBackupTime,omitempty"`
LastBackupDuration string `json:"lastBackupDuration,omitempty"`
BackupCount int64 `json:"backupCount,omitempty"`
}

// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object

type ResticList struct {
Expand Down Expand Up @@ -243,6 +234,11 @@ type RepositorySpec struct {
}

type RepositoryStatus struct {
FirstBackupTime *metav1.Time `json:"firstBackupTime,omitempty"`
LastBackupTime *metav1.Time `json:"lastBackupTime,omitempty"`
LastSuccessfulBackupTime *metav1.Time `json:"lastSuccessfulBackupTime,omitempty"`
LastBackupDuration string `json:"lastBackupDuration,omitempty"`
BackupCount int64 `json:"backupCount,omitempty"`
}

// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
Expand Down
73 changes: 28 additions & 45 deletions apis/stash/v1alpha1/zz_generated.deepcopy.go
Original file line number Diff line number Diff line change
Expand Up @@ -323,7 +323,7 @@ func (in *Repository) DeepCopyInto(out *Repository) {
out.TypeMeta = in.TypeMeta
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
in.Spec.DeepCopyInto(&out.Spec)
out.Status = in.Status
in.Status.DeepCopyInto(&out.Status)
return
}

Expand Down Expand Up @@ -400,6 +400,33 @@ func (in *RepositorySpec) DeepCopy() *RepositorySpec {
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *RepositoryStatus) DeepCopyInto(out *RepositoryStatus) {
*out = *in
if in.FirstBackupTime != nil {
in, out := &in.FirstBackupTime, &out.FirstBackupTime
if *in == nil {
*out = nil
} else {
*out = new(meta_v1.Time)
(*in).DeepCopyInto(*out)
}
}
if in.LastBackupTime != nil {
in, out := &in.LastBackupTime, &out.LastBackupTime
if *in == nil {
*out = nil
} else {
*out = new(meta_v1.Time)
(*in).DeepCopyInto(*out)
}
}
if in.LastSuccessfulBackupTime != nil {
in, out := &in.LastSuccessfulBackupTime, &out.LastSuccessfulBackupTime
if *in == nil {
*out = nil
} else {
*out = new(meta_v1.Time)
(*in).DeepCopyInto(*out)
}
}
return
}

Expand Down Expand Up @@ -435,7 +462,6 @@ func (in *Restic) DeepCopyInto(out *Restic) {
out.TypeMeta = in.TypeMeta
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
in.Spec.DeepCopyInto(&out.Spec)
in.Status.DeepCopyInto(&out.Status)
return
}

Expand Down Expand Up @@ -537,49 +563,6 @@ func (in *ResticSpec) DeepCopy() *ResticSpec {
return out
}

// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ResticStatus) DeepCopyInto(out *ResticStatus) {
*out = *in
if in.FirstBackupTime != nil {
in, out := &in.FirstBackupTime, &out.FirstBackupTime
if *in == nil {
*out = nil
} else {
*out = new(meta_v1.Time)
(*in).DeepCopyInto(*out)
}
}
if in.LastBackupTime != nil {
in, out := &in.LastBackupTime, &out.LastBackupTime
if *in == nil {
*out = nil
} else {
*out = new(meta_v1.Time)
(*in).DeepCopyInto(*out)
}
}
if in.LastSuccessfulBackupTime != nil {
in, out := &in.LastSuccessfulBackupTime, &out.LastSuccessfulBackupTime
if *in == nil {
*out = nil
} else {
*out = new(meta_v1.Time)
(*in).DeepCopyInto(*out)
}
}
return
}

// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ResticStatus.
func (in *ResticStatus) DeepCopy() *ResticStatus {
if in == nil {
return nil
}
out := new(ResticStatus)
in.DeepCopyInto(out)
return out
}

// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *RestoreStats) DeepCopyInto(out *RestoreStats) {
*out = *in
Expand Down
2 changes: 2 additions & 0 deletions chart/stable/stash/templates/user-roles.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ rules:
resources:
- restics
- recoveries
- repositories
verbs:
- create
- delete
Expand All @@ -34,6 +35,7 @@ rules:
resources:
- restics
- recoveries
- repositories
verbs:
- get
- list
Expand Down
117 changes: 117 additions & 0 deletions docs/concepts/crds/repository.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
> New to Stash? Please start [here](/docs/concepts/README.md).
# Repository

## What is Repository
A `Repository` is a Kubernetes `CustomResourceDefinition (CRD)`. It provides information of a [restic](https://restic.net/) repository in Kubernetes native way. When [stash](/docs/concepts/what-is-stash/overview.md) sidecar create a restic repository for backup in desired backend, it also create a `Repository` CRD object with relevant information of the repository. This enable user to view backup status of the workloads very easily.

## Repository CRD structure
A sample `Repository` CRD object for backup a `Deployment` in local backend is shown below,

```yaml
apiVersion: stash.appscode.com/v1alpha1
kind: Repository
metadata:
clusterName: ""
creationTimestamp: 2018-03-29T05:39:04Z
generation: 0
labels:
restic: stash-demo
workload-kind: Deployment
workload-name: stash-demo
name: deployment.stash-demo
namespace: default
resourceVersion: "10389"
selfLink: /apis/stash.appscode.com/v1alpha1/namespaces/default/repositories/deployment.stash-demo
uid: 7db206b0-3313-11e8-ad40-0800277f165c
spec:
backend:
local:
hostPath:
path: /data/stash-test/restic-repo
mountPath: /safe/data
storageSecretName: local-secret
backupPath: deployment/stash-demo
status:
backupCount: 3
firstBackupTime: 2018-03-29T05:40:05Z
lastBackupDuration: 2.724088654s
lastBackupTime: 2018-03-29T05:42:04Z
```
Here, we are going describe some important sections of `Repository` CRD.

## Repository Labels

`Repository` maintain some important information in label. These labels enable user to filter `Repository` according to `restic`, `workload-kind`, `workload-name`, `node-name` etc. Details of these labels are given below.

| Label name | Description |
| --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `restic` | Name of the `Restic` which is responsible for this `Repository`. |
| `workload-kind` | `Kind` of the workload for which the `Repository` has been created. |
| `workload-name` | `Name` of the workload for which the `Repository` has been created. |
| `pod-name` | This `label` present when the respective workload is `StatefulSet`. It represent the pod name of the `StatefulSet` who is responsible for this `Repository`. |
| `node-name` | This `label` present when the respective workload is `DaemonSet`. It represent the node name where the `DaemonSet` is running. |

## Repository Spec

`Repository` CRD needs the following information in `.spec` section.

### spec.backend

`spec.backend` holds the backend information where the backup snapshots are being stored. To learn how to configure various backends for Restic, please visit [here](/docs/guides/backends.md).

### spec.backupPath

`spec.backupPath` denotes the directory inside the backend where the snapshots are being stored.

## Repository Status

Stash operator updates `.status` of a Repository CRD every time a backup operation is completed.

- `status.backupCount` indicated the total number of backup operation completed for this Repository.
- `status.firstBackupTime` indicates the timestamp of first backup operation.
- `status.lastBackupTime` indicates the timestamp of last backup operation.
- `status.lastSuccessfulBackupTime` indicates the timestamp of last successful backup operation. If `status.lastBackupTime` and `status.lastSuccessfulBackupTime` are same, it means that last backup operation was successful.
- `status.lastBackupDuration` indicates the duration of last backup operation.

## Creation of Repository CRD

Whenever a `restic` repository is created according to [these](/docs/concepts/crds/restic.md#backup-repository-structure) rules, it also create respective `Repository` CRD object. Name of this `Repository` CRD object is generated based on rules below:

- For workload kind `Deployment`, `Replicaset` and `ReplicationController` `Repository` is created with name `<WORKLOAD_KIND>.<WORKLOAD_NAME>`. For multiple replicas, only one `Repository` is created as backup is taken by sidecar of replica determined by leader-election.
- For workload kind `Statefulset` `Repository` is created with name`<WORKLOAD_KIND>.<POD_NAME>`. A separate `Repository` is created for each replica of a StatefulSet..
- For workload kind `Daemonset` Repository is created with name `<WORKLOAD_KIND>.<WORKLOAD_NAME>.<NODE_NAME>`. One repository is created for each node where pods of a DaemonSet are running.

## Working with Repository CRD

Here are some helpful commands to play with `Repository` CRD,

```
# List all Repositories of all namespaces in the cluster
$ kubectl get repository --all-namespaces

# List all Repositories created for a particular Restic
$ kubectl get repository -l restic=stash-demo --all-namespaces

# List all Repositories of Deployment workloads of all namespaces
$ kubectl get repository -l workload-kind=Deployment --all-namespaces

# List all Respositories of a particular Workload
$ kubectl get repository -l workload-kind=StatefulSet,workload-name=stash-demo

# List all Repositories of a particular node (DaemonSet only)
$ kubectl get repository -l node-name=minikube
```
## Next Steps
- Learn how to use Stash to backup a Kubernetes deployment [here](/docs/guides/backup.md).
- To restore a backup see [here](/docs/guides/restore.md).
- Learn about the details of Recovery CRD [here](/docs/concepts/crds/recovery.md).
- To run backup in offline mode see [here](/docs/guides/offline_backup.md)
- See the list of supported backends and how to configure them [here](/docs/guides/backends.md).
- See working examples for supported workload types [here](/docs/guides/workloads.md).
- Thinking about monitoring your backup operations? Stash works [out-of-the-box with Prometheus](/docs/guides/monitoring.md).
- Learn about how to configure [RBAC roles](/docs/guides/rbac.md).
- Want to hack on Stash? Check our [contribution guidelines](/docs/CONTRIBUTING.md).
12 changes: 2 additions & 10 deletions docs/concepts/crds/restic.md
Original file line number Diff line number Diff line change
Expand Up @@ -107,15 +107,6 @@ At each tick, `restic backup` and `restic forget` commands are run for each of t
- For workload kind `Statefulset` restic repository is created in the sub-directory `<WORKLOAD_KIND>/<POD_NAME>`. For multiple replicas, multiple repositories are created and sidecar is added to all pods.
- For workload kind `Daemonset` restic repository is created in the sub-directory `<WORKLOAD_KIND>/<WORKLOAD_NAME>/<NODE_NAME>`. For multiple replicas, multiple repositories are created and sidecar is added to all pods.

## Restic Status
Stash operator updates `.status` of a Restic CRD every time a backup operation is completed.

- `status.backupCount` indicated the total number of backup operation completed for this Restic CRD.
- `status.firstBackupTime` indicates the timestamp of first backup operation.
- `status.lastBackupTime` indicates the timestamp of last backup operation.
- `status.lastSuccessfulBackupTime` indicates the timestamp of last successful backup operation. If `status.lastBackupTime` and `status.lastSuccessfulBackupTime` are same, it means that last backup operation was successful.
- `status.lastBackupDuration` indicates the duration of last backup operation.

## Workload Annotations
For each workload where a sidecar container is added by Stash operator, the following annotations are added:

Expand All @@ -137,10 +128,11 @@ To stop Restic from taking backup, you can do following things:

* Change the labels of a workload. Stash operator will remove sidecar container from that workload. This way you can selectively stop backup of a Deployment, ReplicaSet etc.

For more details about how to disable and resume Restic see [here](/docs/guides/backup.md#disable-backup).
For more details about how to disable and resume Restic see [here](/docs/guides/backup.md#disable-backup).

## Next Steps

- Learn about Repository CRD [here](/docs/concepts/crds/repository.md)
- Learn how to use Stash to backup a Kubernetes deployment [here](/docs/guides/backup.md).
- To restore a backup see [here](/docs/guides/restore.md).
- Learn about the details of Recovery CRD [here](/docs/concepts/crds/recovery.md).
Expand Down
Loading

0 comments on commit 7568e62

Please sign in to comment.