Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create a cloned OpenEBS (jiva) Volume from a snapshot #283

Merged
merged 3 commits into from
Mar 28, 2018

Conversation

prateekpandey14
Copy link
Contributor

@prateekpandey14 prateekpandey14 commented Mar 21, 2018

What this PR does / why we need it:
This PR will extends the volume create API to create a cloned volume by taking in source volume and source snapshot details. This feature will be used by the Snapshot provisioner to promote a snapshot into a PV.

Special Note:
This PR is part of a feature that spans across multiple repos.

Related PRs:

  1. Jiva replica clone feature jiva#44
  2. Add openebs snapshot feature external-storage#37

Note on the Changes:
The Volume Create Spec is extended to include:

  • CloneIP - Source Controller IP
  • SnapshotName - Source Volume Snapshot Name

The Jiva Replica command line takes 3 new ags:

  • cloneIP : This is frontendIP of running source controller, which will be used to make a clone request, will be passed as a argument while starting clone replica.
  • type=clone: Type of replica, now we can pass type as clone to trigger the clone API of jiva, which says the new replica is getting added as clone not as usual replica.
  • snapName : Name of the snapshot which will be synced/cloned to a new persistent volume.

The replica when it comes up as clone, will register itself with it controller in write-only mode. Then issue a sync request to the source controller. Restore to the snapshot provided and convert itself into read-write mode.

Current implementation only support launching of clone volume in read-only mode. To support read-write clones, further cases need to be handled.

The changes were tested by using custom images of jiva and provisioner:

  1. Created PVC demo-vol1-claim ( 5GB volume ), which has been formatted/mounted, and write some data inside that.
  2. Created a snapshot fastfurious for the ``demo-vol1-claim` pvc.
  3. used created snapshot fastfurious to restore as a new PVC snapshot-pv-provisioning
  4. Mounted the new volume and verified the data by comparing the Hash value

**Detailed Output of snapshot and new PVC **:

  1. Created snapshot fastfurious of a pvc `demo-vol1-claim
$ kubectl get volumesnapshot,volumesnapshotdata
NAME                          AGE
volumesnapshots/fastfurious   1h

NAME                                                                           AGE
volumesnapshotdatas/k8s-volume-snapshot-ab9d6035-325f-11e8-881b-54e1ad0c1ccc   1h
$ kubectl get volumesnapshot,volumesnapshotdata -o yaml
apiVersion: v1
items:
- apiVersion: volumesnapshot.external-storage.k8s.io/v1
  kind: VolumeSnapshot
  metadata:
    clusterName: ""
    creationTimestamp: 2018-03-28T08:11:51Z
    generation: 1
    labels:
      SnapshotMetadata-PVName: pvc-44f62bc6-325d-11e8-bd8d-54e1ad0c1ccc
      SnapshotMetadata-Timestamp: "1522224711632395804"
    name: fastfurious
    namespace: default
    resourceVersion: "5050"
    selfLink: /apis/volumesnapshot.external-storage.k8s.io/v1/namespaces/default/volumesnapshots/fastfurious
    uid: ab77fa61-325f-11e8-bd8d-54e1ad0c1ccc
  spec:
    persistentVolumeClaimName: demo-vol1-claim
    snapshotDataName: k8s-volume-snapshot-ab9d6035-325f-11e8-881b-54e1ad0c1ccc
  status:
    conditions:
    - lastTransitionTime: 2018-03-28T08:11:51Z
      message: Snapshot created successfully
      reason: ""
      status: "True"
      type: Ready
    creationTimestamp: null
- apiVersion: volumesnapshot.external-storage.k8s.io/v1
  kind: VolumeSnapshotData
  metadata:
    clusterName: ""
    creationTimestamp: 2018-03-28T08:11:51Z
    generation: 1
    name: k8s-volume-snapshot-ab9d6035-325f-11e8-881b-54e1ad0c1ccc
    namespace: ""
    resourceVersion: "5049"
    selfLink: /apis/volumesnapshot.external-storage.k8s.io/v1/volumesnapshotdatas/k8s-volume-snapshot-ab9d6035-325f-11e8-881b-54e1ad0c1ccc
    uid: ab9dd581-325f-11e8-bd8d-54e1ad0c1ccc
  spec:
    openebsVolume:
      snapshotId: pvc-44f62bc6-325d-11e8-bd8d-54e1ad0c1ccc_1522224711637025925
    persistentVolumeRef:
      kind: PersistentVolume
      name: pvc-44f62bc6-325d-11e8-bd8d-54e1ad0c1ccc
    volumeSnapshotRef:
      kind: VolumeSnapshot
      name: default/fastfurious
  status:
    conditions:
    - lastTransitionTime: null
      message: Snapshot created successfully
      reason: ""
      status: "True"
      type: Ready
    creationTimestamp: null
kind: List
metadata:
  resourceVersion: ""
  selfLink: ""
  1. Promoted snapshot fastfurious as a new PVC snapshot-pv-provisioning
$ kubectl get pvc snapshot-pv-provisioning-demo -o yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  annotations:
    control-plane.alpha.kubernetes.io/leader: '{"holderIdentity":"83677192-325f-11e8-b068-54e1ad0c1ccc","leaseDurationSeconds":15,"acquireTime":"2018-03-28T08:19:58Z","renewTime":"2018-03-28T08:20:00Z","leaderTransitions":0}'
    pv.kubernetes.io/bind-completed: "yes"
    pv.kubernetes.io/bound-by-controller: "yes"
    snapshot.alpha.kubernetes.io/snapshot: fastfurious
    volume.beta.kubernetes.io/storage-provisioner: volumesnapshot.external-storage.k8s.io/snapshot-promoter
  creationTimestamp: 2018-03-28T08:19:58Z
  finalizers:
  - kubernetes.io/pvc-protection
  name: snapshot-pv-provisioning-demo
  namespace: default
  resourceVersion: "5658"
  selfLink: /api/v1/namespaces/default/persistentvolumeclaims/snapshot-pv-provisioning-demo
  uid: cda83b58-3260-11e8-bd8d-54e1ad0c1ccc
spec:
  accessModes:
  - ReadWriteOnce
  resources:
    requests:
      storage: 5G
  storageClassName: snapshot-promoter
  volumeName: pvc-cda83b58-3260-11e8-bd8d-54e1ad0c1ccc
status:
  accessModes:
  - ReadWriteOnce
  capacity:
    storage: 5G
  phase: Bound
$ kubectl get pods pvc-cda83b58-3260-11e8-bd8d-54e1ad0c1ccc-ctrl-6f5f68cbf4-6btfj -o yaml
apiVersion: v1
kind: Pod
metadata:
  creationTimestamp: 2018-03-28T08:19:58Z
  generateName: pvc-cda83b58-3260-11e8-bd8d-54e1ad0c1ccc-ctrl-6f5f68cbf4-
  labels:
    openebs/controller: jiva-controller
    pod-template-hash: "2919247690"
    vsm: pvc-cda83b58-3260-11e8-bd8d-54e1ad0c1ccc
  name: pvc-cda83b58-3260-11e8-bd8d-54e1ad0c1ccc-ctrl-6f5f68cbf4-6btfj
  namespace: default
  ownerReferences:
  - apiVersion: extensions/v1beta1
    blockOwnerDeletion: true
    controller: true
    kind: ReplicaSet
    name: pvc-cda83b58-3260-11e8-bd8d-54e1ad0c1ccc-ctrl-6f5f68cbf4
    uid: cde59b54-3260-11e8-bd8d-54e1ad0c1ccc
  resourceVersion: "5668"
  selfLink: /api/v1/namespaces/default/pods/pvc-cda83b58-3260-11e8-bd8d-54e1ad0c1ccc-ctrl-6f5f68cbf4-6btfj
  uid: cdf468e4-3260-11e8-bd8d-54e1ad0c1ccc
spec:
  containers:
  - args:
    - controller
    - --frontend
    - gotgt
    - --clusterIP
    - 10.0.0.26
    - pvc-cda83b58-3260-11e8-bd8d-54e1ad0c1ccc
    command:
    - launch
    image: openebs/jiva:clone
    imagePullPolicy: IfNotPresent
    name: pvc-cda83b58-3260-11e8-bd8d-54e1ad0c1ccc-ctrl-con
    ports:
    - containerPort: 3260
      protocol: TCP
    - containerPort: 9501
      protocol: TCP
    resources: {}
    terminationMessagePath: /dev/termination-log
    terminationMessagePolicy: File
    volumeMounts:
    - mountPath: /var/run/secrets/kubernetes.io/serviceaccount
      name: default-token-g6h76
      readOnly: true
  dnsPolicy: ClusterFirst
  nodeName: 127.0.0.1
  restartPolicy: Always
  schedulerName: default-scheduler
  securityContext: {}
  serviceAccount: default
  serviceAccountName: default
  terminationGracePeriodSeconds: 30
  tolerations:
  - effect: NoExecute
    key: node.alpha.kubernetes.io/notReady
    operator: Exists
    tolerationSeconds: 0
  - effect: NoExecute
    key: node.alpha.kubernetes.io/unreachable
    operator: Exists
    tolerationSeconds: 0
  - effect: NoExecute
    key: node.kubernetes.io/not-ready
    operator: Exists
    tolerationSeconds: 300
  - effect: NoExecute
    key: node.kubernetes.io/unreachable
    operator: Exists
    tolerationSeconds: 300
  volumes:
  - name: default-token-g6h76
    secret:
      defaultMode: 420
      secretName: default-token-g6h76
status:
  conditions:
  - lastProbeTime: null
    lastTransitionTime: 2018-03-28T08:19:59Z
    status: "True"
    type: Initialized
  - lastProbeTime: null
    lastTransitionTime: 2018-03-28T08:20:03Z
    status: "True"
    type: Ready
  - lastProbeTime: null
    lastTransitionTime: 2018-03-28T08:19:58Z
    status: "True"
    type: PodScheduled
  containerStatuses:
  - containerID: docker://4faa766c5c21f58a78e3a77e61e0e57f20080066b967071b9a2f7a4b814ee02f
    image: openebs/jiva:clone
    imageID: docker://sha256:e71b32b1cfe11874e22a71af11388b7fe4473279754acf46a53f7cad4113b6b9
    lastState: {}
    name: pvc-cda83b58-3260-11e8-bd8d-54e1ad0c1ccc-ctrl-con
    ready: true
    restartCount: 0
    state:
      running:
        startedAt: 2018-03-28T08:20:03Z
  hostIP: 127.0.0.1
  phase: Running
  podIP: 172.17.0.7
  qosClass: BestEffort
  startTime: 2018-03-28T08:19:59Z
 $ kubectl get pods pvc-cda83b58-3260-11e8-bd8d-54e1ad0c1ccc-rep-5fcbd794f7-rgwj6 -o yaml
apiVersion: v1
kind: Pod
metadata:
  creationTimestamp: 2018-03-28T08:19:58Z
  generateName: pvc-cda83b58-3260-11e8-bd8d-54e1ad0c1ccc-rep-5fcbd794f7-
  labels:
    openebs/replica: jiva-replica
    pod-template-hash: "1976835093"
    vsm: pvc-cda83b58-3260-11e8-bd8d-54e1ad0c1ccc
  name: pvc-cda83b58-3260-11e8-bd8d-54e1ad0c1ccc-rep-5fcbd794f7-rgwj6
  namespace: default
  ownerReferences:
  - apiVersion: extensions/v1beta1
    blockOwnerDeletion: true
    controller: true
    kind: ReplicaSet
    name: pvc-cda83b58-3260-11e8-bd8d-54e1ad0c1ccc-rep-5fcbd794f7
    uid: cdf1759a-3260-11e8-bd8d-54e1ad0c1ccc
  resourceVersion: "5673"
  selfLink: /api/v1/namespaces/default/pods/pvc-cda83b58-3260-11e8-bd8d-54e1ad0c1ccc-rep-5fcbd794f7-rgwj6
  uid: cdf4aae0-3260-11e8-bd8d-54e1ad0c1ccc
spec:
  affinity:
    podAntiAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
      - labelSelector:
          matchLabels:
            openebs/replica: jiva-replica
            vsm: pvc-cda83b58-3260-11e8-bd8d-54e1ad0c1ccc
        topologyKey: kubernetes.io/hostname
  containers:
  - args:
    - replica
    - --frontendIP
    - 10.0.0.26
    - --cloneIP
    - 172.17.0.5
    - --type
    - clone
    - --snapName
    - pvc-44f62bc6-325d-11e8-bd8d-54e1ad0c1ccc_1522224711637025925
    - --size
    - 5G
    - /openebs
    command:
    - launch
    image: openebs/jiva:clone
    imagePullPolicy: IfNotPresent
    name: pvc-cda83b58-3260-11e8-bd8d-54e1ad0c1ccc-rep-con
    ports:
    - containerPort: 9502
      protocol: TCP
    - containerPort: 9503
      protocol: TCP
    - containerPort: 9504
      protocol: TCP
    resources: {}
    terminationMessagePath: /dev/termination-log
    terminationMessagePolicy: File
    volumeMounts:
    - mountPath: /openebs
      name: openebs
    - mountPath: /var/run/secrets/kubernetes.io/serviceaccount
      name: default-token-g6h76
      readOnly: true
  dnsPolicy: ClusterFirst
  nodeName: 127.0.0.1
  restartPolicy: Always
  schedulerName: default-scheduler
  securityContext: {}
  serviceAccount: default
  serviceAccountName: default
  terminationGracePeriodSeconds: 30
  tolerations:
  - effect: NoExecute
    key: node.alpha.kubernetes.io/notReady
    operator: Exists
  - effect: NoExecute
    key: node.alpha.kubernetes.io/unreachable
    operator: Exists
  - effect: NoExecute
    key: node.kubernetes.io/not-ready
    operator: Exists
    tolerationSeconds: 300
  - effect: NoExecute
    key: node.kubernetes.io/unreachable
    operator: Exists
    tolerationSeconds: 300
  volumes:
  - hostPath:
      path: /var/openebs/pvc-cda83b58-3260-11e8-bd8d-54e1ad0c1ccc
      type: ""
    name: openebs
  - name: default-token-g6h76
    secret:
      defaultMode: 420
      secretName: default-token-g6h76
status:
  conditions:
  - lastProbeTime: null
    lastTransitionTime: 2018-03-28T08:19:59Z
    status: "True"
    type: Initialized
  - lastProbeTime: null
    lastTransitionTime: 2018-03-28T08:20:04Z
    status: "True"
    type: Ready
  - lastProbeTime: null
    lastTransitionTime: 2018-03-28T08:19:58Z
    status: "True"
    type: PodScheduled
  containerStatuses:
  - containerID: docker://63a93ed98465525b2ace7b007be4de95af93739abaaa47e5964417c76fcf3879
    image: openebs/jiva:clone
    imageID: docker://sha256:e71b32b1cfe11874e22a71af11388b7fe4473279754acf46a53f7cad4113b6b9
    lastState: {}
    name: pvc-cda83b58-3260-11e8-bd8d-54e1ad0c1ccc-rep-con
    ready: true
    restartCount: 0
    state:
      running:
        startedAt: 2018-03-28T08:20:03Z
  hostIP: 127.0.0.1
  phase: Running
  podIP: 172.17.0.8
  qosClass: BestEffort
  startTime: 2018-03-28T08:19:59Z
$ kubectl get all
NAME                                                   DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
deploy/maya-apiserver                                  1         1         1            1           1h
deploy/openebs-provisioner                             1         1         1            1           1h
deploy/pvc-44f62bc6-325d-11e8-bd8d-54e1ad0c1ccc-ctrl   1         1         1            1           1h
deploy/pvc-44f62bc6-325d-11e8-bd8d-54e1ad0c1ccc-rep    1         1         1            1           1h
deploy/pvc-cda83b58-3260-11e8-bd8d-54e1ad0c1ccc-ctrl   1         1         1            1           53m
deploy/pvc-cda83b58-3260-11e8-bd8d-54e1ad0c1ccc-rep    1         1         1            1           53m

NAME                                                          DESIRED   CURRENT   READY     AGE
rs/maya-apiserver-6d5f66d777                                  1         1         1         1h
rs/openebs-provisioner-5dcbb54ff4                             1         1         1         1h
rs/pvc-44f62bc6-325d-11e8-bd8d-54e1ad0c1ccc-ctrl-58774bbbf4   1         1         1         1h
rs/pvc-44f62bc6-325d-11e8-bd8d-54e1ad0c1ccc-rep-ff6d865c4     1         1         1         1h
rs/pvc-cda83b58-3260-11e8-bd8d-54e1ad0c1ccc-ctrl-6f5f68cbf4   1         1         1         53m
rs/pvc-cda83b58-3260-11e8-bd8d-54e1ad0c1ccc-rep-5fcbd794f7    1         1         1         53m

NAME                                                                READY     STATUS    RESTARTS   AGE
po/maya-apiserver-6d5f66d777-svdgw                                  1/1       Running   0          1h
po/openebs-provisioner-5dcbb54ff4-f6tdt                             1/1       Running   0          1h
po/pvc-44f62bc6-325d-11e8-bd8d-54e1ad0c1ccc-ctrl-58774bbbf4-ghwfz   1/1       Running   0          1h
po/pvc-44f62bc6-325d-11e8-bd8d-54e1ad0c1ccc-rep-ff6d865c4-8v76d     1/1       Running   0          1h
po/pvc-cda83b58-3260-11e8-bd8d-54e1ad0c1ccc-ctrl-6f5f68cbf4-6btfj   1/1       Running   0          53m
po/pvc-cda83b58-3260-11e8-bd8d-54e1ad0c1ccc-rep-5fcbd794f7-rgwj6    1/1       Running   0          53m

NAME                                                    TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)             AGE
svc/kubernetes                                          ClusterIP   10.0.0.1     <none>        443/TCP             2h
svc/maya-apiserver-service                              ClusterIP   10.0.0.215   <none>        5656/TCP            1h
svc/pvc-44f62bc6-325d-11e8-bd8d-54e1ad0c1ccc-ctrl-svc   ClusterIP   10.0.0.60    <none>        3260/TCP,9501/TCP   1h
svc/pvc-cda83b58-3260-11e8-bd8d-54e1ad0c1ccc-ctrl-svc   ClusterIP   10.0.0.26    <none>        3260/TCP,9501/TCP   53m

Signed-off-by: prateekpandey14 prateekpandey14@gmail.com

This PR will add snapshot API for clone feature.

Signed-off-by: prateekpandey14 <prateekpandey14@gmail.com>
@codecov
Copy link

codecov bot commented Mar 21, 2018

Codecov Report

Merging #283 into master will not change coverage.
The diff coverage is 100%.

Impacted file tree graph

@@           Coverage Diff           @@
##           master     #283   +/-   ##
=======================================
  Coverage   27.72%   27.72%           
=======================================
  Files          58       58           
  Lines        4476     4476           
=======================================
  Hits         1241     1241           
  Misses       3089     3089           
  Partials      146      146
Impacted Files Coverage Δ
orchprovider/k8s/v1/k8s.go 31.52% <100%> (ø) ⬆️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 36a3424...c71528d. Read the comment docs.

@@ -25,6 +25,8 @@ func (s *HTTPServer) snapshotSpecificRequest(resp http.ResponseWriter, req *http
return s.snapshotCreate(resp, req)
case strings.Contains(path, "/revert/"):
return s.snapshotRevert(resp, req)
case strings.Contains(path, "/clone/"):

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you think it will be good if we explain somewhere in the comments or commit or PR on:

  • Snapshot
  • Clone
  • Promote
    This helps contributors as well as docs.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Workflow is changed now, API no longer exists.

@@ -167,6 +169,17 @@ func (s *HTTPServer) snapshotList(resp http.ResponseWriter, req *http.Request, v

}

// SnapshotClone is http handler for restore a snapshot to a persistent volume

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some more explanation might be nice. Some questions that arise here are:

  • Are the PV already available?
  • Are the snapshots already available?
  • Is this possible if all are in the same namespace, different namespaces, different clusters?

You need not put these info here. But this should be answered somewhere.
Was there a design doc that tries to talk about these things?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Workflow is changed now, API no longer exists.

// SnapshotClone is http handler for restore a snapshot to a persistent volume
func (s *HTTPServer) snapshotClone(resp http.ResponseWriter, req *http.Request) (interface{}, error) {

clone, err := s.volumeAdd(resp, req)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is adding a volume. Why are we calling it as a clone.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let us not reuse the methods here & inject if else conditionals throughout the code.
We will be better off if we go for well defined/dedicated structures that handle clone & snapshot respectively.

//
// NOTE:
// This is replaced at runtime
JivaCloneIPHolder JivaAnnotations = "__CLONE_IP__"

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are we calling these as annotations? I guess this is an old type that we are re-using. But lets make it a point to avoid once we feel that this design/code is not good.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, these are coming from the Volume struct, just using this to pass as replica args .

types/v1/util.go Outdated

repArgs := make([]string, len(JivaReplicaArgs))
if cloneIP == "" {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe its best to avoid this if else by structuring the code better.
Probably a new struct that deals with clone would have been great.
When the complexity arises with new business logic/features, a well defined struct will be able to handle this better.

This PR will extend the maya-apiserver volume create
API's to create volume clone feature.

Signed-off-by: prateekpandey14 <prateekpandey14@gmail.com>
@prateekpandey14 prateekpandey14 changed the title [WIP] Add Snapshot clone API Extend Volume API to support for volume clone feature Mar 27, 2018
@kmova
Copy link
Contributor

kmova commented Mar 27, 2018

@prateekpandey14 The changes look fine. Couple of high level comments.

  • How was this change tested? Can you paste the API request and response file with and without clone related parameters?
  • Can you raise an issue to support invoking the clone api via the mayactl? This way we can add this to the e2e tests.

@prateekpandey14 prateekpandey14 self-assigned this Mar 27, 2018
@kmova kmova changed the title Extend Volume API to support for volume clone feature Create a cloned OpenEBS (jiva) Volume from a snapshot Mar 28, 2018
@kmova kmova merged commit 362bdfa into openebs-archive:master Mar 28, 2018
@prateekpandey14 prateekpandey14 deleted the snapshot-clone branch January 11, 2019 14:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants