Last active
May 9, 2018 22:12
-
-
Save liangrog/3210939df1c3ea3dd0a9df1eb97fee32 to your computer and use it in GitHub Desktop.
pseudo codes for implementing external-storage provisioner interface used in Medium article
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"flag" | |
"github.com/golang/glog" | |
"k8s.io/apimachinery/pkg/util/wait" | |
"k8s.io/client-go/kubernetes" | |
"k8s.io/client-go/rest" | |
"github.com/kubernetes-incubator/external-storage/lib/controller" | |
) | |
// Main func | |
func main() { | |
flag.Parse() | |
flag.Set("logtostderr", "true") | |
// Create an InClusterConfig and use it to create a client for the controller | |
// to use to communicate with Kubernetes | |
config, err := rest.InClusterConfig() | |
if err != nil { | |
glog.Fatalf("Failed to create config: %v", err) | |
} | |
clientset, err := kubernetes.NewForConfig(config) | |
if err != nil { | |
glog.Fatalf("Failed to create client: %v", err) | |
} | |
// The controller needs to know what the server version is because out-of-tree | |
// provisioners aren't officially supported until 1.5 | |
serverVersion, err := clientset.Discovery().ServerVersion() | |
if err != nil { | |
glog.Fatalf("Error getting server version: %v", err) | |
} | |
provisioner := NewAwesomeProvisioner(clientset, "awesome-no-1") | |
// Start the provision controller which will dynamically | |
// provision awesome volume PVs | |
pc := controller.NewProvisionController( | |
clientset, | |
"storage-class-name", | |
provisioner, | |
serverVersion.GitVersion, | |
) | |
pc.Run(wait.NeverStop) | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// awesomeProvisioner | |
package main | |
import ( | |
"errors" | |
"github.com/golang/glog" | |
"k8s.io/api/core/v1" | |
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | |
"k8s.io/client-go/kubernetes" | |
"github.com/kubernetes-incubator/external-storage/lib/controller" | |
"github.com/kubernetes-incubator/external-storage/lib/util" | |
) | |
// Provisioner struct | |
type awesomeProvisioner struct { | |
// kubernetes api client | |
client kubernetes.Interface | |
// Provisioner identity so you can | |
// run multiple provisioners. Each | |
// is responsible for separate sets of PVs | |
id string | |
} | |
// Constructor | |
func NewAwesomeProvisioner(c kubernetes.Interface, id string) controller.Provisioner { | |
return &awesomeProvisioner{client: c, id: id} | |
} | |
// Calling other APIs to provision a persistent volume | |
// and return the volume ID | |
func createAwesomeVolume(size string) string { | |
/* Do your magic here */ | |
} | |
// Calling other APIs to delete persistent | |
// volume by given id | |
func deleteAwesomeVolume(id string) error { | |
/* Do your magic here */ | |
} | |
// Implementing external-storage controller required interface | |
func (p *awesomeProvisioner) Provision(options controller.VolumeOptions) (*v1.PersistentVolume, error) { | |
// Get volume size requirement from PVC | |
volumeSize := util.RoundUpSize(options.PVC.Spec.Resources.Requests[v1.ResourceName(v1.ResourceStorage)].Value(), util.GiB) | |
// Provisioning the physical volume | |
volumeId := createAwesomeVolume(util.RoundUpSize(volumeSize.Value(), util.GiB)) | |
// This is the drive your created in "Part 1" | |
driver := "vendor/driver" | |
// You can change to any file type as long as | |
// your drive can deal with it | |
fsType := "xfs" | |
// PV spec, similar to a PV manifest | |
pv := &v1.PersistentVolume{ | |
ObjectMeta: metav1.ObjectMeta{ | |
Name: options.PVName, | |
Annotations: map[string]string{ | |
"awesomeProvisionerIdentity": p.id, | |
}, | |
}, | |
Spec: v1.PersistentVolumeSpec{ | |
PersistentVolumeReclaimPolicy: options.PersistentVolumeReclaimPolicy, | |
AccessModes: options.PVC.Spec.AccessModes, | |
Capacity: v1.ResourceList{ | |
v1.ResourceName(v1.ResourceStorage): options.PVC.Spec.Resources.Requests[v1.ResourceName(v1.ResourceStorage)], | |
}, | |
PersistentVolumeSource: v1.PersistentVolumeSource{ | |
FlexVolume: &v1.FlexPersistentVolumeSource{ | |
Driver: driver, | |
FSType: fsType, | |
// Provide the name of the secret | |
// if you are using one | |
SecretRef: &v1.SecretReference{ | |
Name: os.Getenv("secret-name"), | |
Namespace: options.PVC.Namespace, | |
}, | |
ReadOnly: false, | |
Options: map[string]string{"volumeId": volumeId}, | |
}, | |
}, | |
}, | |
} | |
return pv, nil | |
} | |
// Implementing external-storage controller required interface | |
func (p *awesomeProvisioner) Delete(volume *v1.PersistentVolume) error { | |
// Check if requested PV should be processed by this provisioner | |
ann, ok := volume.Annotations["awesomeProvisionerIdentity"] | |
if !ok { | |
return errors.New("identity annotation not found on PV") | |
} | |
if ann != p.id { | |
return &controller.IgnoredError{"identity annotation on PV does not match"} | |
} | |
// Get volumeId from PV that created by this provisioner | |
volumeId := volume.Spec.PersistentVolumeSource.FlexVolume.Options["volumeId"] | |
glog.Infof("Received request to delete awesome volume (ID: %s)\n", volumeId) | |
// delete the physical volume | |
err := DeleteAwesomeVolume(volumeId) | |
if err == nil { | |
glog.Infof("Successfully deleted awesome volume (ID: %s)\n", volumeId) | |
} | |
return err | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment