Fresh dep ensure

This commit is contained in:
Mike Cronce
2018-11-26 13:23:56 -05:00
parent 93cb8a04d7
commit 407478ab9a
9016 changed files with 551394 additions and 279685 deletions

View File

@ -69,8 +69,6 @@ cscope.*
# Godeps or dep workspace
/Godeps/_workspace
vendor
vendor.*
/bazel-*
*.pyc

View File

@ -5,18 +5,14 @@ services:
sudo: true
go: 1.10.3
go_import_path: github.com/kubernetes-csi/drivers
install:
- go get -u github.com/golang/dep/cmd/dep
- dep ensure -vendor-only
- make hostpath
script:
- go fmt $(go list ./... | grep -v vendor) | wc -l | grep 0
- go vet $(go list ./... | grep -v vendor)
- go test $(go list ./... | grep -v vendor)
- make hostpath
- ./hack/e2e-hostpath.sh
after_success:
- if [ "${TRAVIS_BRANCH}" == "master" ] && [ "${TRAVIS_PULL_REQUEST}" == "false" ]; then
- if [ "${TRAVIS_PULL_REQUEST}" == "false" ]; then
docker login -u "${DOCKER_USERNAME}" -p "${DOCKER_PASSWORD}" quay.io;
make hostpath-container;
docker push quay.io/k8scsi/hostpathplugin:canary;
make push;
fi

View File

@ -0,0 +1,25 @@
# Contributing Guidelines
Welcome to Kubernetes. We are excited about the prospect of you joining our [community](https://github.com/kubernetes/community)! The Kubernetes community abides by the CNCF [code of conduct](code-of-conduct.md). Here is an excerpt:
_As contributors and maintainers of this project, and in the interest of fostering an open and welcoming community, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities._
## Getting Started
## Adding new sample drivers
Please, DO NOT submit PRs to add new drivers here unless they are just examples. Real CSI drivers are to be housed on their own repo separate from this one. You are then welcomed to send a PR to https://github.com/kubernetes-csi/docs to add the [Driver](https://github.com/kubernetes-csi/docs/wiki/Drivers) page.
We have full documentation on how to get started contributing here:
- [Contributor License Agreement](https://git.k8s.io/community/CLA.md) Kubernetes projects require that you sign a Contributor License Agreement (CLA) before we can accept your pull requests
- [Kubernetes Contributor Guide](http://git.k8s.io/community/contributors/guide) - Main contributor documentation, or you can just jump directly to the [contributing section](http://git.k8s.io/community/contributors/guide#contributing)
- [Contributor Cheat Sheet](https://git.k8s.io/community/contributors/guide/contributor-cheatsheet.md) - Common resources for existing developers
## Mentorship
- [Mentoring Initiatives](https://git.k8s.io/community/mentoring) - We have a diverse set of mentorship programs available that are always looking for volunteers!
## Contact Information
- [Slack channel](https://kubernetes.slack.com/messages/sig-storage)
- [Mailing list](https://groups.google.com/forum/#!forum/kubernetes-sig-storage)

View File

@ -3,282 +3,341 @@
[[projects]]
branch = "master"
digest = "1:c0bec5f9b98d0bc872ff5e834fac186b807b656683bd29cb82fb207a1513fabb"
name = "github.com/beorn7/perks"
packages = ["quantile"]
revision = "4c0e84591b9aa9e6dcfdf3e020114cd81f89d5f9"
pruneopts = ""
revision = "3a771d992973f24aa725d07868b467d1ddfceafb"
[[projects]]
digest = "1:93147eb1d6f08d39f2c0efe3d29ee043bda72be7a8b3b367eb08c72c18524638"
name = "github.com/container-storage-interface/spec"
packages = ["lib/go/csi/v0"]
revision = "2178fdeea87f1150a17a63252eee28d4d8141f72"
version = "v0.3.0"
packages = ["lib/go/csi"]
pruneopts = ""
revision = "ed0bb0e1557548aa028307f48728767cfe8f6345"
version = "v1.0.0"
[[projects]]
digest = "1:0deddd908b6b4b768cfc272c16ee61e7088a60f7fe2f06c547bd3d8e1f8b8e77"
name = "github.com/davecgh/go-spew"
packages = ["spew"]
revision = "346938d642f2ec3594ed81d874461961cd0faa76"
version = "v1.1.0"
pruneopts = ""
revision = "8991bc29aa16c548c550c7ff78260e27b9ab7c73"
version = "v1.1.1"
[[projects]]
digest = "1:2c87cf00343faf42f84cbda2e475281542497a250a85c5cfa50747f55028e2d8"
name = "github.com/docker/distribution"
packages = [
"digestset",
"reference"
"reference",
]
pruneopts = ""
revision = "5db89f0ca68677abc5eefce8f2a0a772c98ba52d"
[[projects]]
name = "github.com/ghodss/yaml"
packages = ["."]
revision = "0ca9ea5df5451ffdf184b4428c902747c2c11cd7"
version = "v1.0.0"
[[projects]]
digest = "1:6e73003ecd35f4487a5e88270d3ca0a81bc80dc88053ac7e4dcfec5fba30d918"
name = "github.com/gogo/protobuf"
packages = [
"proto",
"sortkeys"
"sortkeys",
]
revision = "1adfc126b41513cc696b209667c8656ea7aac67c"
version = "v1.0.0"
pruneopts = ""
revision = "636bf0302bc95575d69441b25a2603156ffdddf1"
version = "v1.1.1"
[[projects]]
branch = "master"
digest = "1:107b233e45174dbab5b1324201d092ea9448e58243ab9f039e4c0f332e121e3a"
name = "github.com/golang/glog"
packages = ["."]
pruneopts = ""
revision = "23def4e6c14b4da8ac2ed8007337bc5eb5007998"
[[projects]]
branch = "master"
digest = "1:aa2251148505e561bfa8cd6b69a319b37761da57b0b25529c4af08389559e3b9"
name = "github.com/golang/groupcache"
packages = ["lru"]
revision = "66deaeb636dff1ac7d938ce666d090556056a4b0"
pruneopts = ""
revision = "c65c006176ff7ff98bb916961c7abbc6b0afc0aa"
[[projects]]
digest = "1:3dd078fda7500c341bc26cfbc6c6a34614f295a2457149fc1045cab767cbcf18"
name = "github.com/golang/protobuf"
packages = [
"proto",
"protoc-gen-go/descriptor",
"ptypes",
"ptypes/any",
"ptypes/duration",
"ptypes/timestamp",
"ptypes/wrappers"
"ptypes/wrappers",
]
revision = "b4deda0973fb4c70b50d226b1af49f3da59f5265"
version = "v1.1.0"
pruneopts = ""
revision = "aa810b61a9c79d51363740d207bb46cf8e620ed5"
version = "v1.2.0"
[[projects]]
branch = "master"
digest = "1:1e5b1e14524ed08301977b7b8e10c719ed853cbf3f24ecb66fae783a46f207a6"
name = "github.com/google/btree"
packages = ["."]
revision = "e89373fe6b4a7413d7acd6da1725b83ef713e6e4"
pruneopts = ""
revision = "4030bb1f1f0c35b30ca7009e9ebd06849dd45306"
[[projects]]
branch = "master"
digest = "1:754f77e9c839b24778a4b64422236d38515301d2baeb63113aa3edc42e6af692"
name = "github.com/google/gofuzz"
packages = ["."]
pruneopts = ""
revision = "24818f796faf91cd76ec7bddd72458fbced7a6c1"
[[projects]]
digest = "1:5247b135b5492aa232a731acdcb52b08f32b874cb398f21ab460396eadbe866b"
name = "github.com/google/uuid"
packages = ["."]
pruneopts = ""
revision = "d460ce9f8df2e77fb1ba55ca87fafed96c607494"
version = "v1.0.0"
[[projects]]
digest = "1:16b2837c8b3cf045fa2cdc82af0cf78b19582701394484ae76b2c3bc3c99ad73"
name = "github.com/googleapis/gnostic"
packages = [
"OpenAPIv2",
"compiler",
"extensions"
"extensions",
]
revision = "ee43cbb60db7bd22502942cccbc39059117352ab"
version = "v0.1.0"
[[projects]]
branch = "master"
name = "github.com/gophercloud/gophercloud"
packages = [
".",
"openstack",
"openstack/blockstorage/v3/volumes",
"openstack/compute/v2/extensions/volumeattach",
"openstack/identity/v2/tenants",
"openstack/identity/v2/tokens",
"openstack/identity/v3/tokens",
"openstack/utils",
"pagination"
]
revision = "afbf0422412f5dc726fa12be280fa0c3cb31fcbd"
pruneopts = ""
revision = "7c663266750e7d82587642f65e60bc4083f1f84e"
version = "v0.2.0"
[[projects]]
branch = "master"
digest = "1:5e345eb75d8bfb2b91cfbfe02a82a79c0b2ea55cf06c5a4d180a9321f36973b4"
name = "github.com/gregjones/httpcache"
packages = [
".",
"diskcache"
"diskcache",
]
revision = "2bcd89a1743fd4b373f7370ce8ddc14dfbd18229"
pruneopts = ""
revision = "c63ab54fda8f77302f8d414e19933f2b6026a089"
[[projects]]
branch = "master"
digest = "1:3313a63031ae281e5f6fd7b0bbca733dfa04d2429df86519e3b4d4c016ccb836"
name = "github.com/hashicorp/golang-lru"
packages = [
".",
"simplelru"
"simplelru",
]
revision = "0fb14efe8c47ae851c0034ed7a448854d3d34cf3"
pruneopts = ""
revision = "20f1fb78b0740ba8c3cb143a61e86ba5c8669768"
version = "v0.5.0"
[[projects]]
digest = "1:870d441fe217b8e689d7949fef6e43efbc787e50f200cb1e70dbca9204a1d6be"
name = "github.com/inconshreveable/mousetrap"
packages = ["."]
pruneopts = ""
revision = "76626ae9c91c4f2a10f34cad8ce83ea42c93bb75"
version = "v1.0"
[[projects]]
digest = "1:b79fc583e4dc7055ed86742e22164ac41bf8c0940722dbcb600f1a3ace1a8cb5"
name = "github.com/json-iterator/go"
packages = ["."]
revision = "3353055b2a1a5ae1b6a8dfde887a524e7088f3a2"
version = "1.1.2"
pruneopts = ""
revision = "1624edc4454b8682399def8740d46db5e4362ba4"
version = "v1.1.5"
[[projects]]
name = "github.com/juju/ratelimit"
digest = "1:63722a4b1e1717be7b98fc686e0b30d5e7f734b9e93d7dee86293b6deab7ea28"
name = "github.com/matttproud/golang_protobuf_extensions"
packages = ["pbutil"]
pruneopts = ""
revision = "c12348ce28de40eed0136aa2b644d0ee0650e56c"
version = "v1.0.1"
[[projects]]
digest = "1:0c0ff2a89c1bb0d01887e1dac043ad7efbf3ec77482ef058ac423d13497e16fd"
name = "github.com/modern-go/concurrent"
packages = ["."]
revision = "59fac5042749a5afb9af70e813da1dd5474f0167"
pruneopts = ""
revision = "bacd9c7ef1dd9b15be4a9909b8ac7a4e313eec94"
version = "1.0.3"
[[projects]]
digest = "1:e32bdbdb7c377a07a9a46378290059822efdce5c8d96fe71940d87cb4f918855"
name = "github.com/modern-go/reflect2"
packages = ["."]
pruneopts = ""
revision = "4b7aa43c6742a2c18fdef89dd197aaae7dac7ccd"
version = "1.0.1"
[[projects]]
name = "github.com/matttproud/golang_protobuf_extensions"
packages = ["pbutil"]
revision = "3247c84500bff8d9fb6d579d800f20b3e091582c"
version = "v1.0.0"
[[projects]]
name = "github.com/modern-go/concurrent"
packages = ["."]
revision = "e0a39a4cb4216ea8db28e22a69f4ec25610d513a"
version = "1.0.0"
[[projects]]
name = "github.com/modern-go/reflect2"
packages = ["."]
revision = "1df9eeb2bb81f327b96228865c5687bc2194af3f"
version = "1.0.0"
[[projects]]
digest = "1:5d9b668b0b4581a978f07e7d2e3314af18eb27b3fb5d19b70185b7c575723d11"
name = "github.com/opencontainers/go-digest"
packages = ["."]
pruneopts = ""
revision = "279bed98673dd5bef374d3b6e4b09e2af76183bf"
version = "v1.0.0-rc1"
[[projects]]
digest = "1:a5484d4fa43127138ae6e7b2299a6a52ae006c7f803d98d717f60abf3e97192e"
name = "github.com/pborman/uuid"
packages = ["."]
revision = "e790cca94e6cc75c7064b1332e63811d4aae1a53"
version = "v1.1"
pruneopts = ""
revision = "adf5a7427709b9deb95d29d3fa8a2bf9cfd388f1"
version = "v1.2"
[[projects]]
branch = "master"
digest = "1:c24598ffeadd2762552269271b3b1510df2d83ee6696c1e543a0ff653af494bc"
name = "github.com/petar/GoLLRB"
packages = ["llrb"]
pruneopts = ""
revision = "53be0d36a84c2a886ca057d34b6aa4468df9ccb4"
[[projects]]
digest = "1:b46305723171710475f2dd37547edd57b67b9de9f2a6267cafdd98331fd6897f"
name = "github.com/peterbourgon/diskv"
packages = ["."]
pruneopts = ""
revision = "5f041e8faa004a95c88a202771f4cc3e991971e6"
version = "v2.0.1"
[[projects]]
digest = "1:256484dbbcd271f9ecebc6795b2df8cad4c458dd0f5fd82a8c2fa0c29f233411"
name = "github.com/pmezard/go-difflib"
packages = ["difflib"]
pruneopts = ""
revision = "792786c7400a136282c1664665ae0a8db921c6c2"
version = "v1.0.0"
[[projects]]
digest = "1:8b2082f564fe20dbb43a621ee0d57ae2777656ab14111d100d3d92d1b5b958b9"
name = "github.com/prometheus/client_golang"
packages = ["prometheus"]
revision = "c5b7fccd204277076155f10851dad72b76a49317"
version = "v0.8.0"
packages = [
"prometheus",
"prometheus/internal",
]
pruneopts = ""
revision = "abad2d1bd44235a26707c172eab6bca5bf2dbad3"
version = "v0.9.1"
[[projects]]
branch = "master"
digest = "1:185cf55b1f44a1bf243558901c3f06efa5c64ba62cfdcbb1bf7bbe8c3fb68561"
name = "github.com/prometheus/client_model"
packages = ["go"]
revision = "99fa1f4be8e564e8a6b613da7fa6f46c9edafc6c"
pruneopts = ""
revision = "5c3871d89910bfb32f5fcab2aa4b9ec68e65a99f"
[[projects]]
branch = "master"
digest = "1:d522feb599bd02a4b76d3ad20b91668c87028a6b5fd19a1bed994e26f6cd3c6d"
name = "github.com/prometheus/common"
packages = [
"expfmt",
"internal/bitbucket.org/ww/goautoneg",
"model"
"model",
]
revision = "6fb6fce6f8b75884b92e1889c150403fc0872c5e"
pruneopts = ""
revision = "41aa239b4cce3c56ab88fc366ae8b0a6423fa239"
[[projects]]
branch = "master"
digest = "1:1f62ed2c173c42c1edad2e94e127318ea11b0d28c62590c82a8d2d3cde189afe"
name = "github.com/prometheus/procfs"
packages = [
".",
"internal/util",
"nfs",
"xfs"
"xfs",
]
revision = "d274e363d5759d1c916232217be421f1cc89c5fe"
pruneopts = ""
revision = "185b4288413d2a0dd0806f78c90dde719829e5ae"
[[projects]]
digest = "1:a1403cc8a94b8d7956ee5e9694badef0e7b051af289caad1cf668331e3ffa4f6"
name = "github.com/spf13/cobra"
packages = ["."]
revision = "7b2c5ac9fc04fc5efafb60700713d4fa609b777b"
version = "v0.0.1"
pruneopts = ""
revision = "ef82de70bb3f60c65fb8eebacbb2d122ef517385"
version = "v0.0.3"
[[projects]]
digest = "1:cbaf13cdbfef0e4734ed8a7504f57fe893d471d62a35b982bf6fb3f036449a66"
name = "github.com/spf13/pflag"
packages = ["."]
revision = "e57e3eeb33f795204c1ca35f56c44f83227c6e66"
version = "v1.0.0"
[[projects]]
name = "github.com/stretchr/objx"
packages = ["."]
revision = "facf9a85c22f48d2f52f2380e4efce1768749a89"
version = "v0.1"
pruneopts = ""
revision = "298182f68c66c05229eb03ac171abe6e309ee79a"
version = "v1.0.3"
[[projects]]
digest = "1:c587772fb8ad29ad4db67575dad25ba17a51f072ff18a22b4f0257a4d9c24f75"
name = "github.com/stretchr/testify"
packages = [
"assert",
"mock"
]
revision = "12b6f73e6084dad08a7c6e575284b177ecafbc71"
version = "v1.2.1"
packages = ["assert"]
pruneopts = ""
revision = "f35b8ab0b5a2cef36673838d662e249dd9c94686"
version = "v1.2.2"
[[projects]]
branch = "master"
digest = "1:f7be435e0ca22e2cd62b2d2542081a231685837170a87a3662abb7cdf9f3f1cd"
name = "golang.org/x/crypto"
packages = [
"ed25519",
"ed25519/internal/edwards25519"
"ed25519/internal/edwards25519",
"pbkdf2",
"ssh/terminal",
]
revision = "91a49db82a88618983a78a06c1cbd4e00ab749ab"
pruneopts = ""
revision = "3d3f9f413869b949e48070b5bc593aa22cc2b8f2"
[[projects]]
branch = "master"
digest = "1:fbc2896199a45d32325e24ceb56624c7db49f9cfb068f739ee53339a8fb183b3"
name = "golang.org/x/net"
packages = [
"context",
"context/ctxhttp",
"http/httpguts",
"http2",
"http2/hpack",
"idna",
"internal/timeseries",
"lex/httplex",
"trace"
"trace",
]
revision = "cbe0f9307d0156177f9dd5dc85da1a31abc5f2fb"
pruneopts = ""
revision = "88d92db4c548972d942ac2a3531a8a9a34c82ca6"
[[projects]]
branch = "master"
name = "golang.org/x/sys"
packages = ["unix"]
revision = "f6cff0780e542efa0c8e864dc8fa522808f6a598"
digest = "1:51d339a1d79f5c617fba14414aefb7dfd184b8ba0ddbb9f95251430b67c8aab8"
name = "golang.org/x/oauth2"
packages = [
".",
"internal",
]
pruneopts = ""
revision = "f42d05182288abf10faef86d16c0d07b8d40ea2d"
[[projects]]
branch = "master"
digest = "1:3f5c191d90f1cf365ff1f88e4b08eb766ee6ade1cb2e4efd7c316cf7e015ac17"
name = "golang.org/x/sys"
packages = [
"unix",
"windows",
]
pruneopts = ""
revision = "66b7b1311ac80bbafcd2daeef9a5e6e2cd1e2399"
[[projects]]
digest = "1:5acd3512b047305d49e8763eef7ba423901e85d5dd2fd1e71778a0ea8de10bd4"
name = "golang.org/x/text"
packages = [
"collate",
@ -294,18 +353,46 @@
"unicode/bidi",
"unicode/cldr",
"unicode/norm",
"unicode/rangetable"
"unicode/rangetable",
]
pruneopts = ""
revision = "f21a4dfb5e38f5895301dc265a8def02365cc3d0"
version = "v0.3.0"
[[projects]]
branch = "master"
name = "google.golang.org/genproto"
packages = ["googleapis/rpc/status"]
revision = "2d9486acae19cf9bd0c093d7dc236a323726a9e4"
digest = "1:14cb1d4240bcbbf1386ae763957e04e2765ec4e4ce7bb2769d05fa6faccd774e"
name = "golang.org/x/time"
packages = ["rate"]
pruneopts = ""
revision = "85acf8d2951cb2a3bde7632f9ff273ef0379bcbd"
[[projects]]
digest = "1:77d3cff3a451d50be4b52db9c7766c0d8570ba47593f0c9dc72173adb208e788"
name = "google.golang.org/appengine"
packages = [
"internal",
"internal/base",
"internal/datastore",
"internal/log",
"internal/remote_api",
"internal/urlfetch",
"urlfetch",
]
pruneopts = ""
revision = "4a4468ece617fc8205e99368fa2200e9d1fad421"
version = "v1.3.0"
[[projects]]
branch = "master"
digest = "1:212d4045ef941b209a154001718705dc723bd77e0200fcea36d15ec87ed49dec"
name = "google.golang.org/genproto"
packages = ["googleapis/rpc/status"]
pruneopts = ""
revision = "b5d43981345bdb2c233eb4bf3277847b48c6fdc6"
[[projects]]
digest = "1:1293087271e314cfa2b3decededba2ecba0ff327e7b7809e00f73f616449191c"
name = "google.golang.org/grpc"
packages = [
".",
@ -317,9 +404,13 @@
"credentials",
"encoding",
"encoding/proto",
"grpclb/grpc_lb_v1/messages",
"grpclog",
"internal",
"internal/backoff",
"internal/channelz",
"internal/envconfig",
"internal/grpcrand",
"internal/transport",
"keepalive",
"metadata",
"naming",
@ -330,52 +421,42 @@
"stats",
"status",
"tap",
"transport"
]
revision = "8e4536a86ab602859c20df5ebfd0bd4228d08655"
version = "v1.10.0"
[[projects]]
name = "gopkg.in/gcfg.v1"
packages = [
".",
"scanner",
"token",
"types"
]
revision = "298b7a6a3838f79debfaee8bd3bfb2b8d779e756"
version = "v1.2.1"
pruneopts = ""
revision = "2e463a05d100327ca47ac218281906921038fd95"
version = "v1.16.0"
[[projects]]
digest = "1:75fb3fcfc73a8c723efde7777b40e8e8ff9babf30d8c56160d01beffea8a95a6"
name = "gopkg.in/inf.v0"
packages = ["."]
revision = "3887ee99ecf07df5b447e9b00d9c0b2adaa9f3e4"
version = "v0.9.0"
pruneopts = ""
revision = "d2d2541c53f18d2a059457998ce2876cc8e67cbf"
version = "v0.9.1"
[[projects]]
digest = "1:ddc5fa8f9159bea7d1ce58143e6d8fd8054018f7bc3709940aa7f7bc92855ed9"
name = "gopkg.in/square/go-jose.v2"
packages = [
".",
"cipher",
"json",
"jwt"
"jwt",
]
revision = "6ee92191fea850cdcab9a18867abf5f521cdbadb"
version = "v2.1.4"
[[projects]]
name = "gopkg.in/warnings.v0"
packages = ["."]
revision = "ec4a0fea49c7b46c2aeb0b51aac55779c607e52b"
version = "v0.1.2"
pruneopts = ""
revision = "ef984e69dd356202fd4e4910d4d9c24468bdf0b8"
version = "v2.1.9"
[[projects]]
digest = "1:f0620375dd1f6251d9973b5f2596228cc8042e887cd7f827e4220bc1ce8c30e2"
name = "gopkg.in/yaml.v2"
packages = ["."]
revision = "7f97868eec74b32b0982dd158a51a446d1da7eb5"
version = "v2.1.1"
pruneopts = ""
revision = "5420a8b6744d3b0345ab293f6fcba19c978f1183"
version = "v2.2.1"
[[projects]]
digest = "1:5f076f6f9c3ac4f2b99d79dc7974eabd3f51be35254aa0d8c4cf920fdb9c7ff8"
name = "k8s.io/api"
packages = [
"admissionregistration/v1alpha1",
@ -389,10 +470,12 @@
"authorization/v1beta1",
"autoscaling/v1",
"autoscaling/v2beta1",
"autoscaling/v2beta2",
"batch/v1",
"batch/v1beta1",
"batch/v2alpha1",
"certificates/v1beta1",
"coordination/v1beta1",
"core/v1",
"events/v1beta1",
"extensions/v1beta1",
@ -402,21 +485,27 @@
"rbac/v1alpha1",
"rbac/v1beta1",
"scheduling/v1alpha1",
"scheduling/v1beta1",
"settings/v1alpha1",
"storage/v1",
"storage/v1alpha1",
"storage/v1beta1"
"storage/v1beta1",
]
revision = "7aac3e00a1b32fa476b83078cebaaca606b2fb48"
version = "kubernetes-1.10.0-beta.1"
pruneopts = ""
revision = "fd83cbc87e7632ccd8bbab63d2b673d4e0c631cc"
version = "kubernetes-1.12.0"
[[projects]]
branch = "master"
digest = "1:570ce571245b39b4fc8a1a5552079e00b1be3aa2c3755b7be76d3eb7d7b8c0ad"
name = "k8s.io/apiextensions-apiserver"
packages = ["pkg/features"]
revision = "cfb732a3dd26c3e6349d0954e1209c9d5c093d1f"
pruneopts = ""
revision = "2c43ee60e25b6e421b37db431bad60e7416a6fd4"
[[projects]]
branch = "master"
digest = "1:cebe5f04ee0890c78c57a957e9d69892cebe60ccda4d1001d9f759a70b1e1bd1"
name = "k8s.io/apimachinery"
packages = [
"pkg/api/equality",
@ -424,9 +513,6 @@
"pkg/api/meta",
"pkg/api/resource",
"pkg/api/validation",
"pkg/apimachinery",
"pkg/apimachinery/announced",
"pkg/apimachinery/registered",
"pkg/apis/meta/internalversion",
"pkg/apis/meta/v1",
"pkg/apis/meta/v1/unstructured",
@ -454,7 +540,9 @@
"pkg/util/intstr",
"pkg/util/json",
"pkg/util/mergepatch",
"pkg/util/naming",
"pkg/util/net",
"pkg/util/rand",
"pkg/util/runtime",
"pkg/util/sets",
"pkg/util/strategicpatch",
@ -465,24 +553,27 @@
"pkg/version",
"pkg/watch",
"third_party/forked/golang/json",
"third_party/forked/golang/reflect"
"third_party/forked/golang/reflect",
]
revision = "302974c03f7e50f16561ba237db776ab93594ef6"
version = "kubernetes-1.10.0-beta.1"
pruneopts = ""
revision = "2a7c9300402896b3c073f2f47df85527c94f83a0"
[[projects]]
branch = "master"
digest = "1:f129d76e4103ddcd176f1a07051eb1826922e54f489032bef8283f7f9c32c4f0"
name = "k8s.io/apiserver"
packages = [
"pkg/authentication/authenticator",
"pkg/authentication/serviceaccount",
"pkg/authentication/user",
"pkg/features",
"pkg/util/feature"
"pkg/util/feature",
]
revision = "74a8a89814a24637e718e271b747a717c24da88f"
pruneopts = ""
revision = "e85ad7b666fef0476185731329f4cff1536efff8"
version = "kubernetes-1.12.0"
[[projects]]
digest = "1:5d4153d12c3aed2c90a94262520d2498d5afa4d692554af55e65a7c5af0bc399"
name = "k8s.io/client-go"
packages = [
"discovery",
@ -497,12 +588,15 @@
"informers/autoscaling",
"informers/autoscaling/v1",
"informers/autoscaling/v2beta1",
"informers/autoscaling/v2beta2",
"informers/batch",
"informers/batch/v1",
"informers/batch/v1beta1",
"informers/batch/v2alpha1",
"informers/certificates",
"informers/certificates/v1beta1",
"informers/coordination",
"informers/coordination/v1beta1",
"informers/core",
"informers/core/v1",
"informers/events",
@ -520,6 +614,7 @@
"informers/rbac/v1beta1",
"informers/scheduling",
"informers/scheduling/v1alpha1",
"informers/scheduling/v1beta1",
"informers/settings",
"informers/settings/v1alpha1",
"informers/storage",
@ -539,10 +634,12 @@
"kubernetes/typed/authorization/v1beta1",
"kubernetes/typed/autoscaling/v1",
"kubernetes/typed/autoscaling/v2beta1",
"kubernetes/typed/autoscaling/v2beta2",
"kubernetes/typed/batch/v1",
"kubernetes/typed/batch/v1beta1",
"kubernetes/typed/batch/v2alpha1",
"kubernetes/typed/certificates/v1beta1",
"kubernetes/typed/coordination/v1beta1",
"kubernetes/typed/core/v1",
"kubernetes/typed/events/v1beta1",
"kubernetes/typed/extensions/v1beta1",
@ -552,6 +649,7 @@
"kubernetes/typed/rbac/v1alpha1",
"kubernetes/typed/rbac/v1beta1",
"kubernetes/typed/scheduling/v1alpha1",
"kubernetes/typed/scheduling/v1beta1",
"kubernetes/typed/settings/v1alpha1",
"kubernetes/typed/storage/v1",
"kubernetes/typed/storage/v1alpha1",
@ -563,10 +661,12 @@
"listers/apps/v1beta2",
"listers/autoscaling/v1",
"listers/autoscaling/v2beta1",
"listers/autoscaling/v2beta2",
"listers/batch/v1",
"listers/batch/v1beta1",
"listers/batch/v2alpha1",
"listers/certificates/v1beta1",
"listers/coordination/v1beta1",
"listers/core/v1",
"listers/events/v1beta1",
"listers/extensions/v1beta1",
@ -576,11 +676,16 @@
"listers/rbac/v1alpha1",
"listers/rbac/v1beta1",
"listers/scheduling/v1alpha1",
"listers/scheduling/v1beta1",
"listers/settings/v1alpha1",
"listers/storage/v1",
"listers/storage/v1alpha1",
"listers/storage/v1beta1",
"pkg/apis/clientauthentication",
"pkg/apis/clientauthentication/v1alpha1",
"pkg/apis/clientauthentication/v1beta1",
"pkg/version",
"plugin/pkg/client/auth/exec",
"rest",
"rest/watch",
"tools/cache",
@ -589,23 +694,50 @@
"tools/pager",
"tools/record",
"tools/reference",
"tools/watch",
"transport",
"util/buffer",
"util/cert",
"util/connrotation",
"util/flowcontrol",
"util/integer",
"util/retry"
"util/retry",
]
revision = "78700dec6369ba22221b72770783300f143df150"
version = "v6.0.0"
pruneopts = ""
revision = "1638f8970cefaa404ff3a62950f88b08292b2696"
version = "v9.0.0"
[[projects]]
branch = "master"
name = "k8s.io/kube-openapi"
packages = ["pkg/util/proto"]
revision = "50ae88d24ede7b8bad68e23c805b5d3da5c8abaf"
digest = "1:ae938748bf72ccd682e9009b6a3dcfedb695ace9cca3ef2ea9f8fd31411b3a44"
name = "k8s.io/csi-api"
packages = [
"pkg/apis/csi/v1alpha1",
"pkg/client/clientset/versioned",
"pkg/client/clientset/versioned/scheme",
"pkg/client/clientset/versioned/typed/csi/v1alpha1",
]
pruneopts = ""
revision = "3ace7a84ffef58a17488dcefe2432bbeb74a5c7b"
[[projects]]
digest = "1:4f5eb833037cc0ba0bf8fe9cae6be9df62c19dd1c869415275c708daa8ccfda5"
name = "k8s.io/klog"
packages = ["."]
pruneopts = ""
revision = "a5bc97fbc634d635061f3146511332c7e313a55a"
version = "v0.1.0"
[[projects]]
branch = "master"
digest = "1:d3fdd2e6dafedf0cd13d327cb62c8675d1f309d5587245e3ad35b083589675af"
name = "k8s.io/kube-openapi"
packages = ["pkg/util/proto"]
pruneopts = ""
revision = "c59034cc13d587f5ef4e85ca0ade0c1866ae8e1d"
[[projects]]
digest = "1:6061aa42761235df375f20fa4a1aa6d1845cba3687575f3adb2ef3f3bc540af5"
name = "k8s.io/kubernetes"
packages = [
"pkg/api/legacyscheme",
@ -621,6 +753,8 @@
"pkg/apis/core/validation",
"pkg/apis/extensions",
"pkg/apis/networking",
"pkg/apis/policy",
"pkg/apis/scheduling",
"pkg/capabilities",
"pkg/cloudprovider",
"pkg/controller",
@ -629,7 +763,11 @@
"pkg/kubelet/apis",
"pkg/kubelet/types",
"pkg/master/ports",
"pkg/scheduler/algorithm",
"pkg/scheduler/algorithm/priorities/util",
"pkg/scheduler/api",
"pkg/scheduler/cache",
"pkg/scheduler/util",
"pkg/security/apparmor",
"pkg/serviceaccount",
"pkg/util/file",
@ -637,28 +775,59 @@
"pkg/util/io",
"pkg/util/mount",
"pkg/util/net/sets",
"pkg/util/node",
"pkg/util/nsenter",
"pkg/util/parsers",
"pkg/util/pointer",
"pkg/util/strings",
"pkg/util/taints",
"pkg/volume",
"pkg/volume/util",
"pkg/volume/util/fs",
"pkg/volume/util/recyclerclient",
"pkg/volume/util/types"
"pkg/volume/util/types",
"pkg/volume/util/volumepathhandler",
]
revision = "37555e6d24c2f951c40660ea59a80fa251982005"
version = "v1.10.0-beta.1"
pruneopts = ""
revision = "17c77c7898218073f14c8d573582e8d2313dc740"
version = "v1.12.2"
[[projects]]
branch = "master"
digest = "1:1aa5e3a611782785b985a64a27254bf93e9a23b24a5b9f3c4dfc49fb6e07fa39"
name = "k8s.io/utils"
packages = ["exec"]
revision = "258e2a2fa64568210fbd6267cf1d8fd87c3cb86e"
packages = [
"exec",
"pointer",
]
pruneopts = ""
revision = "1bd4f387aa67de2eec07a362c10bc8bd7fe74237"
[[projects]]
digest = "1:321081b4a44256715f2b68411d8eda9a17f17ebfe6f0cc61d2cc52d11c08acfa"
name = "sigs.k8s.io/yaml"
packages = ["."]
pruneopts = ""
revision = "fd68e9863619f6ec2fdd8625fe1f02e7c877e480"
version = "v1.1.0"
[solve-meta]
analyzer-name = "dep"
analyzer-version = 1
inputs-digest = "8b43ab8306203b049af581d7567bd62d58b438ad31ada07c05ab0398c721a0fd"
input-imports = [
"github.com/container-storage-interface/spec/lib/go/csi",
"github.com/golang/glog",
"github.com/golang/protobuf/ptypes",
"github.com/golang/protobuf/ptypes/timestamp",
"github.com/pborman/uuid",
"github.com/spf13/cobra",
"github.com/stretchr/testify/assert",
"golang.org/x/net/context",
"google.golang.org/grpc",
"google.golang.org/grpc/codes",
"google.golang.org/grpc/status",
"k8s.io/kubernetes/pkg/util/mount",
"k8s.io/kubernetes/pkg/volume/util",
"k8s.io/utils/exec",
]
solver-name = "gps-cdcl"
solver-version = 1

View File

@ -23,7 +23,7 @@
[[constraint]]
name = "github.com/container-storage-interface/spec"
version = "~0.3.0"
version = "1.0.0"
[[constraint]]
branch = "master"
@ -33,10 +33,6 @@
revision = "5db89f0ca68677abc5eefce8f2a0a772c98ba52d"
name = "github.com/docker/distribution"
[[constraint]]
branch = "master"
name = "github.com/gophercloud/gophercloud"
[[constraint]]
name = "github.com/pborman/uuid"
version = "1.1.0"
@ -57,22 +53,26 @@
name = "google.golang.org/grpc"
version = "1.10.0"
[[constraint]]
name = "gopkg.in/gcfg.v1"
version = "1.2.1"
[[constraint]]
version = "kubernetes-1.10.0-beta.1"
name = "k8s.io/apimachinery"
[[constraint]]
name = "k8s.io/kubernetes"
version = "v1.10.0-beta.1"
version = "v1.12.0"
[[override]]
version = "kubernetes-1.10.0-beta.1"
version = "kubernetes-1.12.0"
name = "k8s.io/api"
[[override]]
version = "kubernetes-1.12.0"
name = "k8s.io/apiserver"
[[override]]
name = "github.com/golang/protobuf"
version = "v1.1.0"
[[override]]
name = "github.com/json-iterator/go"
version = "1.1.4"
[[override]]
name = "gopkg.in/square/go-jose.v2"
version = "2.1.7"

View File

@ -16,10 +16,11 @@ REGISTRY_NAME=quay.io/k8scsi
IMAGE_NAME=hostpathplugin
IMAGE_VERSION=canary
IMAGE_TAG=$(REGISTRY_NAME)/$(IMAGE_NAME):$(IMAGE_VERSION)
REV=$(shell git describe --long --tags --dirty)
.PHONY: all flexadapter nfs hostpath iscsi cinder clean hostpath-container
.PHONY: all flexadapter nfs hostpath iscsi clean hostpath-container
all: flexadapter nfs hostpath iscsi cinder
all: flexadapter nfs hostpath iscsi
test:
go test github.com/kubernetes-csi/drivers/pkg/... -cover
@ -32,7 +33,7 @@ nfs:
CGO_ENABLED=0 GOOS=linux go build -a -ldflags '-extldflags "-static"' -o _output/nfsplugin ./app/nfsplugin
hostpath:
if [ ! -d ./vendor ]; then dep ensure -vendor-only; fi
CGO_ENABLED=0 GOOS=linux go build -a -ldflags '-extldflags "-static"' -o _output/hostpathplugin ./app/hostpathplugin
CGO_ENABLED=0 GOOS=linux go build -a -ldflags '-X github.com/kubernetes-csi/drivers/pkg/hostpath.vendorVersion=$(REV) -extldflags "-static"' -o _output/hostpathplugin ./app/hostpathplugin
hostpath-container: hostpath
docker build -t $(IMAGE_TAG) -f ./app/hostpathplugin/Dockerfile .
push: hostpath-container
@ -40,9 +41,6 @@ push: hostpath-container
iscsi:
if [ ! -d ./vendor ]; then dep ensure -vendor-only; fi
CGO_ENABLED=0 GOOS=linux go build -a -ldflags '-extldflags "-static"' -o _output/iscsiplugin ./app/iscsiplugin
cinder:
if [ ! -d ./vendor ]; then dep ensure -vendor-only; fi
CGO_ENABLED=0 GOOS=linux go build -a -ldflags '-extldflags "-static"' -o _output/cinderplugin ./app/cinderplugin
clean:
go clean -r -x
-rm -rf _output

6
vendor/github.com/kubernetes-csi/drivers/OWNERS generated vendored Normal file
View File

@ -0,0 +1,6 @@
approvers:
- saad-ali
- chakri-nelluri
- lpabon
- edisonxiang
- sbezverk

View File

@ -6,5 +6,15 @@ These drivers are provided purely for illustrative purposes, and should not be u
## Other sample drivers
Please read [Drivers](https://kubernetes-csi.github.io/docs/Drivers.html) for more information
## Adding new sample drivers
Please, DO NOT submit PRs to add new drivers here unless they are just examples. Real CSI drivers are to be housed on their own repo separate from this one. You are then welcomed to send a PR to https://github.com/kubernetes-csi/docs to add the [Driver](https://github.com/kubernetes-csi/docs/wiki/Drivers) page.
## Community, discussion, contribution, and support
Learn how to engage with the Kubernetes community on the [community page](http://kubernetes.io/community/).
You can reach the maintainers of this project at:
- [Slack channel](https://kubernetes.slack.com/messages/sig-storage)
- [Mailing list](https://groups.google.com/forum/#!forum/kubernetes-sig-storage)
### Code of conduct
Participation in the Kubernetes community is governed by the [Kubernetes Code of Conduct](code-of-conduct.md).

View File

@ -1,72 +0,0 @@
/*
Copyright 2017 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package main
import (
"flag"
"fmt"
"os"
"github.com/kubernetes-csi/drivers/pkg/cinder"
"github.com/spf13/cobra"
)
var (
endpoint string
nodeID string
cloudconfig string
)
func init() {
flag.Set("logtostderr", "true")
}
func main() {
flag.CommandLine.Parse([]string{})
cmd := &cobra.Command{
Use: "Cinder",
Short: "CSI based Cinder driver",
Run: func(cmd *cobra.Command, args []string) {
handle()
},
}
cmd.Flags().AddGoFlagSet(flag.CommandLine)
cmd.PersistentFlags().StringVar(&nodeID, "nodeid", "", "node id")
cmd.MarkPersistentFlagRequired("nodeid")
cmd.PersistentFlags().StringVar(&endpoint, "endpoint", "", "CSI endpoint")
cmd.MarkPersistentFlagRequired("endpoint")
cmd.PersistentFlags().StringVar(&cloudconfig, "cloud-config", "", "CSI driver cloud config")
cmd.MarkPersistentFlagRequired("cloud-config")
if err := cmd.Execute(); err != nil {
fmt.Fprintf(os.Stderr, "%s", err.Error())
os.Exit(1)
}
os.Exit(0)
}
func handle() {
d := cinder.NewDriver(nodeID, endpoint, cloudconfig)
d.Run()
}

View File

@ -0,0 +1,48 @@
kind: Service
apiVersion: v1
metadata:
name: csi-hostpath-attacher
labels:
app: csi-hostpath-attacher
spec:
selector:
app: csi-hostpath-attacher
ports:
- name: dummy
port: 12345
---
kind: StatefulSet
apiVersion: apps/v1
metadata:
name: csi-hostpath-attacher
spec:
serviceName: "csi-hostpath-attacher"
replicas: 1
selector:
matchLabels:
app: csi-hostpath-attacher
template:
metadata:
labels:
app: csi-hostpath-attacher
spec:
serviceAccountName: csi-attacher
containers:
- name: csi-attacher
image: gcr.io/gke-release/csi-attacher:v1.0.0-gke.0
args:
- --v=5
- --csi-address=$(ADDRESS)
env:
- name: ADDRESS
value: /csi/csi.sock
imagePullPolicy: Always
volumeMounts:
- mountPath: /csi
name: socket-dir
volumes:
- hostPath:
path: /var/lib/kubelet/plugins/csi-hostpath
type: DirectoryOrCreate
name: socket-dir

View File

@ -0,0 +1,49 @@
kind: Service
apiVersion: v1
metadata:
name: csi-hostpath-provisioner
labels:
app: csi-hostpath-provisioner
spec:
selector:
app: csi-hostpath-provisioner
ports:
- name: dummy
port: 12345
---
kind: StatefulSet
apiVersion: apps/v1
metadata:
name: csi-hostpath-provisioner
spec:
serviceName: "csi-hostpath-provisioner"
replicas: 1
selector:
matchLabels:
app: csi-hostpath-provisioner
template:
metadata:
labels:
app: csi-hostpath-provisioner
spec:
serviceAccountName: csi-provisioner
containers:
- name: csi-provisioner
image: gcr.io/gke-release/csi-provisioner:v1.0.0-gke.0
args:
- "--provisioner=csi-hostpath"
- "--csi-address=$(ADDRESS)"
- "--connection-timeout=15s"
env:
- name: ADDRESS
value: /csi/csi.sock
imagePullPolicy: Always
volumeMounts:
- mountPath: /csi
name: socket-dir
volumes:
- hostPath:
path: /var/lib/kubelet/plugins/csi-hostpath
type: DirectoryOrCreate
name: socket-dir

View File

@ -0,0 +1,48 @@
kind: Service
apiVersion: v1
metadata:
name: csi-hostpath-snapshotter
labels:
app: csi-hostpath-snapshotter
spec:
selector:
app: csi-hostpath-snapshotter
ports:
- name: dummy
port: 12345
---
kind: StatefulSet
apiVersion: apps/v1
metadata:
name: csi-hostpath-snapshotter
spec:
serviceName: "csi-hostpath-snapshotter"
replicas: 1
selector:
matchLabels:
app: csi-hostpath-snapshotter
template:
metadata:
labels:
app: csi-hostpath-snapshotter
spec:
serviceAccount: csi-snapshotter
containers:
- name: csi-snapshotter
image: quay.io/k8scsi/csi-snapshotter:v0.4.1
args:
- "--csi-address=$(ADDRESS)"
- "--connection-timeout=15s"
env:
- name: ADDRESS
value: /csi/csi.sock
imagePullPolicy: Always
volumeMounts:
- mountPath: /csi
name: socket-dir
volumes:
- hostPath:
path: /var/lib/kubelet/plugins/csi-hostpath
type: DirectoryOrCreate
name: socket-dir

View File

@ -0,0 +1,70 @@
kind: DaemonSet
apiVersion: apps/v1
metadata:
name: csi-hostpathplugin
spec:
selector:
matchLabels:
app: csi-hostpathplugin
template:
metadata:
labels:
app: csi-hostpathplugin
spec:
serviceAccountName: csi-node-sa
hostNetwork: true
containers:
- name: driver-registrar
image: gcr.io/gke-release/csi-driver-registrar:v1.0.1-gke.0
args:
- --v=5
- --csi-address=/csi/csi.sock
- --kubelet-registration-path=/var/lib/kubelet/plugins/csi-hostpath/csi.sock
env:
- name: KUBE_NODE_NAME
valueFrom:
fieldRef:
apiVersion: v1
fieldPath: spec.nodeName
imagePullPolicy: Always
volumeMounts:
- mountPath: /csi
name: socket-dir
- mountPath: /registration
name: registration-dir
- name: hostpath
image: quay.io/k8scsi/hostpathplugin:v1.0.0
args:
- "--v=5"
- "--endpoint=$(CSI_ENDPOINT)"
- "--nodeid=$(KUBE_NODE_NAME)"
env:
- name: CSI_ENDPOINT
value: unix:///csi/csi.sock
- name: KUBE_NODE_NAME
valueFrom:
fieldRef:
apiVersion: v1
fieldPath: spec.nodeName
imagePullPolicy: Always
securityContext:
privileged: true
volumeMounts:
- mountPath: /csi
name: socket-dir
- mountPath: /var/lib/kubelet/pods
mountPropagation: Bidirectional
name: mountpoint-dir
volumes:
- hostPath:
path: /var/lib/kubelet/plugins/csi-hostpath
type: DirectoryOrCreate
name: socket-dir
- hostPath:
path: /var/lib/kubelet/pods
type: DirectoryOrCreate
name: mountpoint-dir
- hostPath:
path: /var/lib/kubelet/plugins_registry
type: Directory
name: registration-dir

View File

@ -0,0 +1,16 @@
kind: Pod
apiVersion: v1
metadata:
name: my-csi-app
spec:
containers:
- name: my-frontend
image: busybox
volumeMounts:
- mountPath: "/data"
name: my-csi-volume
command: [ "sleep", "1000000" ]
volumes:
- name: my-csi-volume
persistentVolumeClaim:
claimName: csi-pvc # defined in csi-pvs.yaml

View File

@ -0,0 +1,11 @@
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: csi-pvc
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
storageClassName: csi-hostpath-sc # defined in csi-setup.yaml

View File

@ -0,0 +1,7 @@
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: csi-hostpath-sc
provisioner: csi-hostpath
reclaimPolicy: Delete
volumeBindingMode: Immediate

View File

@ -14,18 +14,11 @@ APP=hostpathplugin
SKIP="WithCapacity"
if [ x${TRAVIS} = x"true" ] ; then
SKIP="WithCapacity|NodeUnpublishVolume|NodePublishVolume"
SKIP="ValidateVolumeCapabilities"
fi
# Get csi-sanity
if [ ! -x $GOPATH/bin/csi-sanity ] ; then
go get -u github.com/kubernetes-csi/csi-test
pushd $GOPATH/src/github.com/kubernetes-csi/csi-test/cmd/csi-sanity
make all
make install
popd
#./hack/get-sanity.sh
fi
./hack/get-sanity.sh
# Build
make hostpath

View File

@ -1,15 +1,12 @@
#!/bin/sh
VERSION="v0.1.0-2"
VERSION="v1.0.0-rc2"
SANITYTGZ="csi-sanity-${VERSION}.linux.amd64.tar.gz"
if [ ! -x $GOPATH/bin/csi-sanity ] ; then
curl -s -L \
https://github.com/kubernetes-csi/csi-test/releases/download/${VERSION}/${SANITYTGZ} \
-o ${SANITYTGZ} && \
tar xzvf ${SANITYTGZ} -C /tmp && \
rm -f ${SANITYTGZ} && \
cp /tmp/csi-sanity/csi-sanity $GOPATH/bin/csi-sanity && \
rm -rf /tmp/csi-sanity
fi
echo "Downloading csi-test from https://github.com/kubernetes-csi/csi-test/releases/download/${VERSION}/${SANITYTGZ}"
curl -s -L "https://github.com/kubernetes-csi/csi-test/releases/download/${VERSION}/${SANITYTGZ}" -o ${SANITYTGZ}
tar xzvf ${SANITYTGZ} -C /tmp && \
rm -f ${SANITYTGZ} && \
rm -f $GOPATH/bin/csi-sanity
cp /tmp/csi-sanity/csi-sanity $GOPATH/bin/csi-sanity && \
rm -rf /tmp/csi-sanity

View File

@ -1,91 +0,0 @@
# CSI Cinder driver
## Kubernetes
### Requirements
The following feature gates and runtime config have to be enabled to deploy the driver.
```
FEATURE_GATES=CSIPersistentVolume=true,MountPropagation=true
RUNTIME_CONFIG="storage.k8s.io/v1alpha1=true"
```
Mountprogpation requires support for privileged containers. So, make sure privileged containers are enabled in the cluster.
### Example local-up-cluster.sh
```ALLOW_PRIVILEGED=true FEATURE_GATES=CSIPersistentVolume=true,MountPropagation=true RUNTIME_CONFIG="storage.k8s.io/v1alpha1=true" LOG_LEVEL=5 hack/local-up-cluster.sh```
### Deploy
Encode your ```cloud.conf``` file content using base64.
```base64 -w 0 cloud.conf```
Update ```cloud.conf``` configuration in ```deploy/kubernetes/csi-secret-cinderplugin.yaml``` file
by using the result of the above command.
```kubectl -f deploy/kubernetes create```
### Example Nginx application
```kubectl -f examples/kubernetes/nginx.yaml create```
## Using CSC tool
### Start Cinder driver
```
$ sudo ./_output/cinderplugin --endpoint tcp://127.0.0.1:10000 --cloud-config /etc/cloud.conf --nodeid CSINodeID
```
### Test using csc
Get ```csc``` tool from https://github.com/rexray/gocsi/tree/master/csc
#### Get plugin info
```
$ csc identity plugin-info --endpoint tcp://127.0.0.1:10000
"csi-cinderplugin" "0.1.0"
```
#### Create a volume
```
$ csc controller new --endpoint tcp://127.0.0.1:10000 CSIVolumeName
CSIVolumeID
```
#### Delete a volume
```
$ csc controller del --endpoint tcp://127.0.0.1:10000 CSIVolumeID
CSIVolumeID
```
#### ControllerPublish a volume
```
$ csc controller publish --endpoint tcp://127.0.0.1:10000 --node-id=CSINodeID CSIVolumeID
CSIVolumeID "DevicePath"="/dev/xxx"
```
#### ControllerUnpublish a volume
```
$ csc controller unpublish --endpoint tcp://127.0.0.1:10000 --node-id=CSINodeID CSIVolumeID
CSIVolumeID
```
#### NodePublish a volume
```
$ csc node publish --endpoint tcp://127.0.0.1:10000 --target-path /mnt/cinder --pub-info DevicePath="/dev/xxx" CSIVolumeID
CSIVolumeID
```
#### NodeUnpublish a volume
```
$ csc node unpublish --endpoint tcp://127.0.0.1:10000 --target-path /mnt/cinder CSIVolumeID
CSIVolumeID
```
#### Get NodeID
```
$ csc node get-id --endpoint tcp://127.0.0.1:10000
CSINodeID
```

View File

@ -1,172 +0,0 @@
/*
Copyright 2017 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package cinder
import (
"github.com/container-storage-interface/spec/lib/go/csi/v0"
"github.com/golang/glog"
"github.com/kubernetes-csi/drivers/pkg/cinder/openstack"
csicommon "github.com/kubernetes-csi/drivers/pkg/csi-common"
"github.com/pborman/uuid"
"golang.org/x/net/context"
"k8s.io/kubernetes/pkg/volume/util"
)
type controllerServer struct {
*csicommon.DefaultControllerServer
}
func (cs *controllerServer) CreateVolume(ctx context.Context, req *csi.CreateVolumeRequest) (*csi.CreateVolumeResponse, error) {
// Volume Name
volName := req.GetName()
if len(volName) == 0 {
volName = uuid.NewUUID().String()
}
// Volume Size - Default is 1 GiB
volSizeBytes := int64(1 * 1024 * 1024 * 1024)
if req.GetCapacityRange() != nil {
volSizeBytes = int64(req.GetCapacityRange().GetRequiredBytes())
}
volSizeGB := int(util.RoundUpSize(volSizeBytes, 1024*1024*1024))
// Volume Type
volType := req.GetParameters()["type"]
// Volume Availability - Default is nova
volAvailability := req.GetParameters()["availability"]
// Get OpenStack Provider
cloud, err := openstack.GetOpenStackProvider()
if err != nil {
glog.V(3).Infof("Failed to GetOpenStackProvider: %v", err)
return nil, err
}
// Volume Create
resID, resAvailability, err := cloud.CreateVolume(volName, volSizeGB, volType, volAvailability, nil)
if err != nil {
glog.V(3).Infof("Failed to CreateVolume: %v", err)
return nil, err
}
glog.V(4).Infof("Create volume %s in Availability Zone: %s", resID, resAvailability)
return &csi.CreateVolumeResponse{
Volume: &csi.Volume{
Id: resID,
Attributes: map[string]string{
"availability": resAvailability,
},
},
}, nil
}
func (cs *controllerServer) DeleteVolume(ctx context.Context, req *csi.DeleteVolumeRequest) (*csi.DeleteVolumeResponse, error) {
// Get OpenStack Provider
cloud, err := openstack.GetOpenStackProvider()
if err != nil {
glog.V(3).Infof("Failed to GetOpenStackProvider: %v", err)
return nil, err
}
// Volume Delete
volID := req.GetVolumeId()
err = cloud.DeleteVolume(volID)
if err != nil {
glog.V(3).Infof("Failed to DeleteVolume: %v", err)
return nil, err
}
glog.V(4).Infof("Delete volume %s", volID)
return &csi.DeleteVolumeResponse{}, nil
}
func (cs *controllerServer) ControllerPublishVolume(ctx context.Context, req *csi.ControllerPublishVolumeRequest) (*csi.ControllerPublishVolumeResponse, error) {
// Get OpenStack Provider
cloud, err := openstack.GetOpenStackProvider()
if err != nil {
glog.V(3).Infof("Failed to GetOpenStackProvider: %v", err)
return nil, err
}
// Volume Attach
instanceID := req.GetNodeId()
volumeID := req.GetVolumeId()
_, err = cloud.AttachVolume(instanceID, volumeID)
if err != nil {
glog.V(3).Infof("Failed to AttachVolume: %v", err)
return nil, err
}
err = cloud.WaitDiskAttached(instanceID, volumeID)
if err != nil {
glog.V(3).Infof("Failed to WaitDiskAttached: %v", err)
return nil, err
}
devicePath, err := cloud.GetAttachmentDiskPath(instanceID, volumeID)
if err != nil {
glog.V(3).Infof("Failed to GetAttachmentDiskPath: %v", err)
return nil, err
}
glog.V(4).Infof("ControllerPublishVolume %s on %s", volumeID, instanceID)
// Publish Volume Info
pvInfo := map[string]string{}
pvInfo["DevicePath"] = devicePath
return &csi.ControllerPublishVolumeResponse{
PublishInfo: pvInfo,
}, nil
}
func (cs *controllerServer) ControllerUnpublishVolume(ctx context.Context, req *csi.ControllerUnpublishVolumeRequest) (*csi.ControllerUnpublishVolumeResponse, error) {
// Get OpenStack Provider
cloud, err := openstack.GetOpenStackProvider()
if err != nil {
glog.V(3).Infof("Failed to GetOpenStackProvider: %v", err)
return nil, err
}
// Volume Detach
instanceID := req.GetNodeId()
volumeID := req.GetVolumeId()
err = cloud.DetachVolume(instanceID, volumeID)
if err != nil {
glog.V(3).Infof("Failed to DetachVolume: %v", err)
return nil, err
}
err = cloud.WaitDiskDetached(instanceID, volumeID)
if err != nil {
glog.V(3).Infof("Failed to WaitDiskDetached: %v", err)
return nil, err
}
glog.V(4).Infof("ControllerUnpublishVolume %s on %s", volumeID, instanceID)
return &csi.ControllerUnpublishVolumeResponse{}, nil
}

View File

@ -1,172 +0,0 @@
/*
Copyright 2017 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package cinder
import (
"testing"
"github.com/container-storage-interface/spec/lib/go/csi/v0"
"github.com/kubernetes-csi/drivers/pkg/cinder/openstack"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
)
var fakeCs *controllerServer
// Init Controller Server
func init() {
if fakeCs == nil {
d := NewDriver(fakeNodeID, fakeEndpoint, fakeConfig)
fakeCs = NewControllerServer(d)
}
}
// Test CreateVolume
func TestCreateVolume(t *testing.T) {
// mock OpenStack
osmock := new(openstack.OpenStackMock)
// CreateVolume(name string, size int, vtype, availability string, tags *map[string]string) (string, string, error)
osmock.On("CreateVolume", fakeVolName, mock.AnythingOfType("int"), fakeVolType, fakeAvailability, (*map[string]string)(nil)).Return(fakeVolID, fakeAvailability, nil)
openstack.OsInstance = osmock
// Init assert
assert := assert.New(t)
// Fake request
fakeReq := &csi.CreateVolumeRequest{
Name: fakeVolName,
VolumeCapabilities: nil,
}
// Invoke CreateVolume
actualRes, err := fakeCs.CreateVolume(fakeCtx, fakeReq)
if err != nil {
t.Errorf("failed to CreateVolume: %v", err)
}
// Assert
assert.NotNil(actualRes.Volume)
assert.NotEqual(0, len(actualRes.Volume.Id), "Volume Id is nil")
assert.Equal(fakeAvailability, actualRes.Volume.Attributes["availability"])
}
// Test DeleteVolume
func TestDeleteVolume(t *testing.T) {
// mock OpenStack
osmock := new(openstack.OpenStackMock)
// DeleteVolume(volumeID string) error
osmock.On("DeleteVolume", fakeVolID).Return(nil)
openstack.OsInstance = osmock
// Init assert
assert := assert.New(t)
// Fake request
fakeReq := &csi.DeleteVolumeRequest{
VolumeId: fakeVolID,
}
// Expected Result
expectedRes := &csi.DeleteVolumeResponse{}
// Invoke DeleteVolume
actualRes, err := fakeCs.DeleteVolume(fakeCtx, fakeReq)
if err != nil {
t.Errorf("failed to DeleteVolume: %v", err)
}
// Assert
assert.Equal(expectedRes, actualRes)
}
// Test ControllerPublishVolume
func TestControllerPublishVolume(t *testing.T) {
// mock OpenStack
osmock := new(openstack.OpenStackMock)
// AttachVolume(instanceID, volumeID string) (string, error)
osmock.On("AttachVolume", fakeNodeID, fakeVolID).Return(fakeVolID, nil)
// WaitDiskAttached(instanceID string, volumeID string) error
osmock.On("WaitDiskAttached", fakeNodeID, fakeVolID).Return(nil)
// GetAttachmentDiskPath(instanceID, volumeID string) (string, error)
osmock.On("GetAttachmentDiskPath", fakeNodeID, fakeVolID).Return(fakeDevicePath, nil)
openstack.OsInstance = osmock
// Init assert
assert := assert.New(t)
// Fake request
fakeReq := &csi.ControllerPublishVolumeRequest{
VolumeId: fakeVolID,
NodeId: fakeNodeID,
VolumeCapability: nil,
Readonly: false,
}
// Expected Result
expectedRes := &csi.ControllerPublishVolumeResponse{
PublishInfo: map[string]string{
"DevicePath": fakeDevicePath,
},
}
// Invoke ControllerPublishVolume
actualRes, err := fakeCs.ControllerPublishVolume(fakeCtx, fakeReq)
if err != nil {
t.Errorf("failed to ControllerPublishVolume: %v", err)
}
// Assert
assert.Equal(expectedRes, actualRes)
}
// Test ControllerUnpublishVolume
func TestControllerUnpublishVolume(t *testing.T) {
// mock OpenStack
osmock := new(openstack.OpenStackMock)
// DetachVolume(instanceID, volumeID string) error
osmock.On("DetachVolume", fakeNodeID, fakeVolID).Return(nil)
// WaitDiskDetached(instanceID string, volumeID string) error
osmock.On("WaitDiskDetached", fakeNodeID, fakeVolID).Return(nil)
openstack.OsInstance = osmock
// Init assert
assert := assert.New(t)
// Fake request
fakeReq := &csi.ControllerUnpublishVolumeRequest{
VolumeId: fakeVolID,
NodeId: fakeNodeID,
}
// Expected Result
expectedRes := &csi.ControllerUnpublishVolumeResponse{}
// Invoke ControllerUnpublishVolume
actualRes, err := fakeCs.ControllerUnpublishVolume(fakeCtx, fakeReq)
if err != nil {
t.Errorf("failed to ControllerUnpublishVolume: %v", err)
}
// Assert
assert.Equal(expectedRes, actualRes)
}

View File

@ -1,71 +0,0 @@
# This YAML file contains attacher & csi driver API objects,
# which are necessary to run external csi attacher for cinder.
kind: Service
apiVersion: v1
metadata:
name: csi-attacher-cinderplugin
labels:
app: csi-attacher-cinderplugin
spec:
selector:
app: csi-attacher-cinderplugin
ports:
- name: dummy
port: 12345
---
kind: StatefulSet
apiVersion: apps/v1beta1
metadata:
name: csi-attacher-cinderplugin
spec:
serviceName: "csi-attacher-cinderplugin"
replicas: 1
template:
metadata:
labels:
app: csi-attacher-cinderplugin
spec:
serviceAccount: csi-attacher
containers:
- name: csi-attacher
image: quay.io/k8scsi/csi-attacher:v0.3.0
args:
- "--v=5"
- "--csi-address=$(ADDRESS)"
env:
- name: ADDRESS
value: /var/lib/csi/sockets/pluginproxy/csi.sock
imagePullPolicy: "IfNotPresent"
volumeMounts:
- name: socket-dir
mountPath: /var/lib/csi/sockets/pluginproxy/
- name: cinder
image: quay.io/k8scsi/cinderplugin
args :
- "--nodeid=$(NODE_ID)"
- "--endpoint=$(CSI_ENDPOINT)"
- "--cloud-config=$(CLOUD_CONFIG)"
env:
- name: NODE_ID
valueFrom:
fieldRef:
fieldPath: spec.nodeName
- name: CSI_ENDPOINT
value: unix://csi/csi.sock
- name: CLOUD_CONFIG
value: /etc/config/cloud.conf
imagePullPolicy: "IfNotPresent"
volumeMounts:
- name: socket-dir
mountPath: /csi
- name: secret-cinderplugin
mountPath: /etc/config
readOnly: true
volumes:
- name: socket-dir
emptyDir:
- name: secret-cinderplugin
secret:
secretName: csi-secret-cinderplugin

View File

@ -1,37 +0,0 @@
# This YAML file contains RBAC API objects,
# which are necessary to run external csi attacher for cinder.
apiVersion: v1
kind: ServiceAccount
metadata:
name: csi-attacher
---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: external-attacher-runner
rules:
- apiGroups: [""]
resources: ["persistentvolumes"]
verbs: ["get", "list", "watch", "update"]
- apiGroups: [""]
resources: ["nodes"]
verbs: ["get", "list", "watch"]
- apiGroups: ["storage.k8s.io"]
resources: ["volumeattachments"]
verbs: ["get", "list", "watch", "update"]
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: csi-attacher-role
subjects:
- kind: ServiceAccount
name: csi-attacher
namespace: default
roleRef:
kind: ClusterRole
name: external-attacher-runner
apiGroup: rbac.authorization.k8s.io

View File

@ -1,90 +0,0 @@
# This YAML file contains driver-registrar & csi driver nodeplugin API objects,
# which are necessary to run csi nodeplugin for cinder.
kind: DaemonSet
apiVersion: apps/v1beta2
metadata:
name: csi-nodeplugin-cinderplugin
spec:
selector:
matchLabels:
app: csi-nodeplugin-cinderplugin
template:
metadata:
labels:
app: csi-nodeplugin-cinderplugin
spec:
serviceAccount: csi-nodeplugin
hostNetwork: true
containers:
- name: driver-registrar
image: quay.io/k8scsi/driver-registrar:v0.3.0
args:
- "--v=5"
- "--csi-address=$(ADDRESS)"
env:
- name: ADDRESS
value: /csi/csi.sock
- name: KUBE_NODE_NAME
valueFrom:
fieldRef:
fieldPath: spec.nodeName
volumeMounts:
- name: socket-dir
mountPath: /csi
- name: cinder
securityContext:
privileged: true
capabilities:
add: ["SYS_ADMIN"]
allowPrivilegeEscalation: true
image: quay.io/k8scsi/cinderplugin
args :
- "--nodeid=$(NODE_ID)"
- "--endpoint=$(CSI_ENDPOINT)"
- "--cloud-config=$(CLOUD_CONFIG)"
env:
- name: NODE_ID
valueFrom:
fieldRef:
fieldPath: spec.nodeName
- name: CSI_ENDPOINT
value: unix://csi/csi.sock
- name: CLOUD_CONFIG
value: /etc/config/cloud.conf
imagePullPolicy: "IfNotPresent"
volumeMounts:
- name: socket-dir
mountPath: /csi
- name: pods-mount-dir
mountPath: /var/lib/kubelet/pods
mountPropagation: "Bidirectional"
- name: pods-cloud-data
mountPath: /var/lib/cloud/data
readOnly: true
- name: pods-probe-dir
mountPath: /dev
mountPropagation: "HostToContainer"
- name: secret-cinderplugin
mountPath: /etc/config
readOnly: true
volumes:
- name: socket-dir
hostPath:
path: /var/lib/kubelet/plugins/csi-cinderplugin
type: DirectoryOrCreate
- name: pods-mount-dir
hostPath:
path: /var/lib/kubelet/pods
type: Directory
- name: pods-cloud-data
hostPath:
path: /var/lib/cloud/data
type: Directory
- name: pods-probe-dir
hostPath:
path: /dev
type: Directory
- name: secret-cinderplugin
secret:
secretName: csi-secret-cinderplugin

View File

@ -1,35 +0,0 @@
# This YAML defines all API objects to create RBAC roles for csi node plugin.
apiVersion: v1
kind: ServiceAccount
metadata:
name: csi-nodeplugin
---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: csi-nodeplugin
rules:
- apiGroups: [""]
resources: ["persistentvolumes"]
verbs: ["get", "list", "watch", "update"]
- apiGroups: [""]
resources: ["nodes"]
verbs: ["get", "list", "watch", "update"]
- apiGroups: ["storage.k8s.io"]
resources: ["volumeattachments"]
verbs: ["get", "list", "watch", "update"]
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: csi-nodeplugin
subjects:
- kind: ServiceAccount
name: csi-nodeplugin
namespace: default
roleRef:
kind: ClusterRole
name: csi-nodeplugin
apiGroup: rbac.authorization.k8s.io

View File

@ -1,71 +0,0 @@
# This YAML file contains attacher & csi driver API objects,
# which are necessary to run external csi provisioner for cinder.
kind: Service
apiVersion: v1
metadata:
name: csi-provisioner-cinderplugin
labels:
app: csi-provisioner-cinderplugin
spec:
selector:
app: csi-provisioner-cinderplugin
ports:
- name: dummy
port: 12345
---
kind: StatefulSet
apiVersion: apps/v1beta1
metadata:
name: csi-provisioner-cinderplugin
spec:
serviceName: "csi-provisioner-cinderplugin"
replicas: 1
template:
metadata:
labels:
app: csi-provisioner-cinderplugin
spec:
serviceAccount: csi-provisioner
containers:
- name: csi-provisioner
image: quay.io/k8scsi/csi-provisioner:v0.3.0
args:
- "--provisioner=csi-cinderplugin"
- "--csi-address=$(ADDRESS)"
env:
- name: ADDRESS
value: /var/lib/csi/sockets/pluginproxy/csi.sock
imagePullPolicy: "IfNotPresent"
volumeMounts:
- name: socket-dir
mountPath: /var/lib/csi/sockets/pluginproxy/
- name: cinder
image: quay.io/k8scsi/cinderplugin
args :
- "--nodeid=$(NODE_ID)"
- "--endpoint=$(CSI_ENDPOINT)"
- "--cloud-config=$(CLOUD_CONFIG)"
env:
- name: NODE_ID
valueFrom:
fieldRef:
fieldPath: spec.nodeName
- name: CSI_ENDPOINT
value: unix://csi/csi.sock
- name: CLOUD_CONFIG
value: /etc/config/cloud.conf
imagePullPolicy: "IfNotPresent"
volumeMounts:
- name: socket-dir
mountPath: /csi
- name: secret-cinderplugin
mountPath: /etc/config
readOnly: true
volumes:
- name: socket-dir
emptyDir:
- name: secret-cinderplugin
secret:
secretName: csi-secret-cinderplugin

View File

@ -1,41 +0,0 @@
# This YAML file contains RBAC API objects,
# which are necessary to run external csi provisioner for cinder.
apiVersion: v1
kind: ServiceAccount
metadata:
name: csi-provisioner
---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: external-provisioner-runner
rules:
- apiGroups: [""]
resources: ["persistentvolumes"]
verbs: ["get", "list", "watch", "create", "delete"]
- apiGroups: [""]
resources: ["persistentvolumeclaims"]
verbs: ["get", "list", "watch", "update"]
- apiGroups: ["storage.k8s.io"]
resources: ["storageclasses"]
verbs: ["get", "list", "watch"]
- apiGroups: [""]
resources: ["events"]
verbs: ["list", "watch", "create", "update", "patch"]
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: csi-provisioner-role
subjects:
- kind: ServiceAccount
name: csi-provisioner
namespace: default
roleRef:
kind: ClusterRole
name: external-provisioner-runner
apiGroup: rbac.authorization.k8s.io

View File

@ -1,9 +0,0 @@
# This YAML file contains secret objects,
# which are necessary to run csi cinder plugin.
kind: Secret
apiVersion: v1
metadata:
name: csi-secret-cinderplugin
data:
cloud.conf: W0dsb2JhbF0KdXNlcm5hbWU9dXNlcgpwYXNzd29yZD1wYXNzCmF1dGgtdXJsPWh0dHBzOi8vPGtleXN0b25lX2lwPi9pZGVudGl0eS92Mwp0ZW5hbnQtaWQ9Yzg2OTE2OGE4Mjg4NDdmMzlmN2YwNmVkZDczMDU2MzcKZG9tYWluLWlkPTJhNzNiOGY1OTdjMDQ1NTFhMGZkYzhlOTU1NDRiZThhCg==

View File

@ -1,13 +0,0 @@
# Based on centos
FROM centos:7.4.1708
LABEL maintainers="Kubernetes Authors"
LABEL description="Cinder CSI Plugin"
# Copy cinderplugin from build directory
COPY cinderplugin /cinderplugin
# Install e4fsprogs for format
RUN yum -y install e4fsprogs
# Define default command
ENTRYPOINT ["/cinderplugin"]

View File

@ -1,84 +0,0 @@
/*
Copyright 2017 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package cinder
import (
"github.com/container-storage-interface/spec/lib/go/csi/v0"
"github.com/golang/glog"
"github.com/kubernetes-csi/drivers/pkg/cinder/openstack"
"github.com/kubernetes-csi/drivers/pkg/csi-common"
)
type driver struct {
csiDriver *csicommon.CSIDriver
endpoint string
cloudconfig string
ids *csicommon.DefaultIdentityServer
cs *controllerServer
ns *nodeServer
cap []*csi.VolumeCapability_AccessMode
cscap []*csi.ControllerServiceCapability
}
const (
driverName = "csi-cinderplugin"
)
var (
version = "0.3.0"
)
func NewDriver(nodeID, endpoint string, cloudconfig string) *driver {
glog.Infof("Driver: %v version: %v", driverName, version)
d := &driver{}
d.endpoint = endpoint
d.cloudconfig = cloudconfig
csiDriver := csicommon.NewCSIDriver(driverName, version, nodeID)
csiDriver.AddControllerServiceCapabilities(
[]csi.ControllerServiceCapability_RPC_Type{
csi.ControllerServiceCapability_RPC_CREATE_DELETE_VOLUME,
csi.ControllerServiceCapability_RPC_PUBLISH_UNPUBLISH_VOLUME,
})
csiDriver.AddVolumeCapabilityAccessModes([]csi.VolumeCapability_AccessMode_Mode{csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER})
d.csiDriver = csiDriver
return d
}
func NewControllerServer(d *driver) *controllerServer {
return &controllerServer{
DefaultControllerServer: csicommon.NewDefaultControllerServer(d.csiDriver),
}
}
func NewNodeServer(d *driver) *nodeServer {
return &nodeServer{
DefaultNodeServer: csicommon.NewDefaultNodeServer(d.csiDriver),
}
}
func (d *driver) Run() {
openstack.InitOpenStackProvider(d.cloudconfig)
csicommon.RunControllerandNodePublishServer(d.endpoint, d.csiDriver, NewControllerServer(d), NewNodeServer(d))
}

View File

@ -1,6 +0,0 @@
[Global]
username=user
password=pass
auth-url=https://<keystone_ip>/identity/v3
tenant-id=c869168a828847f39f7f06edd7305637
domain-id=2a73b8f597c04551a0fdc8e95544be8a

View File

@ -1,44 +0,0 @@
# This YAML file contains nginx & csi cinder driver objects,
# which are necessary to run nginx with csi cinder driver.
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: csi-sc-cinderplugin
provisioner: csi-cinderplugin
parameters:
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: csi-pvc-cinderplugin
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
storageClassName: csi-sc-cinderplugin
---
apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
containers:
- image: nginx
imagePullPolicy: IfNotPresent
name: nginx
ports:
- containerPort: 80
protocol: TCP
volumeMounts:
- mountPath: /var/lib/www/html
name: csi-data-cinderplugin
volumes:
- name: csi-data-cinderplugin
persistentVolumeClaim:
claimName: csi-pvc-cinderplugin
readOnly: false

View File

@ -1,32 +0,0 @@
/*
Copyright 2017 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package cinder
import (
"golang.org/x/net/context"
)
var fakeNodeID = "CSINodeID"
var fakeEndpoint = "tcp://127.0.0.1:10000"
var fakeConfig = "/etc/cloud.conf"
var fakeCtx = context.Background()
var fakeVolName = "CSIVolumeName"
var fakeVolID = "CSIVolumeID"
var fakeVolType = ""
var fakeAvailability = ""
var fakeDevicePath = "/dev/xxx"
var fakeTargetPath = "/mnt/cinder"

View File

@ -1,161 +0,0 @@
/*
Copyright 2017 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package mount
import (
"fmt"
"io/ioutil"
"os"
"strings"
"time"
"k8s.io/kubernetes/pkg/util/mount"
"k8s.io/kubernetes/pkg/volume/util"
utilexec "k8s.io/utils/exec"
"github.com/golang/glog"
)
const (
probeVolumeDuration = 1 * time.Second
probeVolumeTimeout = 60 * time.Second
instanceIDFile = "/var/lib/cloud/data/instance-id"
)
type IMount interface {
ScanForAttach(devicePath string) error
IsLikelyNotMountPointAttach(targetpath string) (bool, error)
FormatAndMount(source string, target string, fstype string, options []string) error
IsLikelyNotMountPointDetach(targetpath string) (bool, error)
UnmountPath(mountPath string) error
GetInstanceID() (string, error)
}
type Mount struct {
}
var MInstance IMount = nil
func GetMountProvider() (IMount, error) {
if MInstance == nil {
MInstance = &Mount{}
}
return MInstance, nil
}
// probeVolume probes volume in compute
func probeVolume() error {
// rescan scsi bus
scsi_path := "/sys/class/scsi_host/"
if dirs, err := ioutil.ReadDir(scsi_path); err == nil {
for _, f := range dirs {
name := scsi_path + f.Name() + "/scan"
data := []byte("- - -")
ioutil.WriteFile(name, data, 0666)
}
}
executor := utilexec.New()
args := []string{"trigger"}
cmd := executor.Command("udevadm", args...)
_, err := cmd.CombinedOutput()
if err != nil {
glog.V(3).Infof("error running udevadm trigger %v\n", err)
return err
}
glog.V(4).Infof("Successfully probed all attachments")
return nil
}
// ScanForAttach
func (m *Mount) ScanForAttach(devicePath string) error {
ticker := time.NewTicker(probeVolumeDuration)
defer ticker.Stop()
timer := time.NewTimer(probeVolumeTimeout)
defer timer.Stop()
for {
select {
case <-ticker.C:
glog.V(5).Infof("Checking Cinder disk %q is attached.", devicePath)
probeVolume()
exists, err := util.PathExists(devicePath)
if exists && err == nil {
return nil
} else {
glog.V(3).Infof("Could not find attached Cinder disk %s", devicePath)
}
case <-timer.C:
return fmt.Errorf("Could not find attached Cinder disk %s. Timeout waiting for mount paths to be created.", devicePath)
}
}
}
// FormatAndMount
func (m *Mount) FormatAndMount(source string, target string, fstype string, options []string) error {
diskMounter := &mount.SafeFormatAndMount{Interface: mount.New(""), Exec: mount.NewOsExec()}
return diskMounter.FormatAndMount(source, target, fstype, options)
}
// IsLikelyNotMountPointAttach
func (m *Mount) IsLikelyNotMountPointAttach(targetpath string) (bool, error) {
notMnt, err := mount.New("").IsLikelyNotMountPoint(targetpath)
if err != nil {
if os.IsNotExist(err) {
err = os.MkdirAll(targetpath, 0750)
if err == nil {
notMnt = true
}
}
}
return notMnt, err
}
// IsLikelyNotMountPointDetach
func (m *Mount) IsLikelyNotMountPointDetach(targetpath string) (bool, error) {
notMnt, err := mount.New("").IsLikelyNotMountPoint(targetpath)
if err != nil {
if os.IsNotExist(err) {
return notMnt, fmt.Errorf("targetpath not found")
} else {
return notMnt, err
}
}
return notMnt, nil
}
// UnmountPath
func (m *Mount) UnmountPath(mountPath string) error {
return util.UnmountPath(mountPath, mount.New(""))
}
// GetInstanceID from file
func (m *Mount) GetInstanceID() (string, error) {
// Try to find instance ID on the local filesystem (created by cloud-init)
idBytes, err := ioutil.ReadFile(instanceIDFile)
if err == nil {
instanceID := string(idBytes)
instanceID = strings.TrimSpace(instanceID)
glog.V(3).Infof("Got instance id from %s: %s", instanceIDFile, instanceID)
if instanceID != "" {
return instanceID, nil
}
}
return "", err
}

View File

@ -1,130 +0,0 @@
/*
Copyright 2017 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package mount
import mock "github.com/stretchr/testify/mock"
// MountMock is an autogenerated mock type for the IMount type
// ORIGINALLY GENERATED BY mockery with hand edits
type MountMock struct {
mock.Mock
}
// FormatAndMount provides a mock function with given fields: source, target, fstype, options
func (_m *MountMock) FormatAndMount(source string, target string, fstype string, options []string) error {
ret := _m.Called(source, target, fstype, options)
var r0 error
if rf, ok := ret.Get(0).(func(string, string, string, []string) error); ok {
r0 = rf(source, target, fstype, options)
} else {
r0 = ret.Error(0)
}
return r0
}
// GetInstanceID provides a mock function with given fields:
func (_m *MountMock) GetInstanceID() (string, error) {
ret := _m.Called()
var r0 string
if rf, ok := ret.Get(0).(func() string); ok {
r0 = rf()
} else {
r0 = ret.Get(0).(string)
}
var r1 error
if rf, ok := ret.Get(1).(func() error); ok {
r1 = rf()
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// IsLikelyNotMountPointAttach provides a mock function with given fields: targetpath
func (_m *MountMock) IsLikelyNotMountPointAttach(targetpath string) (bool, error) {
ret := _m.Called(targetpath)
var r0 bool
if rf, ok := ret.Get(0).(func(string) bool); ok {
r0 = rf(targetpath)
} else {
r0 = ret.Get(0).(bool)
}
var r1 error
if rf, ok := ret.Get(1).(func(string) error); ok {
r1 = rf(targetpath)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// IsLikelyNotMountPointDetach provides a mock function with given fields: targetpath
func (_m *MountMock) IsLikelyNotMountPointDetach(targetpath string) (bool, error) {
ret := _m.Called(targetpath)
var r0 bool
if rf, ok := ret.Get(0).(func(string) bool); ok {
r0 = rf(targetpath)
} else {
r0 = ret.Get(0).(bool)
}
var r1 error
if rf, ok := ret.Get(1).(func(string) error); ok {
r1 = rf(targetpath)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// ScanForAttach provides a mock function with given fields: devicePath
func (_m *MountMock) ScanForAttach(devicePath string) error {
ret := _m.Called(devicePath)
var r0 error
if rf, ok := ret.Get(0).(func(string) error); ok {
r0 = rf(devicePath)
} else {
r0 = ret.Error(0)
}
return r0
}
// UnmountPath provides a mock function with given fields: mountPath
func (_m *MountMock) UnmountPath(mountPath string) error {
ret := _m.Called(mountPath)
var r0 error
if rf, ok := ret.Get(0).(func(string) error); ok {
r0 = rf(mountPath)
} else {
r0 = ret.Error(0)
}
return r0
}

View File

@ -1,167 +0,0 @@
/*
Copyright 2017 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package cinder
import (
"github.com/container-storage-interface/spec/lib/go/csi/v0"
"github.com/golang/glog"
"golang.org/x/net/context"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
"github.com/kubernetes-csi/drivers/pkg/cinder/mount"
csicommon "github.com/kubernetes-csi/drivers/pkg/csi-common"
)
type nodeServer struct {
*csicommon.DefaultNodeServer
}
func (ns *nodeServer) NodeGetId(ctx context.Context, req *csi.NodeGetIdRequest) (*csi.NodeGetIdResponse, error) {
nodeID, err := getNodeID()
if err != nil {
return nil, err
}
if len(nodeID) > 0 {
return &csi.NodeGetIdResponse{
NodeId: nodeID,
}, nil
}
// Using default function
return ns.DefaultNodeServer.NodeGetId(ctx, req)
}
func (ns *nodeServer) NodeGetInfo(ctx context.Context, req *csi.NodeGetInfoRequest) (*csi.NodeGetInfoResponse, error) {
nodeID, err := getNodeID()
if err != nil {
return nil, err
}
if len(nodeID) > 0 {
return &csi.NodeGetInfoResponse{
NodeId: nodeID,
}, nil
}
// Using default function
return ns.DefaultNodeServer.NodeGetInfo(ctx, req)
}
func getNodeID() (string, error) {
// Get Mount Provider
m, err := mount.GetMountProvider()
if err != nil {
glog.V(3).Infof("Failed to GetMountProvider: %v", err)
return "", err
}
nodeID, err := m.GetInstanceID()
if err != nil {
glog.V(3).Infof("Failed to GetInstanceID: %v", err)
return "", err
}
return nodeID, nil
}
func (ns *nodeServer) NodePublishVolume(ctx context.Context, req *csi.NodePublishVolumeRequest) (*csi.NodePublishVolumeResponse, error) {
targetPath := req.GetTargetPath()
fsType := req.GetVolumeCapability().GetMount().GetFsType()
devicePath := req.GetPublishInfo()["DevicePath"]
// Get Mount Provider
m, err := mount.GetMountProvider()
if err != nil {
glog.V(3).Infof("Failed to GetMountProvider: %v", err)
return nil, err
}
// Device Scan
err = m.ScanForAttach(devicePath)
if err != nil {
glog.V(3).Infof("Failed to ScanForAttach: %v", err)
return nil, err
}
// Verify whether mounted
notMnt, err := m.IsLikelyNotMountPointAttach(targetPath)
if err != nil {
return nil, status.Error(codes.Internal, err.Error())
}
// Volume Mount
if notMnt {
// Get Options
var options []string
if req.GetReadonly() {
options = append(options, "ro")
} else {
options = append(options, "rw")
}
mountFlags := req.GetVolumeCapability().GetMount().GetMountFlags()
options = append(options, mountFlags...)
// Mount
err = m.FormatAndMount(devicePath, targetPath, fsType, options)
if err != nil {
return nil, status.Error(codes.Internal, err.Error())
}
}
return &csi.NodePublishVolumeResponse{}, nil
}
func (ns *nodeServer) NodeUnpublishVolume(ctx context.Context, req *csi.NodeUnpublishVolumeRequest) (*csi.NodeUnpublishVolumeResponse, error) {
targetPath := req.GetTargetPath()
// Get Mount Provider
m, err := mount.GetMountProvider()
if err != nil {
glog.V(3).Infof("Failed to GetMountProvider: %v", err)
return nil, err
}
notMnt, err := m.IsLikelyNotMountPointDetach(targetPath)
if err != nil {
return nil, status.Error(codes.Internal, err.Error())
}
if notMnt {
return nil, status.Error(codes.NotFound, "Volume not mounted")
}
err = m.UnmountPath(req.GetTargetPath())
if err != nil {
return nil, status.Error(codes.Internal, err.Error())
}
return &csi.NodeUnpublishVolumeResponse{}, nil
}
func (ns *nodeServer) NodeUnstageVolume(ctx context.Context, req *csi.NodeUnstageVolumeRequest) (*csi.NodeUnstageVolumeResponse, error) {
return &csi.NodeUnstageVolumeResponse{}, nil
}
func (ns *nodeServer) NodeStageVolume(ctx context.Context, req *csi.NodeStageVolumeRequest) (*csi.NodeStageVolumeResponse, error) {
return &csi.NodeStageVolumeResponse{}, nil
}

View File

@ -1,168 +0,0 @@
/*
Copyright 2017 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package cinder
import (
"testing"
"github.com/container-storage-interface/spec/lib/go/csi/v0"
"github.com/kubernetes-csi/drivers/pkg/cinder/mount"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
)
var fakeNs *nodeServer
// Init Node Server
func init() {
if fakeNs == nil {
d := NewDriver(fakeNodeID, fakeEndpoint, fakeConfig)
fakeNs = NewNodeServer(d)
}
}
// Test NodeGetId
func TestNodeGetId(t *testing.T) {
// mock MountMock
mmock := new(mount.MountMock)
// GetInstanceID() (string, error)
mmock.On("GetInstanceID").Return(fakeNodeID, nil)
mount.MInstance = mmock
// Init assert
assert := assert.New(t)
// Expected Result
expectedRes := &csi.NodeGetIdResponse{
NodeId: fakeNodeID,
}
// Fake request
fakeReq := &csi.NodeGetIdRequest{}
// Invoke NodeGetId
actualRes, err := fakeNs.NodeGetId(fakeCtx, fakeReq)
if err != nil {
t.Errorf("failed to NodeGetId: %v", err)
}
// Assert
assert.Equal(expectedRes, actualRes)
}
// Test NodeGetInfo
func TestNodeGetInfo(t *testing.T) {
// mock MountMock
mmock := new(mount.MountMock)
// GetInstanceID() (string, error)
mmock.On("GetInstanceID").Return(fakeNodeID, nil)
mount.MInstance = mmock
// Init assert
assert := assert.New(t)
// Expected Result
expectedRes := &csi.NodeGetInfoResponse{
NodeId: fakeNodeID,
}
// Fake request
fakeReq := &csi.NodeGetInfoRequest{}
// Invoke NodeGetId
actualRes, err := fakeNs.NodeGetInfo(fakeCtx, fakeReq)
if err != nil {
t.Errorf("failed to NodeGetInfo: %v", err)
}
// Assert
assert.Equal(expectedRes, actualRes)
}
// Test NodePublishVolume
func TestNodePublishVolume(t *testing.T) {
// mock MountMock
mmock := new(mount.MountMock)
// ScanForAttach(devicePath string) error
mmock.On("ScanForAttach", fakeDevicePath).Return(nil)
// IsLikelyNotMountPointAttach(targetpath string) (bool, error)
mmock.On("IsLikelyNotMountPointAttach", fakeTargetPath).Return(true, nil)
// FormatAndMount(source string, target string, fstype string, options []string) error
mmock.On("FormatAndMount", fakeDevicePath, fakeTargetPath, mock.AnythingOfType("string"), []string{"rw"}).Return(nil)
mount.MInstance = mmock
// Init assert
assert := assert.New(t)
// Expected Result
expectedRes := &csi.NodePublishVolumeResponse{}
// Fake request
fakeReq := &csi.NodePublishVolumeRequest{
VolumeId: fakeVolID,
PublishInfo: map[string]string{"DevicePath": fakeDevicePath},
TargetPath: fakeTargetPath,
VolumeCapability: nil,
Readonly: false,
}
// Invoke NodePublishVolume
actualRes, err := fakeNs.NodePublishVolume(fakeCtx, fakeReq)
if err != nil {
t.Errorf("failed to NodePublishVolume: %v", err)
}
// Assert
assert.Equal(expectedRes, actualRes)
}
// Test NodeUnpublishVolume
func TestNodeUnpublishVolume(t *testing.T) {
// mock MountMock
mmock := new(mount.MountMock)
// IsLikelyNotMountPointDetach(targetpath string) (bool, error)
mmock.On("IsLikelyNotMountPointDetach", fakeTargetPath).Return(false, nil)
// UnmountPath(mountPath string) error
mmock.On("UnmountPath", fakeTargetPath).Return(nil)
mount.MInstance = mmock
// Init assert
assert := assert.New(t)
// Expected Result
expectedRes := &csi.NodeUnpublishVolumeResponse{}
// Fake request
fakeReq := &csi.NodeUnpublishVolumeRequest{
VolumeId: fakeVolID,
TargetPath: fakeTargetPath,
}
// Invoke NodeUnpublishVolume
actualRes, err := fakeNs.NodeUnpublishVolume(fakeCtx, fakeReq)
if err != nil {
t.Errorf("failed to NodeUnpublishVolume: %v", err)
}
// Assert
assert.Equal(expectedRes, actualRes)
}

View File

@ -1,163 +0,0 @@
/*
Copyright 2017 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package openstack
import (
"os"
"github.com/golang/glog"
"github.com/gophercloud/gophercloud"
"github.com/gophercloud/gophercloud/openstack"
"gopkg.in/gcfg.v1"
)
type IOpenStack interface {
CreateVolume(name string, size int, vtype, availability string, tags *map[string]string) (string, string, error)
DeleteVolume(volumeID string) error
AttachVolume(instanceID, volumeID string) (string, error)
WaitDiskAttached(instanceID string, volumeID string) error
DetachVolume(instanceID, volumeID string) error
WaitDiskDetached(instanceID string, volumeID string) error
GetAttachmentDiskPath(instanceID, volumeID string) (string, error)
}
type OpenStack struct {
compute *gophercloud.ServiceClient
blockstorage *gophercloud.ServiceClient
}
type Config struct {
Global struct {
AuthUrl string `gcfg:"auth-url"`
Username string
UserId string `gcfg:"user-id"`
Password string
TenantId string `gcfg:"tenant-id"`
TenantName string `gcfg:"tenant-name"`
DomainId string `gcfg:"domain-id"`
DomainName string `gcfg:"domain-name"`
Region string
}
}
func (cfg Config) toAuthOptions() gophercloud.AuthOptions {
return gophercloud.AuthOptions{
IdentityEndpoint: cfg.Global.AuthUrl,
Username: cfg.Global.Username,
UserID: cfg.Global.UserId,
Password: cfg.Global.Password,
TenantID: cfg.Global.TenantId,
TenantName: cfg.Global.TenantName,
DomainID: cfg.Global.DomainId,
DomainName: cfg.Global.DomainName,
// Persistent service, so we need to be able to renew tokens.
AllowReauth: true,
}
}
func GetConfigFromFile(configFilePath string) (gophercloud.AuthOptions, gophercloud.EndpointOpts, error) {
// Get config from file
var authOpts gophercloud.AuthOptions
var epOpts gophercloud.EndpointOpts
config, err := os.Open(configFilePath)
if err != nil {
glog.V(3).Infof("Failed to open OpenStack configuration file: %v", err)
return authOpts, epOpts, err
}
defer config.Close()
// Read configuration
var cfg Config
err = gcfg.ReadInto(&cfg, config)
if err != nil {
glog.V(3).Infof("Failed to read OpenStack configuration file: %v", err)
return authOpts, epOpts, err
}
authOpts = cfg.toAuthOptions()
epOpts = gophercloud.EndpointOpts{
Region: cfg.Global.Region,
}
return authOpts, epOpts, nil
}
func GetConfigFromEnv() (gophercloud.AuthOptions, gophercloud.EndpointOpts, error) {
// Get config from env
authOpts, err := openstack.AuthOptionsFromEnv()
var epOpts gophercloud.EndpointOpts
if err != nil {
glog.V(3).Infof("Failed to read OpenStack configuration from env: %v", err)
return authOpts, epOpts, err
}
epOpts = gophercloud.EndpointOpts{
Region: os.Getenv("OS_REGION_NAME"),
}
return authOpts, epOpts, nil
}
var OsInstance IOpenStack = nil
var configFile string = "/etc/cloud.conf"
func InitOpenStackProvider(cfg string) {
configFile = cfg
glog.V(2).Infof("InitOpenStackProvider configFile: %s", configFile)
}
func GetOpenStackProvider() (IOpenStack, error) {
if OsInstance == nil {
// Get config from file
authOpts, epOpts, err := GetConfigFromFile(configFile)
if err != nil {
// Get config from env
authOpts, epOpts, err = GetConfigFromEnv()
if err != nil {
return nil, err
}
}
// Authenticate Client
provider, err := openstack.AuthenticatedClient(authOpts)
if err != nil {
return nil, err
}
// Init Nova ServiceClient
computeclient, err := openstack.NewComputeV2(provider, epOpts)
if err != nil {
return nil, err
}
// Init Cinder ServiceClient
blockstorageclient, err := openstack.NewBlockStorageV3(provider, epOpts)
if err != nil {
return nil, err
}
// Init OpenStack
OsInstance = &OpenStack{
compute: computeclient,
blockstorage: blockstorageclient,
}
}
return OsInstance, nil
}

View File

@ -1,151 +0,0 @@
/*
Copyright 2017 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package openstack
import "github.com/stretchr/testify/mock"
// OpenStackMock is an autogenerated mock type for the IOpenStack type
// ORIGINALLY GENERATED BY mockery with hand edits
type OpenStackMock struct {
mock.Mock
}
// AttachVolume provides a mock function with given fields: instanceID, volumeID
func (_m *OpenStackMock) AttachVolume(instanceID string, volumeID string) (string, error) {
ret := _m.Called(instanceID, volumeID)
var r0 string
if rf, ok := ret.Get(0).(func(string, string) string); ok {
r0 = rf(instanceID, volumeID)
} else {
r0 = ret.Get(0).(string)
}
var r1 error
if rf, ok := ret.Get(1).(func(string, string) error); ok {
r1 = rf(instanceID, volumeID)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// CreateVolume provides a mock function with given fields: name, size, vtype, availability, tags
func (_m *OpenStackMock) CreateVolume(name string, size int, vtype string, availability string, tags *map[string]string) (string, string, error) {
ret := _m.Called(name, size, vtype, availability, tags)
var r0 string
if rf, ok := ret.Get(0).(func(string, int, string, string, *map[string]string) string); ok {
r0 = rf(name, size, vtype, availability, tags)
} else {
r0 = ret.Get(0).(string)
}
var r1 string
if rf, ok := ret.Get(1).(func(string, int, string, string, *map[string]string) string); ok {
r1 = rf(name, size, vtype, availability, tags)
} else {
r1 = ret.Get(1).(string)
}
var r2 error
if rf, ok := ret.Get(2).(func(string, int, string, string, *map[string]string) error); ok {
r2 = rf(name, size, vtype, availability, tags)
} else {
r2 = ret.Error(2)
}
return r0, r1, r2
}
// DeleteVolume provides a mock function with given fields: volumeID
func (_m *OpenStackMock) DeleteVolume(volumeID string) error {
ret := _m.Called(volumeID)
var r0 error
if rf, ok := ret.Get(0).(func(string) error); ok {
r0 = rf(volumeID)
} else {
r0 = ret.Error(0)
}
return r0
}
// DetachVolume provides a mock function with given fields: instanceID, volumeID
func (_m *OpenStackMock) DetachVolume(instanceID string, volumeID string) error {
ret := _m.Called(instanceID, volumeID)
var r0 error
if rf, ok := ret.Get(0).(func(string, string) error); ok {
r0 = rf(instanceID, volumeID)
} else {
r0 = ret.Error(0)
}
return r0
}
// GetAttachmentDiskPath provides a mock function with given fields: instanceID, volumeID
func (_m *OpenStackMock) GetAttachmentDiskPath(instanceID string, volumeID string) (string, error) {
ret := _m.Called(instanceID, volumeID)
var r0 string
if rf, ok := ret.Get(0).(func(string, string) string); ok {
r0 = rf(instanceID, volumeID)
} else {
r0 = ret.Get(0).(string)
}
var r1 error
if rf, ok := ret.Get(1).(func(string, string) error); ok {
r1 = rf(instanceID, volumeID)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// WaitDiskAttached provides a mock function with given fields: instanceID, volumeID
func (_m *OpenStackMock) WaitDiskAttached(instanceID string, volumeID string) error {
ret := _m.Called(instanceID, volumeID)
var r0 error
if rf, ok := ret.Get(0).(func(string, string) error); ok {
r0 = rf(instanceID, volumeID)
} else {
r0 = ret.Error(0)
}
return r0
}
// WaitDiskDetached provides a mock function with given fields: instanceID, volumeID
func (_m *OpenStackMock) WaitDiskDetached(instanceID string, volumeID string) error {
ret := _m.Called(instanceID, volumeID)
var r0 error
if rf, ok := ret.Get(0).(func(string, string) error); ok {
r0 = rf(instanceID, volumeID)
} else {
r0 = ret.Error(0)
}
return r0
}

View File

@ -1,119 +0,0 @@
/*
Copyright 2017 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package openstack
import (
"os"
"testing"
"github.com/gophercloud/gophercloud"
"github.com/stretchr/testify/assert"
)
var fakeFileName = "cloud.conf"
var fakeUserName = "user"
var fakePassword = "pass"
var fakeAuthUrl = "https://169.254.169.254/identity/v3"
var fakeTenantID = "c869168a828847f39f7f06edd7305637"
var fakeDomainID = "2a73b8f597c04551a0fdc8e95544be8a"
var fakeRegion = "RegionOne"
// Test GetConfigFromFile
func TestGetConfigFromFile(t *testing.T) {
// init file
var fakeFileContent = `
[Global]
username=` + fakeUserName + `
password=` + fakePassword + `
auth-url=` + fakeAuthUrl + `
tenant-id=` + fakeTenantID + `
domain-id=` + fakeDomainID + `
region=` + fakeRegion + `
`
f, err := os.Create(fakeFileName)
if err != nil {
t.Errorf("failed to create file: %v", err)
}
_, err = f.WriteString(fakeFileContent)
f.Close()
if err != nil {
t.Errorf("failed to write file: %v", err)
}
defer os.Remove(fakeFileName)
// Init assert
assert := assert.New(t)
expectedAuthOpts := gophercloud.AuthOptions{
IdentityEndpoint: fakeAuthUrl,
Username: fakeUserName,
Password: fakePassword,
TenantID: fakeTenantID,
DomainID: fakeDomainID,
AllowReauth: true,
}
expectedEpOpts := gophercloud.EndpointOpts{
Region: fakeRegion,
}
// Invoke GetConfigFromFile
actualAuthOpts, actualEpOpts, err := GetConfigFromFile(fakeFileName)
if err != nil {
t.Errorf("failed to GetConfigFromFile: %v", err)
}
// Assert
assert.Equal(expectedAuthOpts, actualAuthOpts)
assert.Equal(expectedEpOpts, actualEpOpts)
}
// Test GetConfigFromEnv
func TestGetConfigFromEnv(t *testing.T) {
// init env
os.Setenv("OS_AUTH_URL", fakeAuthUrl)
os.Setenv("OS_USERNAME", fakeUserName)
os.Setenv("OS_PASSWORD", fakePassword)
os.Setenv("OS_TENANT_ID", fakeTenantID)
os.Setenv("OS_DOMAIN_ID", fakeDomainID)
os.Setenv("OS_REGION_NAME", fakeRegion)
// Init assert
assert := assert.New(t)
expectedAuthOpts := gophercloud.AuthOptions{
IdentityEndpoint: fakeAuthUrl,
Username: fakeUserName,
Password: fakePassword,
TenantID: fakeTenantID,
DomainID: fakeDomainID,
}
expectedEpOpts := gophercloud.EndpointOpts{
Region: fakeRegion,
}
// Invoke GetConfigFromEnv
actualAuthOpts, actualEpOpts, err := GetConfigFromEnv()
if err != nil {
t.Errorf("failed to GetConfigFromEnv: %v", err)
}
// Assert
assert.Equal(expectedAuthOpts, actualAuthOpts)
assert.Equal(expectedEpOpts, actualEpOpts)
}

View File

@ -1,253 +0,0 @@
/*
Copyright 2017 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package openstack
import (
"fmt"
"time"
"github.com/gophercloud/gophercloud/openstack/blockstorage/v3/volumes"
"github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/volumeattach"
"k8s.io/apimachinery/pkg/util/wait"
"github.com/golang/glog"
)
const (
VolumeAvailableStatus = "available"
VolumeInUseStatus = "in-use"
VolumeDeletedStatus = "deleted"
VolumeErrorStatus = "error"
operationFinishInitDelay = 1 * time.Second
operationFinishFactor = 1.1
operationFinishSteps = 10
diskAttachInitDelay = 1 * time.Second
diskAttachFactor = 1.2
diskAttachSteps = 15
diskDetachInitDelay = 1 * time.Second
diskDetachFactor = 1.2
diskDetachSteps = 13
)
type Volume struct {
// ID of the instance, to which this volume is attached. "" if not attached
AttachedServerId string
// Device file path
AttachedDevice string
// Unique identifier for the volume.
ID string
// Human-readable display name for the volume.
Name string
// Current status of the volume.
Status string
// Volume size in GB
Size int
}
// CreateVolume creates a volume of given size
func (os *OpenStack) CreateVolume(name string, size int, vtype, availability string, tags *map[string]string) (string, string, error) {
opts := &volumes.CreateOpts{
Name: name,
Size: size,
VolumeType: vtype,
AvailabilityZone: availability,
}
if tags != nil {
opts.Metadata = *tags
}
vol, err := volumes.Create(os.blockstorage, opts).Extract()
if err != nil {
return "", "", err
}
return vol.ID, vol.AvailabilityZone, nil
}
// DeleteVolume delete a volume
func (os *OpenStack) DeleteVolume(volumeID string) error {
used, err := os.diskIsUsed(volumeID)
if err != nil {
return err
}
if used {
return fmt.Errorf("Cannot delete the volume %q, it's still attached to a node", volumeID)
}
err = volumes.Delete(os.blockstorage, volumeID).ExtractErr()
return err
}
// GetVolume retrieves Volume by its ID.
func (os *OpenStack) GetVolume(volumeID string) (Volume, error) {
vol, err := volumes.Get(os.blockstorage, volumeID).Extract()
if err != nil {
return Volume{}, err
}
volume := Volume{
ID: vol.ID,
Name: vol.Name,
Status: vol.Status,
}
if len(vol.Attachments) > 0 {
volume.AttachedServerId = vol.Attachments[0].ServerID
volume.AttachedDevice = vol.Attachments[0].Device
}
return volume, nil
}
// AttachVolume attaches given cinder volume to the compute
func (os *OpenStack) AttachVolume(instanceID, volumeID string) (string, error) {
volume, err := os.GetVolume(volumeID)
if err != nil {
return "", err
}
if volume.AttachedServerId != "" {
if instanceID == volume.AttachedServerId {
glog.V(4).Infof("Disk %s is already attached to instance %s", volumeID, instanceID)
return volume.ID, nil
}
return "", fmt.Errorf("disk %s is attached to a different instance (%s)", volumeID, volume.AttachedServerId)
}
_, err = volumeattach.Create(os.compute, instanceID, &volumeattach.CreateOpts{
VolumeID: volume.ID,
}).Extract()
if err != nil {
return "", fmt.Errorf("failed to attach %s volume to %s compute: %v", volumeID, instanceID, err)
}
glog.V(2).Infof("Successfully attached %s volume to %s compute", volumeID, instanceID)
return volume.ID, nil
}
// WaitDiskAttached waits for attched
func (os *OpenStack) WaitDiskAttached(instanceID string, volumeID string) error {
backoff := wait.Backoff{
Duration: diskAttachInitDelay,
Factor: diskAttachFactor,
Steps: diskAttachSteps,
}
err := wait.ExponentialBackoff(backoff, func() (bool, error) {
attached, err := os.diskIsAttached(instanceID, volumeID)
if err != nil {
return false, err
}
return attached, nil
})
if err == wait.ErrWaitTimeout {
err = fmt.Errorf("Volume %q failed to be attached within the alloted time", volumeID)
}
return err
}
// DetachVolume detaches given cinder volume from the compute
func (os *OpenStack) DetachVolume(instanceID, volumeID string) error {
volume, err := os.GetVolume(volumeID)
if err != nil {
return err
}
if volume.Status == VolumeAvailableStatus {
glog.V(2).Infof("volume: %s has been detached from compute: %s ", volume.ID, instanceID)
return nil
}
if volume.Status != VolumeInUseStatus {
return fmt.Errorf("can not detach volume %s, its status is %s", volume.Name, volume.Status)
}
if volume.AttachedServerId != instanceID {
return fmt.Errorf("disk: %s has no attachments or is not attached to compute: %s", volume.Name, instanceID)
} else {
err = volumeattach.Delete(os.compute, instanceID, volume.ID).ExtractErr()
if err != nil {
return fmt.Errorf("failed to delete volume %s from compute %s attached %v", volume.ID, instanceID, err)
}
glog.V(2).Infof("Successfully detached volume: %s from compute: %s", volume.ID, instanceID)
}
return nil
}
// WaitDiskDetached waits for detached
func (os *OpenStack) WaitDiskDetached(instanceID string, volumeID string) error {
backoff := wait.Backoff{
Duration: diskDetachInitDelay,
Factor: diskDetachFactor,
Steps: diskDetachSteps,
}
err := wait.ExponentialBackoff(backoff, func() (bool, error) {
attached, err := os.diskIsAttached(instanceID, volumeID)
if err != nil {
return false, err
}
return !attached, nil
})
if err == wait.ErrWaitTimeout {
err = fmt.Errorf("Volume %q failed to detach within the alloted time", volumeID)
}
return err
}
// GetAttachmentDiskPath gets device path of attached volume to the compute
func (os *OpenStack) GetAttachmentDiskPath(instanceID, volumeID string) (string, error) {
volume, err := os.GetVolume(volumeID)
if err != nil {
return "", err
}
if volume.Status != VolumeInUseStatus {
return "", fmt.Errorf("can not get device path of volume %s, its status is %s ", volume.Name, volume.Status)
}
if volume.AttachedServerId != "" {
if instanceID == volume.AttachedServerId {
return volume.AttachedDevice, nil
} else {
return "", fmt.Errorf("disk %q is attached to a different compute: %q, should be detached before proceeding", volumeID, volume.AttachedServerId)
}
}
return "", fmt.Errorf("volume %s has no ServerId", volumeID)
}
// diskIsAttached queries if a volume is attached to a compute instance
func (os *OpenStack) diskIsAttached(instanceID, volumeID string) (bool, error) {
volume, err := os.GetVolume(volumeID)
if err != nil {
return false, err
}
return instanceID == volume.AttachedServerId, nil
}
// diskIsUsed returns true a disk is attached to any node.
func (os *OpenStack) diskIsUsed(volumeID string) (bool, error) {
volume, err := os.GetVolume(volumeID)
if err != nil {
return false, err
}
return volume.AttachedServerId != "", nil
}

View File

@ -17,7 +17,7 @@ limitations under the License.
package csicommon
import (
"github.com/container-storage-interface/spec/lib/go/csi/v0"
"github.com/container-storage-interface/spec/lib/go/csi"
"github.com/golang/glog"
"golang.org/x/net/context"
"google.golang.org/grpc/codes"
@ -45,27 +45,7 @@ func (cs *DefaultControllerServer) ControllerUnpublishVolume(ctx context.Context
}
func (cs *DefaultControllerServer) ValidateVolumeCapabilities(ctx context.Context, req *csi.ValidateVolumeCapabilitiesRequest) (*csi.ValidateVolumeCapabilitiesResponse, error) {
glog.V(5).Infof("Using default ValidateVolumeCapabilities")
for _, c := range req.GetVolumeCapabilities() {
found := false
for _, c1 := range cs.Driver.vc {
if c1.GetMode() == c.GetAccessMode().GetMode() {
found = true
}
}
if !found {
return &csi.ValidateVolumeCapabilitiesResponse{
Supported: false,
Message: "Driver doesnot support mode:" + c.GetAccessMode().GetMode().String(),
}, status.Error(codes.InvalidArgument, "Driver doesnot support mode:"+c.GetAccessMode().GetMode().String())
}
// TODO: Ignoring mount & block tyeps for now.
}
return &csi.ValidateVolumeCapabilitiesResponse{
Supported: true,
}, nil
return nil, status.Error(codes.Unimplemented, "")
}
func (cs *DefaultControllerServer) ListVolumes(ctx context.Context, req *csi.ListVolumesRequest) (*csi.ListVolumesResponse, error) {

View File

@ -18,11 +18,12 @@ package csicommon
import (
"fmt"
"github.com/golang/glog"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
"github.com/container-storage-interface/spec/lib/go/csi/v0"
"github.com/container-storage-interface/spec/lib/go/csi"
)
type CSIDriver struct {

View File

@ -19,7 +19,7 @@ package csicommon
import (
"testing"
"github.com/container-storage-interface/spec/lib/go/csi/v0"
"github.com/container-storage-interface/spec/lib/go/csi"
"github.com/stretchr/testify/assert"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
@ -31,7 +31,7 @@ const (
)
var (
vendorVersion = "0.3.0"
vendorVersion = "1.0.0-rc2"
)
func NewFakeDriver() *CSIDriver {

View File

@ -17,7 +17,7 @@ limitations under the License.
package csicommon
import (
"github.com/container-storage-interface/spec/lib/go/csi/v0"
"github.com/container-storage-interface/spec/lib/go/csi"
"github.com/golang/glog"
"golang.org/x/net/context"
"google.golang.org/grpc/codes"

View File

@ -20,7 +20,7 @@ import (
"context"
"testing"
"github.com/container-storage-interface/spec/lib/go/csi/v0"
"github.com/container-storage-interface/spec/lib/go/csi"
"github.com/stretchr/testify/assert"
)

View File

@ -17,7 +17,7 @@ limitations under the License.
package csicommon
import (
"github.com/container-storage-interface/spec/lib/go/csi/v0"
"github.com/container-storage-interface/spec/lib/go/csi"
"github.com/golang/glog"
"golang.org/x/net/context"
"google.golang.org/grpc/codes"
@ -36,14 +36,6 @@ func (ns *DefaultNodeServer) NodeUnpublishVolume(ctx context.Context, req *csi.N
return nil, status.Error(codes.Unimplemented, "")
}
func (ns *DefaultNodeServer) NodeGetId(ctx context.Context, req *csi.NodeGetIdRequest) (*csi.NodeGetIdResponse, error) {
glog.V(5).Infof("Using default NodeGetId")
return &csi.NodeGetIdResponse{
NodeId: ns.Driver.nodeID,
}, nil
}
func (ns *DefaultNodeServer) NodeGetInfo(ctx context.Context, req *csi.NodeGetInfoRequest) (*csi.NodeGetInfoResponse, error) {
glog.V(5).Infof("Using default NodeGetInfo")
@ -67,3 +59,7 @@ func (ns *DefaultNodeServer) NodeGetCapabilities(ctx context.Context, req *csi.N
},
}, nil
}
func (ns *DefaultNodeServer) NodeGetVolumeStats(ctx context.Context, in *csi.NodeGetVolumeStatsRequest) (*csi.NodeGetVolumeStatsResponse, error) {
return nil, status.Error(codes.Unimplemented, "")
}

View File

@ -20,24 +20,12 @@ import (
"context"
"testing"
"github.com/container-storage-interface/spec/lib/go/csi/v0"
"github.com/container-storage-interface/spec/lib/go/csi"
"github.com/stretchr/testify/assert"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)
func TestNodeGetId(t *testing.T) {
d := NewFakeDriver()
ns := NewDefaultNodeServer(d)
// Test valid request
req := csi.NodeGetIdRequest{}
resp, err := ns.NodeGetId(context.Background(), &req)
assert.NoError(t, err)
assert.Equal(t, resp.GetNodeId(), fakeNodeID)
}
func TestNodeGetInfo(t *testing.T) {
d := NewFakeDriver()

View File

@ -24,7 +24,7 @@ import (
"github.com/golang/glog"
"google.golang.org/grpc"
"github.com/container-storage-interface/spec/lib/go/csi/v0"
"github.com/container-storage-interface/spec/lib/go/csi"
)
// Defines Non blocking GRPC server interfaces

View File

@ -20,7 +20,7 @@ import (
"fmt"
"strings"
"github.com/container-storage-interface/spec/lib/go/csi/v0"
"github.com/container-storage-interface/spec/lib/go/csi"
"github.com/golang/glog"
"golang.org/x/net/context"
"google.golang.org/grpc"

View File

@ -17,7 +17,7 @@ limitations under the License.
package flexadapter
import (
"github.com/container-storage-interface/spec/lib/go/csi/v0"
"github.com/container-storage-interface/spec/lib/go/csi"
"golang.org/x/net/context"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
@ -47,7 +47,7 @@ func (cs *controllerServer) ControllerPublishVolume(ctx context.Context, req *cs
}
call := cs.flexDriver.NewDriverCall(attachCmd)
call.AppendSpec(req.GetVolumeId(), fsType, req.GetReadonly(), req.GetVolumeAttributes())
call.AppendSpec(req.GetVolumeId(), fsType, req.GetReadonly(), req.GetVolumeContext())
call.Append(req.GetNodeId())
callStatus, err := call.Run()
@ -57,12 +57,12 @@ func (cs *controllerServer) ControllerPublishVolume(ctx context.Context, req *cs
return nil, status.Error(codes.Internal, err.Error())
}
pvInfo := map[string]string{}
publishContext := map[string]string{}
pvInfo[deviceID] = callStatus.DevicePath
publishContext[deviceID] = callStatus.DevicePath
return &csi.ControllerPublishVolumeResponse{
PublishInfo: pvInfo,
PublishContext: publishContext,
}, nil
}
@ -86,10 +86,5 @@ func (cs *controllerServer) ControllerUnpublishVolume(ctx context.Context, req *
}
func (cs *controllerServer) ValidateVolumeCapabilities(ctx context.Context, req *csi.ValidateVolumeCapabilitiesRequest) (*csi.ValidateVolumeCapabilitiesResponse, error) {
for _, cap := range req.VolumeCapabilities {
if cap.GetAccessMode().GetMode() != csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER {
return &csi.ValidateVolumeCapabilitiesResponse{Supported: false, Message: ""}, nil
}
}
return &csi.ValidateVolumeCapabilitiesResponse{Supported: true, Message: ""}, nil
return cs.DefaultControllerServer.ValidateVolumeCapabilities(ctx, req)
}

View File

@ -19,7 +19,7 @@ package flexadapter
import (
"os"
"github.com/container-storage-interface/spec/lib/go/csi/v0"
"github.com/container-storage-interface/spec/lib/go/csi"
"github.com/golang/glog"
"github.com/kubernetes-csi/drivers/pkg/csi-common"
@ -38,7 +38,7 @@ type flexAdapter struct {
}
var (
version = "0.3.0"
version = "1.0.0-rc2"
)
func New() *flexAdapter {

View File

@ -19,7 +19,7 @@ package flexadapter
import (
"os"
"github.com/container-storage-interface/spec/lib/go/csi/v0"
"github.com/container-storage-interface/spec/lib/go/csi"
"golang.org/x/net/context"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
@ -53,9 +53,9 @@ func (ns *nodeServer) waitForAttach(req *csi.NodePublishVolumeRequest, fsType st
var dID string
if req.GetPublishInfo() != nil {
if req.GetPublishContext() != nil {
var ok bool
dID, ok = req.GetPublishInfo()[deviceID]
dID, ok = req.GetPublishContext()[deviceID]
if !ok {
return status.Error(codes.InvalidArgument, "Missing device ID")
}
@ -65,7 +65,7 @@ func (ns *nodeServer) waitForAttach(req *csi.NodePublishVolumeRequest, fsType st
call := ns.flexDriver.NewDriverCall(waitForAttachCmd)
call.Append(dID)
call.AppendSpec(req.GetVolumeId(), fsType, req.GetReadonly(), req.GetVolumeAttributes())
call.AppendSpec(req.GetVolumeId(), fsType, req.GetReadonly(), req.GetVolumeContext())
_, err := call.Run()
if isCmdNotSupportedErr(err) {
@ -116,15 +116,15 @@ func (ns *nodeServer) NodePublishVolume(ctx context.Context, req *csi.NodePublis
call.Append(req.GetTargetPath())
if req.GetPublishInfo() != nil {
call.Append(req.GetPublishInfo()[deviceID])
if req.GetPublishContext() != nil {
call.Append(req.GetPublishContext()[deviceID])
}
call.AppendSpec(req.GetVolumeId(), fsType, req.GetReadonly(), req.GetVolumeAttributes())
call.AppendSpec(req.GetVolumeId(), fsType, req.GetReadonly(), req.GetVolumeContext())
_, err = call.Run()
if isCmdNotSupportedErr(err) {
mountFlags := req.GetVolumeCapability().GetMount().GetMountFlags()
err := mountDevice(req.VolumeAttributes[deviceID], targetPath, fsType, req.GetReadonly(), mountFlags)
err := mountDevice(req.VolumeContext[deviceID], targetPath, fsType, req.GetReadonly(), mountFlags)
if err != nil {
return nil, status.Error(codes.Internal, err.Error())
}

View File

@ -18,7 +18,12 @@ package hostpath
import (
"fmt"
"math"
"os"
"sort"
"strconv"
"github.com/golang/protobuf/ptypes"
"github.com/golang/glog"
"github.com/pborman/uuid"
@ -26,13 +31,15 @@ import (
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
"github.com/container-storage-interface/spec/lib/go/csi/v0"
"github.com/container-storage-interface/spec/lib/go/csi"
"github.com/kubernetes-csi/drivers/pkg/csi-common"
utilexec "k8s.io/utils/exec"
)
const (
deviceID = "deviceID"
provisionRoot = "/tmp/"
snapshotRoot = "/tmp/"
maxStorageCapacity = tib
)
@ -64,9 +71,9 @@ func (cs *controllerServer) CreateVolume(ctx context.Context, req *csi.CreateVol
// TODO (sbezverk) Do I need to make sure that RBD volume still exists?
return &csi.CreateVolumeResponse{
Volume: &csi.Volume{
Id: exVol.VolID,
VolumeId: exVol.VolID,
CapacityBytes: int64(exVol.VolSize),
Attributes: req.GetParameters(),
VolumeContext: req.GetParameters(),
},
}, nil
}
@ -84,6 +91,26 @@ func (cs *controllerServer) CreateVolume(ctx context.Context, req *csi.CreateVol
glog.V(3).Infof("failed to create volume: %v", err)
return nil, err
}
if req.GetVolumeContentSource() != nil {
contentSource := req.GetVolumeContentSource()
if contentSource.GetSnapshot() != nil {
snapshotId := contentSource.GetSnapshot().GetSnapshotId()
snapshot, ok := hostPathVolumeSnapshots[snapshotId]
if !ok {
return nil, status.Errorf(codes.NotFound, "cannot find snapshot %v", snapshotId)
}
if snapshot.ReadyToUse != true {
return nil, status.Errorf(codes.Internal, "Snapshot %v is not yet ready to use.", snapshotId)
}
snapshotPath := snapshot.Path
args := []string{"zxvf", snapshotPath, "-C", path}
executor := utilexec.New()
out, err := executor.Command("tar", args...).CombinedOutput()
if err != nil {
return nil, status.Error(codes.Internal, fmt.Sprintf("failed pre-populate data for volume: %v: %s", err, out))
}
}
}
glog.V(4).Infof("create volume %s", path)
hostPathVol := hostPathVolume{}
hostPathVol.VolName = req.GetName()
@ -93,9 +120,9 @@ func (cs *controllerServer) CreateVolume(ctx context.Context, req *csi.CreateVol
hostPathVolumes[volumeID] = hostPathVol
return &csi.CreateVolumeResponse{
Volume: &csi.Volume{
Id: volumeID,
VolumeId: volumeID,
CapacityBytes: req.GetCapacityRange().GetRequiredBytes(),
Attributes: req.GetParameters(),
VolumeContext: req.GetParameters(),
},
}, nil
}
@ -120,22 +147,221 @@ func (cs *controllerServer) DeleteVolume(ctx context.Context, req *csi.DeleteVol
}
func (cs *controllerServer) ValidateVolumeCapabilities(ctx context.Context, req *csi.ValidateVolumeCapabilitiesRequest) (*csi.ValidateVolumeCapabilitiesResponse, error) {
return cs.DefaultControllerServer.ValidateVolumeCapabilities(ctx, req)
}
// CreateSnapshot uses tar command to create snapshot for hostpath volume. The tar command can quickly create
// archives of entire directories. The host image must have "tar" binaries in /bin, /usr/sbin, or /usr/bin.
func (cs *controllerServer) CreateSnapshot(ctx context.Context, req *csi.CreateSnapshotRequest) (*csi.CreateSnapshotResponse, error) {
if err := cs.Driver.ValidateControllerServiceRequest(csi.ControllerServiceCapability_RPC_CREATE_DELETE_SNAPSHOT); err != nil {
glog.V(3).Infof("invalid create snapshot req: %v", req)
return nil, err
}
if len(req.GetName()) == 0 {
return nil, status.Error(codes.InvalidArgument, "Name missing in request")
}
// Check arguments
if len(req.GetVolumeId()) == 0 {
return nil, status.Error(codes.InvalidArgument, "Volume ID missing in request")
}
if req.GetVolumeCapabilities() == nil {
return nil, status.Error(codes.InvalidArgument, "Volume capabilities missing in request")
}
if _, ok := hostPathVolumes[req.GetVolumeId()]; !ok {
return nil, status.Error(codes.NotFound, "Volume does not exist")
if len(req.GetSourceVolumeId()) == 0 {
return nil, status.Error(codes.InvalidArgument, "SourceVolumeId missing in request")
}
for _, cap := range req.VolumeCapabilities {
if cap.GetAccessMode().GetMode() != csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER {
return &csi.ValidateVolumeCapabilitiesResponse{Supported: false, Message: ""}, nil
// Need to check for already existing snapshot name, and if found check for the
// requested sourceVolumeId and sourceVolumeId of snapshot that has been created.
if exSnap, err := getSnapshotByName(req.GetName()); err == nil {
// Since err is nil, it means the snapshot with the same name already exists need
// to check if the sourceVolumeId of existing snapshot is the same as in new request.
if exSnap.VolID == req.GetSourceVolumeId() {
// same snapshot has been created.
return &csi.CreateSnapshotResponse{
Snapshot: &csi.Snapshot{
SnapshotId: exSnap.Id,
SourceVolumeId: exSnap.VolID,
CreationTime: &exSnap.CreationTime,
SizeBytes: exSnap.SizeBytes,
ReadyToUse: exSnap.ReadyToUse,
},
}, nil
}
return nil, status.Error(codes.AlreadyExists, fmt.Sprintf("snapshot with the same name: %s but with different SourceVolumeId already exist", req.GetName()))
}
volumeID := req.GetSourceVolumeId()
hostPathVolume, ok := hostPathVolumes[volumeID]
if !ok {
return nil, status.Error(codes.Internal, "volumeID is not exist")
}
snapshotID := uuid.NewUUID().String()
creationTime := ptypes.TimestampNow()
volPath := hostPathVolume.VolPath
file := snapshotRoot + snapshotID + ".tgz"
args := []string{"czf", file, "-C", volPath, "."}
executor := utilexec.New()
out, err := executor.Command("tar", args...).CombinedOutput()
if err != nil {
return nil, status.Error(codes.Internal, fmt.Sprintf("failed create snapshot: %v: %s", err, out))
}
glog.V(4).Infof("create volume snapshot %s", file)
snapshot := hostPathSnapshot{}
snapshot.Name = req.GetName()
snapshot.Id = snapshotID
snapshot.VolID = volumeID
snapshot.Path = file
snapshot.CreationTime = *creationTime
snapshot.SizeBytes = hostPathVolume.VolSize
snapshot.ReadyToUse = true
hostPathVolumeSnapshots[snapshotID] = snapshot
return &csi.CreateSnapshotResponse{
Snapshot: &csi.Snapshot{
SnapshotId: snapshot.Id,
SourceVolumeId: snapshot.VolID,
CreationTime: &snapshot.CreationTime,
SizeBytes: snapshot.SizeBytes,
ReadyToUse: snapshot.ReadyToUse,
},
}, nil
}
func (cs *controllerServer) DeleteSnapshot(ctx context.Context, req *csi.DeleteSnapshotRequest) (*csi.DeleteSnapshotResponse, error) {
// Check arguments
if len(req.GetSnapshotId()) == 0 {
return nil, status.Error(codes.InvalidArgument, "Snapshot ID missing in request")
}
if err := cs.Driver.ValidateControllerServiceRequest(csi.ControllerServiceCapability_RPC_CREATE_DELETE_SNAPSHOT); err != nil {
glog.V(3).Infof("invalid delete snapshot req: %v", req)
return nil, err
}
snapshotID := req.GetSnapshotId()
glog.V(4).Infof("deleting volume %s", snapshotID)
path := snapshotRoot + snapshotID + ".tgz"
os.RemoveAll(path)
delete(hostPathVolumeSnapshots, snapshotID)
return &csi.DeleteSnapshotResponse{}, nil
}
func (cs *controllerServer) ListSnapshots(ctx context.Context, req *csi.ListSnapshotsRequest) (*csi.ListSnapshotsResponse, error) {
if err := cs.Driver.ValidateControllerServiceRequest(csi.ControllerServiceCapability_RPC_LIST_SNAPSHOTS); err != nil {
glog.V(3).Infof("invalid list snapshot req: %v", req)
return nil, err
}
// case 1: SnapshotId is not empty, return snapshots that match the snapshot id.
if len(req.GetSnapshotId()) != 0 {
snapshotID := req.SnapshotId
if snapshot, ok := hostPathVolumeSnapshots[snapshotID]; ok {
return convertSnapshot(snapshot), nil
}
}
return &csi.ValidateVolumeCapabilitiesResponse{Supported: true, Message: ""}, nil
// case 2: SourceVolumeId is not empty, return snapshots that match the source volume id.
if len(req.GetSourceVolumeId()) != 0 {
for _, snapshot := range hostPathVolumeSnapshots {
if snapshot.VolID == req.SourceVolumeId {
return convertSnapshot(snapshot), nil
}
}
}
var snapshots []csi.Snapshot
// case 3: no parameter is set, so we return all the snapshots.
sortedKeys := make([]string, 0)
for k := range hostPathVolumeSnapshots {
sortedKeys = append(sortedKeys, k)
}
sort.Strings(sortedKeys)
for _, key := range sortedKeys {
snap := hostPathVolumeSnapshots[key]
snapshot := csi.Snapshot{
SnapshotId: snap.Id,
SourceVolumeId: snap.VolID,
CreationTime: &snap.CreationTime,
SizeBytes: snap.SizeBytes,
ReadyToUse: snap.ReadyToUse,
}
snapshots = append(snapshots, snapshot)
}
var (
ulenSnapshots = int32(len(snapshots))
maxEntries = req.MaxEntries
startingToken int32
)
if v := req.StartingToken; v != "" {
i, err := strconv.ParseUint(v, 10, 32)
if err != nil {
return nil, status.Errorf(
codes.Aborted,
"startingToken=%d !< int32=%d",
startingToken, math.MaxUint32)
}
startingToken = int32(i)
}
if startingToken > ulenSnapshots {
return nil, status.Errorf(
codes.Aborted,
"startingToken=%d > len(snapshots)=%d",
startingToken, ulenSnapshots)
}
// Discern the number of remaining entries.
rem := ulenSnapshots - startingToken
// If maxEntries is 0 or greater than the number of remaining entries then
// set maxEntries to the number of remaining entries.
if maxEntries == 0 || maxEntries > rem {
maxEntries = rem
}
var (
i int
j = startingToken
entries = make(
[]*csi.ListSnapshotsResponse_Entry,
maxEntries)
)
for i = 0; i < len(entries); i++ {
entries[i] = &csi.ListSnapshotsResponse_Entry{
Snapshot: &snapshots[j],
}
j++
}
var nextToken string
if j < ulenSnapshots {
nextToken = fmt.Sprintf("%d", j)
}
return &csi.ListSnapshotsResponse{
Entries: entries,
NextToken: nextToken,
}, nil
}
func convertSnapshot(snap hostPathSnapshot) *csi.ListSnapshotsResponse {
entries := []*csi.ListSnapshotsResponse_Entry{
{
Snapshot: &csi.Snapshot{
SnapshotId: snap.Id,
SourceVolumeId: snap.VolID,
CreationTime: &snap.CreationTime,
SizeBytes: snap.SizeBytes,
ReadyToUse: snap.ReadyToUse,
},
},
}
rsp := &csi.ListSnapshotsResponse{
Entries: entries,
}
return rsp
}

View File

@ -19,9 +19,10 @@ package hostpath
import (
"fmt"
"github.com/container-storage-interface/spec/lib/go/csi/v0"
"github.com/container-storage-interface/spec/lib/go/csi"
"github.com/golang/glog"
timestamp "github.com/golang/protobuf/ptypes/timestamp"
"github.com/kubernetes-csi/drivers/pkg/csi-common"
)
@ -52,15 +53,27 @@ type hostPathVolume struct {
VolPath string `json:"volPath"`
}
type hostPathSnapshot struct {
Name string `json:"name"`
Id string `json:"id"`
VolID string `json:"volID"`
Path string `json:"path"`
CreationTime timestamp.Timestamp `json:"creationTime"`
SizeBytes int64 `json:"sizeBytes"`
ReadyToUse bool `json:"readyToUse"`
}
var hostPathVolumes map[string]hostPathVolume
var hostPathVolumeSnapshots map[string]hostPathSnapshot
var (
hostPathDriver *hostPath
vendorVersion = "0.3.0"
vendorVersion = "dev"
)
func init() {
hostPathVolumes = map[string]hostPathVolume{}
hostPathVolumeSnapshots = map[string]hostPathSnapshot{}
}
func GetHostPathDriver() *hostPath {
@ -87,13 +100,19 @@ func NewNodeServer(d *csicommon.CSIDriver) *nodeServer {
func (hp *hostPath) Run(driverName, nodeID, endpoint string) {
glog.Infof("Driver: %v ", driverName)
glog.Infof("Version: %s", vendorVersion)
// Initialize default library driver
hp.driver = csicommon.NewCSIDriver(driverName, vendorVersion, nodeID)
if hp.driver == nil {
glog.Fatalln("Failed to initialize CSI Driver.")
}
hp.driver.AddControllerServiceCapabilities([]csi.ControllerServiceCapability_RPC_Type{csi.ControllerServiceCapability_RPC_CREATE_DELETE_VOLUME})
hp.driver.AddControllerServiceCapabilities(
[]csi.ControllerServiceCapability_RPC_Type{
csi.ControllerServiceCapability_RPC_CREATE_DELETE_VOLUME,
csi.ControllerServiceCapability_RPC_CREATE_DELETE_SNAPSHOT,
csi.ControllerServiceCapability_RPC_LIST_SNAPSHOTS,
})
hp.driver.AddVolumeCapabilityAccessModes([]csi.VolumeCapability_AccessMode_Mode{csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER})
// Create GRPC servers
@ -121,3 +140,12 @@ func getVolumeByName(volName string) (hostPathVolume, error) {
}
return hostPathVolume{}, fmt.Errorf("volume name %s does not exit in the volumes list", volName)
}
func getSnapshotByName(name string) (hostPathSnapshot, error) {
for _, snapshot := range hostPathVolumeSnapshots {
if snapshot.Name == name {
return snapshot, nil
}
}
return hostPathSnapshot{}, fmt.Errorf("snapshot name %s does not exit in the snapshots list", name)
}

View File

@ -22,7 +22,7 @@ import (
"github.com/golang/glog"
"golang.org/x/net/context"
"github.com/container-storage-interface/spec/lib/go/csi/v0"
"github.com/container-storage-interface/spec/lib/go/csi"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
"k8s.io/kubernetes/pkg/util/mount"
@ -67,13 +67,13 @@ func (ns *nodeServer) NodePublishVolume(ctx context.Context, req *csi.NodePublis
fsType := req.GetVolumeCapability().GetMount().GetFsType()
deviceId := ""
if req.GetPublishInfo() != nil {
deviceId = req.GetPublishInfo()[deviceID]
if req.GetPublishContext() != nil {
deviceId = req.GetPublishContext()[deviceID]
}
readOnly := req.GetReadonly()
volumeId := req.GetVolumeId()
attrib := req.GetVolumeAttributes()
attrib := req.GetVolumeContext()
mountFlags := req.GetVolumeCapability().GetMount().GetMountFlags()
glog.V(4).Infof("target %v\nfstype %v\ndevice %v\nreadonly %v\nvolumeId %v\nattributes %v\nmountflags %v\n",

View File

@ -17,7 +17,7 @@ limitations under the License.
package iscsi
import (
"github.com/container-storage-interface/spec/lib/go/csi/v0"
"github.com/container-storage-interface/spec/lib/go/csi"
"github.com/golang/glog"
"github.com/kubernetes-csi/drivers/pkg/csi-common"
@ -39,7 +39,7 @@ const (
)
var (
version = "0.3.0"
version = "1.0.0-rc2"
)
func NewDriver(nodeID, endpoint string) *driver {

View File

@ -21,22 +21,22 @@ import (
"fmt"
"strings"
"github.com/container-storage-interface/spec/lib/go/csi/v0"
"github.com/container-storage-interface/spec/lib/go/csi"
"k8s.io/kubernetes/pkg/util/mount"
"k8s.io/kubernetes/pkg/volume/util"
)
func getISCSIInfo(req *csi.NodePublishVolumeRequest) (*iscsiDisk, error) {
volName := req.GetVolumeId()
tp := req.GetVolumeAttributes()["targetPortal"]
iqn := req.GetVolumeAttributes()["iqn"]
lun := req.GetVolumeAttributes()["lun"]
tp := req.GetVolumeContext()["targetPortal"]
iqn := req.GetVolumeContext()["iqn"]
lun := req.GetVolumeContext()["lun"]
if tp == "" || iqn == "" || lun == "" {
return nil, fmt.Errorf("iSCSI target information is missing")
}
portalList := req.GetVolumeAttributes()["portals"]
secretParams := req.GetVolumeAttributes()["secret"]
portalList := req.GetVolumeContext()["portals"]
secretParams := req.GetVolumeContext()["secret"]
secret := parseSecret(secretParams)
portal := portalMounter(tp)
@ -52,15 +52,15 @@ func getISCSIInfo(req *csi.NodePublishVolumeRequest) (*iscsiDisk, error) {
bkportal = append(bkportal, portalMounter(string(portal)))
}
iface := req.GetVolumeAttributes()["iscsiInterface"]
initiatorName := req.GetVolumeAttributes()["initiatorName"]
iface := req.GetVolumeContext()["iscsiInterface"]
initiatorName := req.GetVolumeContext()["initiatorName"]
chapDiscovery := false
if req.GetVolumeAttributes()["discoveryCHAPAuth"] == "true" {
if req.GetVolumeContext()["discoveryCHAPAuth"] == "true" {
chapDiscovery = true
}
chapSession := false
if req.GetVolumeAttributes()["sessionCHAPAuth"] == "true" {
if req.GetVolumeContext()["sessionCHAPAuth"] == "true" {
chapSession = true
}

View File

@ -17,7 +17,7 @@ limitations under the License.
package iscsi
import (
"github.com/container-storage-interface/spec/lib/go/csi/v0"
"github.com/container-storage-interface/spec/lib/go/csi"
"golang.org/x/net/context"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"

View File

@ -17,7 +17,7 @@ limitations under the License.
package nfs
import (
"github.com/container-storage-interface/spec/lib/go/csi/v0"
"github.com/container-storage-interface/spec/lib/go/csi"
"github.com/golang/glog"
"github.com/kubernetes-csi/drivers/pkg/csi-common"
@ -39,7 +39,7 @@ const (
)
var (
version = "0.3.0"
version = "1.0.0-rc2"
)
func NewDriver(nodeID, endpoint string) *driver {

View File

@ -21,7 +21,7 @@ import (
"os"
"strings"
"github.com/container-storage-interface/spec/lib/go/csi/v0"
"github.com/container-storage-interface/spec/lib/go/csi"
"golang.org/x/net/context"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
@ -58,8 +58,8 @@ func (ns *nodeServer) NodePublishVolume(ctx context.Context, req *csi.NodePublis
mo = append(mo, "ro")
}
s := req.GetVolumeAttributes()["server"]
ep := req.GetVolumeAttributes()["share"]
s := req.GetVolumeContext()["server"]
ep := req.GetVolumeContext()["share"]
source := fmt.Sprintf("%s:%s", s, ep)
mounter := mount.New("")