Skip to content

Commit

Permalink
Changed Trident version to 17.04.0
Browse files Browse the repository at this point in the history
Rewrote Trident launcher to better support failures, error reporting, user arguments, and unit testing
Creation of volumes is an idempotent operation at the Trident layer
Closes Issue #16
  • Loading branch information
kangarlou committed Apr 7, 2017
1 parent 31e031f commit c5eae67
Show file tree
Hide file tree
Showing 23 changed files with 2,119 additions and 710 deletions.
7 changes: 6 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,15 @@
- Trident now allows ONTAP backends even if it cannot read the aggregate media type,
or if the media type is unknown. However, such backends will be ignored for storage
classes that require a specific media type.
- Trident launcher supports creating the ConfigMap in a non-default namespace.

**Enhancements:**

- Added release notes (CHANGELOG.md)
- The improved Trident launcher has a better support for failure recovery, error
reporting, user arguments, and unit testing.
- Enabled SVM-scoped users for ONTAP backends.
- Switched to using vserver-show-aggr-get-iter API for ONTAP 9.0 and later to get aggregate
media type.
- Added support for E-Series.
- Upgraded the etcd version to v3.1.3.
- Added release notes (CHANGELOG.md).
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
FROM debian:jessie
MAINTAINER Ardalan Kangarlou <[email protected]>

LABEL version="1.0" \
LABEL version="17.04.0" \
description="Kubernetes storage orchestrator"

RUN apt-get update && apt-get install -y \
Expand Down
12 changes: 6 additions & 6 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ BIN ?= trident_orchestrator

DIST_REGISTRY=netapp

TRIDENT_DIST_VERSION ?= 1.1
TRIDENT_DIST_VERSION ?= 17.04.0

TRIDENT_VERSION ?= local
TRIDENT_IMAGE ?= trident
Expand Down Expand Up @@ -130,7 +130,7 @@ test_core:
@docker rm etcd-test > /dev/null

test_other:
@go test -cover $(shell go list ./... | grep -v /vendor/ | grep -v core | grep -v persistent_store)
@go test -cover -v $(shell go list ./... | grep -v /vendor/ | grep -v core | grep -v persistent_store)

vet:
@go vet $(shell go list ./... | grep -v /vendor/)
Expand All @@ -157,14 +157,14 @@ launcher_build: check_registry launcher_retag
docker push ${LAUNCHER_TAG}
-docker rmi ${LAUNCHER_TAG_OLD}

docker_launcher_build:
docker_launcher_build: check_registry launcher_retag
@chmod 777 ./launcher/docker-build
@${GO} ${BUILD} -o ${TRIDENT_VOLUME_PATH}/launcher/docker-build/launcher ./launcher
docker build -t ${LAUNCHER_TAG} ./launcher/docker-build/
docker push ${LAUNCHER_TAG}
-docker rmi ${LAUNCHER_TAG_OLD}

launcher_start: check_registry
launcher_start: prep_pod_template
ifndef LAUNCHER_BACKEND
$(error Must define LAUNCHER_BACKEND to start the launcher.)
endif
Expand Down Expand Up @@ -207,10 +207,10 @@ endif
-kubectl delete --ignore-not-found=true pod trident-launcher
@mkdir -p ${LAUNCHER_CONFIG_DIR}
@cp ${LAUNCHER_BACKEND} ${LAUNCHER_CONFIG_DIR}/backend.json
@sed "s|__TRIDENT_IMAGE__|netapp/trident:1.0|g" kubernetes-yaml/trident-deployment.yaml.templ > ${LAUNCHER_CONFIG_DIR}/trident-deployment.yaml
@sed "s|__TRIDENT_IMAGE__|netapp/trident:latest|g" kubernetes-yaml/trident-deployment.yaml.templ > ${LAUNCHER_CONFIG_DIR}/trident-deployment.yaml
@echo "Usable Trident pod definition available at ./launcher/kubernetes-yaml/trident-deployment.yaml"
@kubectl create configmap trident-launcher-config --from-file=${LAUNCHER_CONFIG_DIR}
@sed "s|__LAUNCHER_TAG__|netapp/trident-launcher:1.0|g" ./launcher/kubernetes-yaml/launcher-pod.yaml.templ > ${LAUNCHER_POD_FILE}
@sed "s|__LAUNCHER_TAG__|netapp/trident-launcher:latest|g" ./launcher/kubernetes-yaml/launcher-pod.yaml.templ > ${LAUNCHER_POD_FILE}
@kubectl create -f ${LAUNCHER_POD_FILE}
@echo "Trident Launcher started; pod definition in ${LAUNCHER_POD_FILE}"

10 changes: 7 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ exposing users to complexities of various backends.
* [Backends](#backends)
* [ONTAP Configurations](#ontap-configurations)
* [SolidFire Configurations](#solidfire-configurations)
* [E-Series Configurations](#e-series configurations)
* [E-Series Configurations](#e-series-configurations)
* [Volume Configurations](#volume-configurations)
* [Storage Class Configurations](#storage-class-configurations)
* [Storage Attributes](#storage-attributes)
Expand Down Expand Up @@ -87,7 +87,8 @@ are not available, see the subsequent sections.
If you plan on using E-Series, create a Host Group named `trident` and create
a Host in that Host Group that contains the IQN of each node in the cluster.

5. Download and untar the [Trident installer bundle](https://github.com/NetApp/trident/releases/download/v1.0/trident-installer-1.0.tar.gz).
5. Download and untar the [Trident installer bundle](https://github.com/NetApp/trident/releases).
Then, change into the `trident-installer` directory resulted from untar.

6. Configure a storage backend from which Trident will provision its volumes.
This will also be used in step 8 to provision the PVC on which Trident will
Expand Down Expand Up @@ -199,7 +200,10 @@ them via Kubernetes are available in the [Storage Classes](#storage-classes)
section. For more details on how Trident chooses storage pools from a storage
class to provision its volumes, see [Provisioning Workflow](#provisioning-workflow).
The following tutorial presents an in-depth overview of Trident and demonstrates some advanced use cases:
The following tutorial presents an in-depth overview of Trident and demonstrates
some advanced use cases (the tutorial is based on v1.0, so please view
[CHANGELOG](https://github.com/NetApp/trident/blob/master/CHANGELOG.md) for
the changes since the first release):
[![Trident: External Provisioner for NetApp Storage](https://img.youtube.com/vi/NDcnyGe2GFo/0.jpg)](https://www.youtube.com/watch?v=NDcnyGe2GFo)
Expand Down
13 changes: 7 additions & 6 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ type VolumeType string
const (
/* Misc. orchestrator constants */
OrchestratorName = "trident"
OrchestratorVersion = "1.1"
OrchestratorVersion = "17.04.0"
OrchestratorAPIVersion = "1"
PersistentStoreTimeout = 60 * time.Second
MaxBootstrapAttempts = 10

Expand Down Expand Up @@ -55,11 +56,11 @@ var (
}
/* API Server and persistent store variables */
OrchestratorMajorVersion = getMajorVersion(OrchestratorVersion)
VersionURL = "/" + OrchestratorName + "/v" + OrchestratorMajorVersion + "/version"
BackendURL = "/" + OrchestratorName + "/v" + OrchestratorMajorVersion + "/backend"
VolumeURL = "/" + OrchestratorName + "/v" + OrchestratorMajorVersion + "/volume"
TransactionURL = "/" + OrchestratorName + "/v" + OrchestratorMajorVersion + "/txn"
StorageClassURL = "/" + OrchestratorName + "/v" + OrchestratorMajorVersion + "/storageclass"
VersionURL = "/" + OrchestratorName + "/v" + OrchestratorAPIVersion + "/version"
BackendURL = "/" + OrchestratorName + "/v" + OrchestratorAPIVersion + "/backend"
VolumeURL = "/" + OrchestratorName + "/v" + OrchestratorAPIVersion + "/volume"
TransactionURL = "/" + OrchestratorName + "/v" + OrchestratorAPIVersion + "/txn"
StorageClassURL = "/" + OrchestratorName + "/v" + OrchestratorAPIVersion + "/storageclass"
)

func IsValidProtocol(p Protocol) bool {
Expand Down
28 changes: 19 additions & 9 deletions core/orchestrator_core.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,6 @@ func (o *tridentOrchestrator) Bootstrap() error {
"store! Bootstrap might have failed, persistent store might "+
"be down, or persistent store may not have any backend, "+
"volume, or storage class state: %s", err.Error())
log.Warnf(errMsg)
return fmt.Errorf(errMsg)
}
o.bootstrapped = true
Expand Down Expand Up @@ -207,10 +206,10 @@ func (o *tridentOrchestrator) bootstrap() error {

func (o *tridentOrchestrator) rollBackTransaction(v *persistent_store.VolumeTransaction) error {
log.WithFields(log.Fields{
"volume": v.Config.Name,
"size": v.Config.Size,
"storage_class": v.Config.StorageClass,
"op": v.Op,
"volume": v.Config.Name,
"size": v.Config.Size,
"storageClass": v.Config.StorageClass,
"op": v.Op,
}).Info("Processed volume transaction log.")
switch v.Op {
case persistent_store.AddVolume:
Expand Down Expand Up @@ -602,6 +601,7 @@ func (o *tridentOrchestrator) AddVolume(volumeConfig *storage.VolumeConfig) (
log.WithFields(log.Fields{
"volume": volumeConfig.Name,
}).Debugf("Looking through %d backends", len(pools))
errorMessages := make([]string, 0)
for _, num := range rand.Perm(len(pools)) {
backend = pools[num].Backend
if vol, err = backend.AddVolume(
Expand All @@ -624,14 +624,24 @@ func (o *tridentOrchestrator) AddVolume(volumeConfig *storage.VolumeConfig) (
"volume": volumeConfig.Name,
"error": err,
}).Warn("Failed to create the volume on this backend!")
errorMessages = append(errorMessages,
fmt.Sprintf("[Failed to create volume %s "+
"on storage pool %s from backend %s: %s]",
volumeConfig.Name, pools[num].Name, backend.Name,
err.Error()))
}
}

externalVol = nil
err = fmt.Errorf("No suitable %s backend with \"%s\" "+
"storage class and %s of free space was found! Find available backends"+
" under %s.", volumeConfig.Protocol,
volumeConfig.StorageClass, volumeConfig.Size, config.BackendURL)
if len(errorMessages) == 0 {
err = fmt.Errorf("No suitable %s backend with \"%s\" "+
"storage class and %s of free space was found! Find available backends"+
" under %s.", volumeConfig.Protocol,
volumeConfig.StorageClass, volumeConfig.Size, config.BackendURL)
} else {
err = fmt.Errorf("Encountered error(s) in creating the volume: %s",
strings.Join(errorMessages, ", "))
}
return nil, err
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (

const (
KubernetesSyncPeriod = 60 * time.Second

// Kubernetes-defined annotations
// (Based on kubernetes/pkg/controller/volume/persistentvolume/controller.go)
AnnClass = "volume.beta.kubernetes.io/storage-class"
Expand All @@ -27,4 +28,12 @@ const (
AnnVendor = AnnPrefix + "/vendor"
AnnBackendID = AnnPrefix + "/backendID"
AnnExportPolicy = AnnPrefix + "/exportPolicy"

// Minimum and maximum supported Kubernetes versions
KubernetesVersionMin = "1.4"
KubernetesVersionMax = "1.6"

//Minimum and maximum supported OpenShift versions
OpenShiftVersionMin = "3.4"
OpenShiftVersionMax = "3.6"
)
90 changes: 70 additions & 20 deletions frontend/kubernetes/plugin.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"strings"

log "github.com/Sirupsen/logrus"
version "github.com/hashicorp/go-version"
dvp "github.com/netapp/netappdvp/storage_drivers"
"k8s.io/client-go/kubernetes"
core_v1 "k8s.io/client-go/kubernetes/typed/core/v1"
Expand All @@ -16,32 +17,56 @@ import (
k8s_storage "k8s.io/client-go/pkg/apis/storage/v1beta1"
"k8s.io/client-go/pkg/conversion"
"k8s.io/client-go/pkg/runtime"
k8s_version "k8s.io/client-go/pkg/version"
"k8s.io/client-go/pkg/watch"
"k8s.io/client-go/rest"
"k8s.io/client-go/tools/cache"
"k8s.io/client-go/tools/clientcmd"
"k8s.io/client-go/tools/record"

"github.com/netapp/trident/config"
"github.com/netapp/trident/core"
"github.com/netapp/trident/storage"
"github.com/netapp/trident/storage_attribute"
"github.com/netapp/trident/storage_class"
)

func VersionSupported(versionInfo *k8s_version.Info) (bool, error) {
v, err := version.NewVersion(versionInfo.Major + "." + versionInfo.Minor)
if err != nil {
return false, err
}
kubeConstraints, err := version.NewConstraint(fmt.Sprintf(">= %s, <= %s",
KubernetesVersionMin, KubernetesVersionMax))
if err != nil {
return false, err
}
openshiftConstraints, err := version.NewConstraint(
fmt.Sprintf(">= %s, <= %s", OpenShiftVersionMin, OpenShiftVersionMax))
if err != nil {
return false, err
}
if kubeConstraints.Check(v) || openshiftConstraints.Check(v) {
return true, nil
}
return false, nil
}

type KubernetesPlugin struct {
orchestrator core.Orchestrator
kubeClient kubernetes.Interface
eventRecorder record.EventRecorder
pendingClaimMatchMap map[string]*v1.PersistentVolume
claimController *cache.Controller
claimControllerStopChan chan struct{}
claimSource cache.ListerWatcher
volumeController *cache.Controller
volumeControllerStopChan chan struct{}
volumeSource cache.ListerWatcher
classController *cache.Controller
classControllerStopChan chan struct{}
classSource cache.ListerWatcher
orchestrator core.Orchestrator
kubeClient kubernetes.Interface
eventRecorder record.EventRecorder
pendingClaimMatchMap map[string]*v1.PersistentVolume
claimController *cache.Controller
claimControllerStopChan chan struct{}
claimSource cache.ListerWatcher
volumeController *cache.Controller
volumeControllerStopChan chan struct{}
volumeSource cache.ListerWatcher
classController *cache.Controller
classControllerStopChan chan struct{}
classSource cache.ListerWatcher
containerOrchestratorVersion *k8s_version.Info
}

func NewPlugin(
Expand All @@ -68,7 +93,30 @@ func newForConfig(
if err != nil {
return nil, err
}
return newKubernetesPlugin(kubeClient, o), nil
versionInfo, err := kubeClient.Discovery().ServerVersion()
if err != nil {
return nil,
fmt.Errorf("Kubernetes frontend couldn't retrieve API server's "+
"version: %v", err)
}
if supported, err := VersionSupported(versionInfo); err != nil {
return nil, fmt.Errorf("Kubernetes frontend encountered error "+
"in checking the version of container orchestrator: %s", err)
} else if !supported {
log.Warnf("%s v%s may not support "+
"container orchestrator version %s.%s! "+
"Supported versions for Kubernetes are %s-%s "+
"and for OpenShift are %s-%s.",
config.OrchestratorName, config.OrchestratorVersion,
versionInfo.Major, versionInfo.Minor,
KubernetesVersionMin, KubernetesVersionMax,
OpenShiftVersionMin, OpenShiftVersionMax)
}
log.WithFields(log.Fields{
"version": versionInfo.Major + "." + versionInfo.Minor,
}).Info("Kubernetes frontend determined the container orchestrator ",
"version.")
return newKubernetesPlugin(kubeClient, o, versionInfo), nil
}

func getUniqueClaimName(claim *v1.PersistentVolumeClaim) string {
Expand All @@ -84,14 +132,16 @@ func getUniqueClaimName(claim *v1.PersistentVolumeClaim) string {
func newKubernetesPlugin(
kubeClient kubernetes.Interface,
orchestrator core.Orchestrator,
containerOrchestratorVersion *k8s_version.Info,
) *KubernetesPlugin {
ret := &KubernetesPlugin{
orchestrator: orchestrator,
kubeClient: kubeClient,
claimControllerStopChan: make(chan struct{}),
volumeControllerStopChan: make(chan struct{}),
classControllerStopChan: make(chan struct{}),
pendingClaimMatchMap: make(map[string]*v1.PersistentVolume),
orchestrator: orchestrator,
kubeClient: kubeClient,
claimControllerStopChan: make(chan struct{}),
volumeControllerStopChan: make(chan struct{}),
classControllerStopChan: make(chan struct{}),
pendingClaimMatchMap: make(map[string]*v1.PersistentVolume),
containerOrchestratorVersion: containerOrchestratorVersion,
}
broadcaster := record.NewBroadcaster()
broadcaster.StartRecordingToSink(
Expand Down
Loading

0 comments on commit c5eae67

Please sign in to comment.