├── Module.symvers ├── tools ├── verification │ ├── settings.json │ ├── v_add_format_remove_10dysks.sh │ ├── v_add_remove_128dysks.sh │ ├── p_basic_io.sh │ ├── basic.fio │ ├── readme.md │ ├── v_simple_add_remove.sh │ ├── __add_remove_format_dysk.sh │ ├── v_add_format_remove_add.sh │ ├── __run_perf_test.sh │ ├── verify.sh │ └── v_mount_ro.sh ├── dysk-cli │ └── Dockerfile ├── dysk-installer │ ├── Dockerfile │ └── install.sh ├── dysk_shortcuts.sh ├── flexvol-installer │ ├── Dockerfile │ └── install.sh └── readme.md ├── dyskctl ├── main.go ├── vendor │ ├── github.com │ │ ├── spf13 │ │ │ ├── cobra │ │ │ │ ├── command_notwin.go │ │ │ │ ├── command_win.go │ │ │ │ ├── args.go │ │ │ │ ├── cobra │ │ │ │ │ └── cmd │ │ │ │ │ │ └── license_mit.go │ │ │ │ └── zsh_completions.go │ │ │ ├── afero │ │ │ │ ├── const_bsds.go │ │ │ │ ├── const_win_unix.go │ │ │ │ ├── mem │ │ │ │ │ ├── dir.go │ │ │ │ │ └── dirmap.go │ │ │ │ ├── readonlyfs.go │ │ │ │ ├── os.go │ │ │ │ └── httpFs.go │ │ │ ├── cast │ │ │ │ └── LICENSE │ │ │ ├── viper │ │ │ │ ├── LICENSE │ │ │ │ └── flags.go │ │ │ ├── jwalterweatherman │ │ │ │ ├── LICENSE │ │ │ │ └── log_counter.go │ │ │ └── pflag │ │ │ │ ├── LICENSE │ │ │ │ ├── int.go │ │ │ │ ├── golangflag.go │ │ │ │ ├── string.go │ │ │ │ ├── int64.go │ │ │ │ ├── int8.go │ │ │ │ ├── uint.go │ │ │ │ ├── count.go │ │ │ │ ├── uint8.go │ │ │ │ ├── int32.go │ │ │ │ └── ip.go │ │ ├── Azure │ │ │ ├── azure-sdk-for-go │ │ │ │ ├── NOTICE │ │ │ │ └── storage │ │ │ │ │ ├── version.go │ │ │ │ │ ├── commonsasuri.go │ │ │ │ │ ├── odata.go │ │ │ │ │ ├── queueserviceclient.go │ │ │ │ │ └── storagepolicy.go │ │ │ └── go-autorest │ │ │ │ └── autorest │ │ │ │ ├── adal │ │ │ │ ├── msi.go │ │ │ │ ├── msi_windows.go │ │ │ │ ├── sender.go │ │ │ │ ├── persist.go │ │ │ │ └── config.go │ │ │ │ ├── date │ │ │ │ └── utility.go │ │ │ │ ├── version.go │ │ │ │ ├── retriablerequest.go │ │ │ │ ├── retriablerequest_1.7.go │ │ │ │ └── retriablerequest_1.8.go │ │ ├── dgrijalva │ │ │ └── jwt-go │ │ │ │ ├── doc.go │ │ │ │ ├── LICENSE │ │ │ │ ├── signing_method.go │ │ │ │ ├── ecdsa_utils.go │ │ │ │ ├── none.go │ │ │ │ ├── rsa_utils.go │ │ │ │ ├── errors.go │ │ │ │ ├── hmac.go │ │ │ │ ├── rsa.go │ │ │ │ └── map_claims.go │ │ ├── hashicorp │ │ │ └── hcl │ │ │ │ ├── hcl │ │ │ │ ├── parser │ │ │ │ │ └── error.go │ │ │ │ ├── token │ │ │ │ │ └── position.go │ │ │ │ └── ast │ │ │ │ │ └── walk.go │ │ │ │ ├── hcl.go │ │ │ │ ├── lex.go │ │ │ │ ├── parse.go │ │ │ │ └── json │ │ │ │ └── token │ │ │ │ ├── position.go │ │ │ │ └── token.go │ │ ├── fsnotify │ │ │ └── fsnotify │ │ │ │ ├── open_mode_bsd.go │ │ │ │ ├── open_mode_darwin.go │ │ │ │ ├── fen.go │ │ │ │ ├── LICENSE │ │ │ │ ├── fsnotify.go │ │ │ │ └── AUTHORS │ │ ├── inconshreveable │ │ │ └── mousetrap │ │ │ │ ├── trap_others.go │ │ │ │ ├── LICENSE │ │ │ │ ├── trap_windows_1.4.go │ │ │ │ └── trap_windows.go │ │ ├── pelletier │ │ │ └── go-toml │ │ │ │ ├── position.go │ │ │ │ ├── doc.go │ │ │ │ ├── LICENSE │ │ │ │ ├── keysparsing.go │ │ │ │ └── token.go │ │ ├── magiconair │ │ │ └── properties │ │ │ │ ├── integrate.go │ │ │ │ ├── rangecheck.go │ │ │ │ ├── LICENSE │ │ │ │ └── parser.go │ │ ├── marstr │ │ │ └── guid │ │ │ │ └── LICENSE.txt │ │ ├── satori │ │ │ └── go.uuid │ │ │ │ └── LICENSE │ │ ├── rubiojr │ │ │ └── go-vhd │ │ │ │ ├── LICENSE │ │ │ │ ├── debian │ │ │ │ └── copyright │ │ │ │ └── vhd │ │ │ │ └── util.go │ │ └── mitchellh │ │ │ └── mapstructure │ │ │ ├── LICENSE │ │ │ └── error.go │ └── gopkg.in │ │ └── yaml.v2 │ │ ├── LICENSE.libyaml │ │ ├── writerc.go │ │ └── sorter.go ├── AUTHORS ├── Gopkg.toml ├── cmd │ ├── rootCmd.go │ └── converter.go └── Makefile ├── kubernetes ├── flexvolume │ ├── examples │ │ ├── storageclass.yaml │ │ ├── nginx-statefulset.yaml │ │ └── readme.md │ ├── pvc-dysk-flexvol.yaml │ ├── nginx-flex-dysk-readonly.yaml │ ├── pv-dysk-flexvol.yaml │ ├── nginx-flex-dysk.yaml │ └── deployment │ │ └── dysk-flexvol-installer.yaml └── csi │ ├── storageclass-csi-dysk.yaml │ ├── pvc-csi-dysk.yaml │ ├── pvc-csi-dysk-readonly.yaml │ ├── deployment │ └── csi-dysk │ │ └── README.md │ ├── nginx-pod-csi-dysk.yaml │ ├── pv-csi-dysk-readonly.yaml │ └── nginx-pod-csi-dysk-readonly.yaml ├── module ├── Makefile ├── az.h ├── dysk_utils.h └── ioctl_cmds.md ├── .gitignore ├── pkg └── client │ ├── types.go │ └── common.go ├── examples ├── 102-mount-existing │ └── readme.md ├── 101-mount-create │ └── readme.md └── readme.md ├── license.txt ├── Makefile └── docs └── design.md /Module.symvers: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tools/verification/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "account" : "{ACCOUNT NAME HERE}", 3 | "key" : "{ACCOUNT KEY HERE}" 4 | } 5 | -------------------------------------------------------------------------------- /tools/dysk-cli/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM alpine:3.5 2 | WORKDIR /bin 3 | 4 | ADD ./dyskctl /bin/dyskctl 5 | 6 | ENTRYPOINT ["./dyskctl"] 7 | -------------------------------------------------------------------------------- /dyskctl/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "github.com/khenidak/dysk/dyskctl/cmd" 4 | 5 | func main() { 6 | cmd.Execute() 7 | } 8 | -------------------------------------------------------------------------------- /dyskctl/vendor/github.com/spf13/cobra/command_notwin.go: -------------------------------------------------------------------------------- 1 | // +build !windows 2 | 3 | package cobra 4 | 5 | var preExecHookFn func(*Command) 6 | -------------------------------------------------------------------------------- /kubernetes/flexvolume/examples/storageclass.yaml: -------------------------------------------------------------------------------- 1 | nd: StorageClass 2 | metadata: 3 | name: flexvoldysk01 4 | provisioner: kubernetes.io/flexvolume 5 | -------------------------------------------------------------------------------- /dyskctl/vendor/github.com/Azure/azure-sdk-for-go/NOTICE: -------------------------------------------------------------------------------- 1 | Microsoft Azure-SDK-for-Go 2 | Copyright 2014-2017 Microsoft 3 | 4 | This product includes software developed at 5 | the Microsoft Corporation (https://www.microsoft.com). 6 | -------------------------------------------------------------------------------- /dyskctl/vendor/github.com/dgrijalva/jwt-go/doc.go: -------------------------------------------------------------------------------- 1 | // Package jwt is a Go implementation of JSON Web Tokens: http://self-issued.info/docs/draft-jones-json-web-token.html 2 | // 3 | // See README.md for more info. 4 | package jwt 5 | -------------------------------------------------------------------------------- /dyskctl/AUTHORS: -------------------------------------------------------------------------------- 1 | andyzhangx 2 | Eric Hotinger 3 | Johan Burati 4 | Khaled (Kal) Henidak 5 | Rita Zhang 6 | Ubuntu 7 | -------------------------------------------------------------------------------- /kubernetes/csi/storageclass-csi-dysk.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: storage.k8s.io/v1beta1 2 | kind: StorageClass 3 | metadata: 4 | name: csi-dysk 5 | provisioner: csi-dysk 6 | parameters: 7 | csiProvisionerSecretName: dyskcreds 8 | csiProvisionerSecretNamespace: default 9 | -------------------------------------------------------------------------------- /module/Makefile: -------------------------------------------------------------------------------- 1 | obj-m := dysk.o 2 | dysk-objs := dysk_utils.o dysk_worker.o dysk_bdd.o az.o 3 | 4 | all: 5 | make -C /lib/modules/$(shell uname -r)/build/ M=$(PWD) modules 6 | clean: 7 | make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean 8 | -------------------------------------------------------------------------------- /tools/dysk-installer/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:17.04 2 | RUN apt update && apt -y install kmod build-essential bash git && rm -r /var/lib/apt/lists/* 3 | 4 | 5 | COPY ./install.sh /etc/install_dysk.sh 6 | 7 | # run it 8 | CMD ["/etc/install_dysk.sh"] 9 | 10 | -------------------------------------------------------------------------------- /tools/verification/v_add_format_remove_10dysks.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" 4 | account="$1" 5 | key="$2" 6 | DYSKCTL="$3" 7 | 8 | "${DIR}"/__add_remove_format_dysk.sh "${account}" "${key}" "${DYSKCTL}" "10" "FORMAT" 9 | -------------------------------------------------------------------------------- /tools/verification/v_add_remove_128dysks.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" 4 | account="$1" 5 | key="$2" 6 | DYSKCTL="$3" 7 | 8 | "${DIR}"/__add_remove_format_dysk.sh "${account}" "${key}" "${DYSKCTL}" "128" "NO FORMAT" 9 | -------------------------------------------------------------------------------- /kubernetes/csi/pvc-csi-dysk.yaml: -------------------------------------------------------------------------------- 1 | kind: PersistentVolumeClaim 2 | apiVersion: v1 3 | metadata: 4 | name: pvc-csi-dysk 5 | spec: 6 | accessModes: 7 | - ReadWriteOnce 8 | resources: 9 | requests: 10 | storage: 5Gi 11 | storageClassName: csi-dysk 12 | -------------------------------------------------------------------------------- /tools/dysk_shortcuts.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | alias install_dysk="docker run --rm -it --privileged -v /usr/src:/usr/src -v /lib/modules:/lib/modules khenidak/dysk-installer:0.6" 3 | alias dyskctl="docker run --rm -it --privileged -v /etc/ssl/certs:/etc/ssl/certs:ro khenidak/dysk-cli:0.6" 4 | -------------------------------------------------------------------------------- /tools/flexvol-installer/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM alpine:3.5 2 | 3 | WORKDIR /bin 4 | 5 | RUN apk add --no-cache bash jq 6 | ADD ./dyskctl /bin/dyskctl 7 | ADD ./dysk /bin/dysk 8 | ADD ./install.sh /bin/install_dysk_flexvol.sh 9 | 10 | ENTRYPOINT ["/bin/install_dysk_flexvol.sh"] 11 | -------------------------------------------------------------------------------- /tools/verification/p_basic_io.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -eo pipefail 4 | DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" 5 | 6 | account="$1" 7 | key="$2" 8 | DYSKCTL="$3" 9 | 10 | 11 | "${DIR}"/__run_perf_test.sh "${account}" "${key}" ${DYSKCTL} "4096" "${DIR}/basic.fio" 12 | -------------------------------------------------------------------------------- /kubernetes/csi/pvc-csi-dysk-readonly.yaml: -------------------------------------------------------------------------------- 1 | kind: PersistentVolumeClaim 2 | apiVersion: v1 3 | metadata: 4 | name: pvc-csi-dysk-readonly 5 | spec: 6 | accessModes: 7 | - ReadOnlyMany 8 | resources: 9 | requests: 10 | storage: 5Gi 11 | volumeName: pv-csi-dysk-readonly 12 | storageClassName: "" 13 | -------------------------------------------------------------------------------- /tools/verification/basic.fio: -------------------------------------------------------------------------------- 1 | # The most basic form of data verification. Write the device randomly 2 | # in 4K chunks, then read it back and verify the contents. 3 | [write-and-verify] 4 | rw=randwrite 5 | bs=4k 6 | direct=1 7 | ioengine=libaio 8 | iodepth=16 9 | verify=crc32c 10 | size=1G 11 | filename=/mnt/dysk01/f.basic 12 | -------------------------------------------------------------------------------- /kubernetes/flexvolume/pvc-dysk-flexvol.yaml: -------------------------------------------------------------------------------- 1 | kind: PersistentVolumeClaim 2 | apiVersion: v1 3 | metadata: 4 | name: pvc-dysk-flexvol 5 | spec: 6 | accessModes: 7 | - ReadOnlyMany #also supports ReadWriteOnce 8 | resources: 9 | requests: 10 | storage: 10Gi 11 | volumeName: pv-dysk-flexvol 12 | storageClassName: "" 13 | -------------------------------------------------------------------------------- /tools/readme.md: -------------------------------------------------------------------------------- 1 | # dysk Tools # 2 | 3 | | Tool | Description | Status | 4 | |-------------|-----------------|------------| 5 | | dyskcli | containerized dyskcli | stable | 6 | | dysk-installer | container that builds + installs dysk kernel module according to host's kernel version | stable | 7 | | verification | verification + Perf tests | stable | 8 | 9 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | module/.* 2 | module/Module* 3 | module/dysk.ko 4 | *mod.c 5 | *.o* 6 | dyskctl/dyskctl 7 | dyskctl/vendor/github.com/khenidak/dysk/* 8 | 9 | #vi files 10 | # Swap 11 | [._]*.s[a-v][a-z] 12 | [._]*.sw[a-p] 13 | [._]s[a-v][a-z] 14 | [._]sw[a-p] 15 | 16 | # Session 17 | Session.vim 18 | 19 | # Temporary 20 | .netrwhist 21 | *~ 22 | # Auto-generated tag files 23 | tags 24 | -------------------------------------------------------------------------------- /dyskctl/vendor/github.com/hashicorp/hcl/hcl/parser/error.go: -------------------------------------------------------------------------------- 1 | package parser 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/hashicorp/hcl/hcl/token" 7 | ) 8 | 9 | // PosError is a parse error that contains a position. 10 | type PosError struct { 11 | Pos token.Pos 12 | Err error 13 | } 14 | 15 | func (e *PosError) Error() string { 16 | return fmt.Sprintf("At %s: %s", e.Pos, e.Err) 17 | } 18 | -------------------------------------------------------------------------------- /dyskctl/vendor/github.com/fsnotify/fsnotify/open_mode_bsd.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // +build freebsd openbsd netbsd dragonfly 6 | 7 | package fsnotify 8 | 9 | import "golang.org/x/sys/unix" 10 | 11 | const openMode = unix.O_NONBLOCK | unix.O_RDONLY 12 | -------------------------------------------------------------------------------- /dyskctl/vendor/github.com/fsnotify/fsnotify/open_mode_darwin.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // +build darwin 6 | 7 | package fsnotify 8 | 9 | import "golang.org/x/sys/unix" 10 | 11 | // note: this constant is not defined on BSD 12 | const openMode = unix.O_EVTONLY 13 | -------------------------------------------------------------------------------- /kubernetes/flexvolume/nginx-flex-dysk-readonly.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Pod 3 | metadata: 4 | name: nginx-flex-dysk 5 | spec: 6 | containers: 7 | - name: nginx-flex-dysk 8 | image: nginx 9 | volumeMounts: 10 | - name: flexvol-mount 11 | mountPath: /data 12 | volumes: 13 | - name: flexvol-mount 14 | persistentVolumeClaim: 15 | claimName: pvc-dysk-flexvol 16 | readOnly: true 17 | -------------------------------------------------------------------------------- /dyskctl/vendor/github.com/spf13/cobra/command_win.go: -------------------------------------------------------------------------------- 1 | // +build windows 2 | 3 | package cobra 4 | 5 | import ( 6 | "os" 7 | "time" 8 | 9 | "github.com/inconshreveable/mousetrap" 10 | ) 11 | 12 | var preExecHookFn = preExecHook 13 | 14 | func preExecHook(c *Command) { 15 | if MousetrapHelpText != "" && mousetrap.StartedByExplorer() { 16 | c.Print(MousetrapHelpText) 17 | time.Sleep(5 * time.Second) 18 | os.Exit(1) 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /kubernetes/csi/deployment/csi-dysk/README.md: -------------------------------------------------------------------------------- 1 | ## 1. Build csi-dysk image 2 | 3 | ``` 4 | make dysk 5 | docker build --no-cache -t andyzhangx/csi-dysk:1.0.0 -f ./app/dyskplugin/Dockerfile . 6 | #docker login 7 | docker push andyzhangx/csi-dysk:1.0.0 8 | ``` 9 | 10 | ## 2. Test csi-flexvol-installer image 11 | ``` 12 | docker run -it --name csi-dysk andyzhangx/csi-dysk:1.0.0 --nodeid=abc bash 13 | docker stop csi-dysk && docker rm csi-dysk 14 | ``` 15 | -------------------------------------------------------------------------------- /dyskctl/Gopkg.toml: -------------------------------------------------------------------------------- 1 | [[constraint]] 2 | name = "github.com/Azure/azure-sdk-for-go" 3 | version = "12.1.0-beta" 4 | 5 | [[constraint]] 6 | branch = "master" 7 | name = "github.com/rubiojr/go-vhd" 8 | 9 | [[constraint]] 10 | name = "github.com/spf13/cobra" 11 | version = "0.0.1" 12 | 13 | [[constraint]] 14 | name = "github.com/spf13/viper" 15 | version = "1.0.0" 16 | 17 | [prune] 18 | non-go = true 19 | go-tests = true 20 | unused-packages = true -------------------------------------------------------------------------------- /kubernetes/csi/nginx-pod-csi-dysk.yaml: -------------------------------------------------------------------------------- 1 | kind: Pod 2 | apiVersion: v1 3 | metadata: 4 | name: nginx-csi-dysk 5 | spec: 6 | containers: 7 | - image: nginx 8 | name: nginx-csi-dysk 9 | command: 10 | - "/bin/sh" 11 | - "-c" 12 | - while true; do echo $(date) >> /mnt/disk/outfile; sleep 1; done 13 | volumeMounts: 14 | - name: disk01 15 | mountPath: /mnt/disk 16 | volumes: 17 | - name: disk01 18 | persistentVolumeClaim: 19 | claimName: pvc-csi-dysk 20 | -------------------------------------------------------------------------------- /kubernetes/flexvolume/pv-dysk-flexvol.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: PersistentVolume 3 | metadata: 4 | name: pv-dysk-flexvol 5 | spec: 6 | capacity: 7 | storage: 100Gi 8 | accessModes: 9 | - ReadOnlyMany #ReadWriteOnce is also supported 10 | persistentVolumeReclaimPolicy: Retain 11 | flexVolume: 12 | driver: "azure/dysk" 13 | readOnly: true 14 | fsType: ext4 15 | secretRef: 16 | name: dyskcreds 17 | options: 18 | container: CONTAINER-NAME 19 | blob: NAME.vhd 20 | -------------------------------------------------------------------------------- /kubernetes/csi/pv-csi-dysk-readonly.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: PersistentVolume 3 | metadata: 4 | name: pv-csi-dysk-readonly 5 | spec: 6 | capacity: 7 | storage: 5Gi 8 | accessModes: 9 | - ReadOnlyMany 10 | csi: 11 | driver: csi-dysk 12 | nodePublishSecretRef: 13 | name: dyskcreds 14 | namespace: default 15 | volumeAttributes: 16 | blob: DISKNAME.vhd 17 | container: dysks 18 | volumeHandle: ACCOUNT-NAME/dysks/DISKNAME.vhd 19 | persistentVolumeReclaimPolicy: Retain 20 | -------------------------------------------------------------------------------- /module/az.h: -------------------------------------------------------------------------------- 1 | #ifndef _AZ_H 2 | #define _AZ_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "dysk_bdd.h" 10 | 11 | void test_request(void); 12 | 13 | 14 | // Module init/teardown 15 | int az_init(void); 16 | void az_teardown(void); 17 | // Init and tear routines (for every dysk) 18 | int az_init_for_dysk(dysk *d); 19 | void az_teardown_for_dysk(dysk *d); 20 | 21 | int az_do_request(dysk *d, struct request *req); 22 | 23 | #endif 24 | -------------------------------------------------------------------------------- /pkg/client/types.go: -------------------------------------------------------------------------------- 1 | package client 2 | 3 | type DyskType string 4 | 5 | const ( 6 | ReadOnly DyskType = "R" 7 | ReadWrite DyskType = "RW" 8 | ) 9 | 10 | type Dysk struct { 11 | Type DyskType 12 | Name string 13 | sectorCount uint64 14 | AccountName string 15 | Sas string 16 | Path string 17 | host string 18 | ip string 19 | LeaseId string 20 | Major int 21 | Minor int 22 | Vhd bool 23 | SizeGB int 24 | AccountRealm string 25 | } 26 | -------------------------------------------------------------------------------- /tools/verification/readme.md: -------------------------------------------------------------------------------- 1 | # dysk Verification # 2 | 3 | ## Configuration ## 4 | 5 | Modify ./settings.json file by adding your storage account name and key 6 | 7 | ## Running the verification ## 8 | 9 | ``` 10 | ./verify.sh 11 | ``` 12 | 13 | Or on the root of this repo 14 | 15 | ``` 16 | make verify #verification 17 | make verify-perf #perf test 18 | ``` 19 | 20 | 21 | > The verification is long running ~5mins. And does not perform storage account clean up. To clean clean remove "dysk" blob container. 22 | -------------------------------------------------------------------------------- /kubernetes/flexvolume/nginx-flex-dysk.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Pod 3 | metadata: 4 | name: nginx-flex-dysk 5 | spec: 6 | containers: 7 | - name: nginx-flex-dysk 8 | image: nginx 9 | volumeMounts: 10 | - name: test 11 | mountPath: /data 12 | volumes: 13 | - name: test 14 | flexVolume: 15 | driver: "azure/dysk" 16 | readOnly: false 17 | fsType: ext4 18 | secretRef: 19 | name: dyskcreds 20 | options: 21 | container: CONTAINER-NAME 22 | blob: NAME.vhd 23 | -------------------------------------------------------------------------------- /kubernetes/csi/nginx-pod-csi-dysk-readonly.yaml: -------------------------------------------------------------------------------- 1 | kind: Pod 2 | apiVersion: v1 3 | metadata: 4 | name: nginx-csi-dysk 5 | spec: 6 | containers: 7 | - image: nginx 8 | name: nginx-csi-dysk 9 | command: 10 | - "/bin/sh" 11 | - "-c" 12 | - while true; do echo $(date) >> /mnt/disk/outfile; sleep 1; done 13 | volumeMounts: 14 | - name: disk01 15 | mountPath: "/mnt/disk" 16 | volumes: 17 | - name: disk01 18 | persistentVolumeClaim: 19 | claimName: pvc-csi-dysk-readonly 20 | readOnly: true 21 | -------------------------------------------------------------------------------- /dyskctl/vendor/github.com/hashicorp/hcl/hcl.go: -------------------------------------------------------------------------------- 1 | // Package hcl decodes HCL into usable Go structures. 2 | // 3 | // hcl input can come in either pure HCL format or JSON format. 4 | // It can be parsed into an AST, and then decoded into a structure, 5 | // or it can be decoded directly from a string into a structure. 6 | // 7 | // If you choose to parse HCL into a raw AST, the benefit is that you 8 | // can write custom visitor implementations to implement custom 9 | // semantic checks. By default, HCL does not perform any semantic 10 | // checks. 11 | package hcl 12 | -------------------------------------------------------------------------------- /dyskctl/vendor/github.com/inconshreveable/mousetrap/trap_others.go: -------------------------------------------------------------------------------- 1 | // +build !windows 2 | 3 | package mousetrap 4 | 5 | // StartedByExplorer returns true if the program was invoked by the user 6 | // double-clicking on the executable from explorer.exe 7 | // 8 | // It is conservative and returns false if any of the internal calls fail. 9 | // It does not guarantee that the program was run from a terminal. It only can tell you 10 | // whether it was launched from explorer.exe 11 | // 12 | // On non-Windows platforms, it always returns false. 13 | func StartedByExplorer() bool { 14 | return false 15 | } 16 | -------------------------------------------------------------------------------- /pkg/client/common.go: -------------------------------------------------------------------------------- 1 | package client 2 | 3 | import ( 4 | "fmt" 5 | "regexp" 6 | ) 7 | 8 | func isValidDeviceName(deviceName string) error { 9 | if 0 == len(deviceName) { 10 | return fmt.Errorf("device name is empty") 11 | } 12 | 13 | if len(deviceName) > DEVICE_NAME_LEN { 14 | return fmt.Errorf("Device name %s is longer than %d chars", deviceName, DEVICE_NAME_LEN) 15 | } 16 | 17 | numbers_alpha := regexp.MustCompile(`^[A-Za-z0-9.]+$`).MatchString 18 | 19 | if !numbers_alpha(deviceName) { 20 | return fmt.Errorf("Device name:%s is invalid only alpha + numnbers", deviceName) 21 | } 22 | return nil 23 | } 24 | -------------------------------------------------------------------------------- /dyskctl/vendor/github.com/inconshreveable/mousetrap/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2014 Alan Shreve 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | -------------------------------------------------------------------------------- /dyskctl/vendor/github.com/hashicorp/hcl/lex.go: -------------------------------------------------------------------------------- 1 | package hcl 2 | 3 | import ( 4 | "unicode" 5 | "unicode/utf8" 6 | ) 7 | 8 | type lexModeValue byte 9 | 10 | const ( 11 | lexModeUnknown lexModeValue = iota 12 | lexModeHcl 13 | lexModeJson 14 | ) 15 | 16 | // lexMode returns whether we're going to be parsing in JSON 17 | // mode or HCL mode. 18 | func lexMode(v []byte) lexModeValue { 19 | var ( 20 | r rune 21 | w int 22 | offset int 23 | ) 24 | 25 | for { 26 | r, w = utf8.DecodeRune(v[offset:]) 27 | offset += w 28 | if unicode.IsSpace(r) { 29 | continue 30 | } 31 | if r == '{' { 32 | return lexModeJson 33 | } 34 | break 35 | } 36 | 37 | return lexModeHcl 38 | } 39 | -------------------------------------------------------------------------------- /dyskctl/vendor/github.com/Azure/azure-sdk-for-go/storage/version.go: -------------------------------------------------------------------------------- 1 | package storage 2 | 3 | // Copyright 2017 Microsoft Corporation 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | var ( 18 | sdkVersion = "v12.2.0-beta" 19 | ) 20 | -------------------------------------------------------------------------------- /tools/flexvol-installer/install.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -eo pipefail 4 | 5 | target_dir="${TARGET_DIR}" 6 | 7 | if [[ -z "${target_dir}" ]];then 8 | echo "target dir is not set. please set TARGET_DIR env var" 9 | exit 1 # if not set this will put the pod in crash loop 10 | fi 11 | 12 | dysk_vol_dir="${target_dir}/azure~dysk" 13 | mkdir -p ${dysk_vol_dir} 14 | 15 | #copy 16 | cp /bin/dyskctl ${dysk_vol_dir}/dyskctl #cli 17 | cp /bin/dysk ${dysk_vol_dir}/dysk #script 18 | cp /usr/bin/jq ${dysk_vol_dir}/jq 19 | 20 | 21 | 22 | 23 | #https://github.com/kubernetes/kubernetes/issues/17182 24 | # if we are running on kubernetes cluster as a daemon set we should 25 | # not exit otherwise, container will restart and goes into crashloop (even if exit code is 0) 26 | while true; do echo "install done, daemonset sleeping" && sleep 300; done 27 | 28 | -------------------------------------------------------------------------------- /dyskctl/vendor/github.com/spf13/afero/const_bsds.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2016 Steve Francia . 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // http://www.apache.org/licenses/LICENSE-2.0 7 | // 8 | // Unless required by applicable law or agreed to in writing, software 9 | // distributed under the License is distributed on an "AS IS" BASIS, 10 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | // +build darwin openbsd freebsd netbsd dragonfly 15 | 16 | package afero 17 | 18 | import ( 19 | "syscall" 20 | ) 21 | 22 | const BADFD = syscall.EBADF 23 | -------------------------------------------------------------------------------- /kubernetes/flexvolume/examples/nginx-statefulset.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1beta1 2 | kind: StatefulSet 3 | metadata: 4 | name: web 5 | spec: 6 | serviceName: "nginx" 7 | replicas: 32 8 | selector: 9 | matchLabels: 10 | app: nginx 11 | template: 12 | metadata: 13 | labels: 14 | app: nginx 15 | spec: 16 | containers: 17 | - name: nginx 18 | image: k8s.gcr.io/nginx-slim:0.8 19 | ports: 20 | - containerPort: 80 21 | name: web 22 | volumeMounts: 23 | - name: www 24 | mountPath: /mnt/dysk 25 | volumeClaimTemplates: 26 | - metadata: 27 | name: www 28 | spec: 29 | accessModes: [ "ReadWriteOnce" ] 30 | resources: 31 | requests: 32 | storage: 100Gi 33 | storageClassName: flexvoldysk01 34 | selector: 35 | matchLabels: 36 | pvCollection: pvC01 37 | -------------------------------------------------------------------------------- /dyskctl/vendor/github.com/pelletier/go-toml/position.go: -------------------------------------------------------------------------------- 1 | // Position support for go-toml 2 | 3 | package toml 4 | 5 | import ( 6 | "fmt" 7 | ) 8 | 9 | // Position of a document element within a TOML document. 10 | // 11 | // Line and Col are both 1-indexed positions for the element's line number and 12 | // column number, respectively. Values of zero or less will cause Invalid(), 13 | // to return true. 14 | type Position struct { 15 | Line int // line within the document 16 | Col int // column within the line 17 | } 18 | 19 | // String representation of the position. 20 | // Displays 1-indexed line and column numbers. 21 | func (p Position) String() string { 22 | return fmt.Sprintf("(%d, %d)", p.Line, p.Col) 23 | } 24 | 25 | // Invalid returns whether or not the position is valid (i.e. with negative or 26 | // null values) 27 | func (p Position) Invalid() bool { 28 | return p.Line <= 0 || p.Col <= 0 29 | } 30 | -------------------------------------------------------------------------------- /dyskctl/vendor/github.com/spf13/afero/const_win_unix.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2016 Steve Francia . 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // http://www.apache.org/licenses/LICENSE-2.0 7 | // 8 | // Unless required by applicable law or agreed to in writing, software 9 | // distributed under the License is distributed on an "AS IS" BASIS, 10 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | // +build !darwin 14 | // +build !openbsd 15 | // +build !freebsd 16 | // +build !dragonfly 17 | // +build !netbsd 18 | 19 | package afero 20 | 21 | import ( 22 | "syscall" 23 | ) 24 | 25 | const BADFD = syscall.EBADFD 26 | -------------------------------------------------------------------------------- /dyskctl/vendor/github.com/Azure/go-autorest/autorest/adal/msi.go: -------------------------------------------------------------------------------- 1 | // +build !windows 2 | 3 | package adal 4 | 5 | // Copyright 2017 Microsoft Corporation 6 | // 7 | // Licensed under the Apache License, Version 2.0 (the "License"); 8 | // you may not use this file except in compliance with the License. 9 | // You may obtain a copy of the License at 10 | // 11 | // http://www.apache.org/licenses/LICENSE-2.0 12 | // 13 | // Unless required by applicable law or agreed to in writing, software 14 | // distributed under the License is distributed on an "AS IS" BASIS, 15 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | // See the License for the specific language governing permissions and 17 | // limitations under the License. 18 | 19 | // msiPath is the path to the MSI Extension settings file (to discover the endpoint) 20 | var msiPath = "/var/lib/waagent/ManagedIdentity-Settings" 21 | -------------------------------------------------------------------------------- /dyskctl/vendor/github.com/pelletier/go-toml/doc.go: -------------------------------------------------------------------------------- 1 | // Package toml is a TOML parser and manipulation library. 2 | // 3 | // This version supports the specification as described in 4 | // https://github.com/toml-lang/toml/blob/master/versions/en/toml-v0.4.0.md 5 | // 6 | // Marshaling 7 | // 8 | // Go-toml can marshal and unmarshal TOML documents from and to data 9 | // structures. 10 | // 11 | // TOML document as a tree 12 | // 13 | // Go-toml can operate on a TOML document as a tree. Use one of the Load* 14 | // functions to parse TOML data and obtain a Tree instance, then one of its 15 | // methods to manipulate the tree. 16 | // 17 | // JSONPath-like queries 18 | // 19 | // The package github.com/pelletier/go-toml/query implements a system 20 | // similar to JSONPath to quickly retrive elements of a TOML document using a 21 | // single expression. See the package documentation for more information. 22 | // 23 | package toml 24 | -------------------------------------------------------------------------------- /tools/verification/v_simple_add_remove.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -eo pipefail 4 | account="$1" 5 | key="$2" 6 | DYSKCTL="$3" 7 | 8 | 9 | echo "Adding an auto create disk 4 gb" 10 | device_name=$(sudo ${DYSKCTL} mount auto-create -a "${account}" -k "${key}" --size 4 -o json | jq -r '.Name' || echo -n "") 11 | 12 | if [[ -z "$device_name" ]]; then 13 | echo "Test failed" 14 | exit 1 15 | fi 16 | 17 | echo "Added deviceName:$device_name" 18 | 19 | if [[ -z "$(lsblk | grep "$device_name" || echo -n "")" ]]; then 20 | echo "Test failed: Unable to find $device_name in blk devices" 21 | lsblk 22 | exit 1 23 | else 24 | echo "$device_name found in blk devices" 25 | fi 26 | 27 | echo "Removing deviceName:$device_name" 28 | sudo ${DYSKCTL} unmount -d "$device_name" 29 | 30 | if [[ ! -z "$(lsblk | grep "$device_name" || echo -n "")" ]]; then 31 | echo "Test failed: $device_name STILL in blk devices" 32 | lsblk 33 | exit 1 34 | fi 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /dyskctl/vendor/github.com/magiconair/properties/integrate.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017 Frank Schroeder. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package properties 6 | 7 | import "flag" 8 | 9 | // MustFlag sets flags that are skipped by dst.Parse when p contains 10 | // the respective key for flag.Flag.Name. 11 | // 12 | // It's use is recommended with command line arguments as in: 13 | // flag.Parse() 14 | // p.MustFlag(flag.CommandLine) 15 | func (p *Properties) MustFlag(dst *flag.FlagSet) { 16 | m := make(map[string]*flag.Flag) 17 | dst.VisitAll(func(f *flag.Flag) { 18 | m[f.Name] = f 19 | }) 20 | dst.Visit(func(f *flag.Flag) { 21 | delete(m, f.Name) // overridden 22 | }) 23 | 24 | for name, f := range m { 25 | v, ok := p.Get(name) 26 | if !ok { 27 | continue 28 | } 29 | 30 | if err := f.Value.Set(v); err != nil { 31 | ErrorHandler(err) 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /dyskctl/vendor/github.com/Azure/go-autorest/autorest/date/utility.go: -------------------------------------------------------------------------------- 1 | package date 2 | 3 | // Copyright 2017 Microsoft Corporation 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | import ( 18 | "strings" 19 | "time" 20 | ) 21 | 22 | // ParseTime to parse Time string to specified format. 23 | func ParseTime(format string, t string) (d time.Time, err error) { 24 | return time.Parse(format, strings.ToUpper(t)) 25 | } 26 | -------------------------------------------------------------------------------- /dyskctl/cmd/rootCmd.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "fmt" 5 | "math/rand" 6 | "os" 7 | "time" 8 | 9 | "github.com/spf13/cobra" 10 | ) 11 | 12 | var output_format = "" 13 | var rootCmd = &cobra.Command{ 14 | Use: "dyskctl mount ", 15 | Short: "dyskctl allows interactions with the dysk kernel module", 16 | Long: `This application interacts with the dysk kernel module 17 | http://github.com/khenidak/dysk/ in order 18 | to mount/unmount Azure storage as block devices. 19 | 20 | Note: default permission on the device file is for root only. You 21 | will need to sudo while executing dyskctl or change the permission 22 | on the /dev/dysk device file. 23 | `, 24 | } 25 | 26 | // Execute executes the root command. 27 | func Execute() { 28 | if err := rootCmd.Execute(); err != nil { 29 | fmt.Println(err) 30 | os.Exit(1) 31 | } 32 | } 33 | 34 | func init() { 35 | rand.Seed(time.Now().UnixNano()) 36 | rootCmd.PersistentFlags().StringVarP(&output_format, "output", "o", "table", "output format") 37 | } 38 | -------------------------------------------------------------------------------- /dyskctl/vendor/github.com/magiconair/properties/rangecheck.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017 Frank Schroeder. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package properties 6 | 7 | import ( 8 | "fmt" 9 | "math" 10 | ) 11 | 12 | // make this a var to overwrite it in a test 13 | var is32Bit = ^uint(0) == math.MaxUint32 14 | 15 | // intRangeCheck checks if the value fits into the int type and 16 | // panics if it does not. 17 | func intRangeCheck(key string, v int64) int { 18 | if is32Bit && (v < math.MinInt32 || v > math.MaxInt32) { 19 | panic(fmt.Sprintf("Value %d for key %s out of range", v, key)) 20 | } 21 | return int(v) 22 | } 23 | 24 | // uintRangeCheck checks if the value fits into the uint type and 25 | // panics if it does not. 26 | func uintRangeCheck(key string, v uint64) uint { 27 | if is32Bit && v > math.MaxUint32 { 28 | panic(fmt.Sprintf("Value %d for key %s out of range", v, key)) 29 | } 30 | return uint(v) 31 | } 32 | -------------------------------------------------------------------------------- /dyskctl/vendor/github.com/Azure/go-autorest/autorest/adal/msi_windows.go: -------------------------------------------------------------------------------- 1 | // +build windows 2 | 3 | package adal 4 | 5 | // Copyright 2017 Microsoft Corporation 6 | // 7 | // Licensed under the Apache License, Version 2.0 (the "License"); 8 | // you may not use this file except in compliance with the License. 9 | // You may obtain a copy of the License at 10 | // 11 | // http://www.apache.org/licenses/LICENSE-2.0 12 | // 13 | // Unless required by applicable law or agreed to in writing, software 14 | // distributed under the License is distributed on an "AS IS" BASIS, 15 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | // See the License for the specific language governing permissions and 17 | // limitations under the License. 18 | 19 | import ( 20 | "os" 21 | "strings" 22 | ) 23 | 24 | // msiPath is the path to the MSI Extension settings file (to discover the endpoint) 25 | var msiPath = strings.Join([]string{os.Getenv("SystemDrive"), "WindowsAzure/Config/ManagedIdentity-Settings"}, "/") 26 | -------------------------------------------------------------------------------- /module/dysk_utils.h: -------------------------------------------------------------------------------- 1 | #ifndef _DYSK_UTILS_H 2 | #define _DYSK_UTILS_H 3 | 4 | 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | //Hash 11 | #include 12 | #include 13 | #include 14 | // Time 15 | #include 16 | 17 | 18 | 19 | int utc_RFC1123_date(char *buf, size_t len); 20 | 21 | //IPv4 as unsigned int 22 | unsigned int inet_addr(char *ip); 23 | 24 | // Calc a HMAC 25 | int calc_hmac(struct crypto_shash *tfm, unsigned char *digest, const unsigned char *key, unsigned int keylen, const unsigned char *buf, unsigned int buflen); 26 | 27 | // Base64 28 | unsigned char *base64_encode(const unsigned char *src, size_t len, size_t *out_len); 29 | unsigned char *base64_decode(const unsigned char *src, size_t len, size_t *out_len); 30 | 31 | // Finds something, copies everything before it to [to] returns len of copied or -1 32 | int get_until(char *haystack, const char *until, char *to, size_t max); 33 | 34 | 35 | #endif 36 | 37 | 38 | -------------------------------------------------------------------------------- /dyskctl/vendor/github.com/hashicorp/hcl/parse.go: -------------------------------------------------------------------------------- 1 | package hcl 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/hashicorp/hcl/hcl/ast" 7 | hclParser "github.com/hashicorp/hcl/hcl/parser" 8 | jsonParser "github.com/hashicorp/hcl/json/parser" 9 | ) 10 | 11 | // ParseBytes accepts as input byte slice and returns ast tree. 12 | // 13 | // Input can be either JSON or HCL 14 | func ParseBytes(in []byte) (*ast.File, error) { 15 | return parse(in) 16 | } 17 | 18 | // ParseString accepts input as a string and returns ast tree. 19 | func ParseString(input string) (*ast.File, error) { 20 | return parse([]byte(input)) 21 | } 22 | 23 | func parse(in []byte) (*ast.File, error) { 24 | switch lexMode(in) { 25 | case lexModeHcl: 26 | return hclParser.Parse(in) 27 | case lexModeJson: 28 | return jsonParser.Parse(in) 29 | } 30 | 31 | return nil, fmt.Errorf("unknown config format") 32 | } 33 | 34 | // Parse parses the given input and returns the root object. 35 | // 36 | // The input format can be either HCL or JSON. 37 | func Parse(input string) (*ast.File, error) { 38 | return parse([]byte(input)) 39 | } 40 | -------------------------------------------------------------------------------- /dyskctl/vendor/github.com/dgrijalva/jwt-go/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012 Dave Grijalva 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | 9 | -------------------------------------------------------------------------------- /examples/102-mount-existing/readme.md: -------------------------------------------------------------------------------- 1 | # Mount an existing page blob 2 | 3 | > The steps below create page blob then mount it. You can mount an existing **unattached** page blob data disk (not managed disk) 4 | 5 | 1. Create page blob - 1TB 6 | 7 | ``` 8 | sudo dyskctl create -a "${ACCOUNT}" -k "${KEY}" --size 1024 --auto-lease -o json > dysk.json 9 | 10 | #file.json now contains dysk definition as json file 11 | ``` 12 | 13 | 2. Use mount file command to mount it 14 | 15 | ``` 16 | sudo dyskctl mount-file -file ./dysk.json 17 | ``` 18 | Alternatively, you can directly use mount command to mount an existing page blob as dysk 19 | 20 | ``` 21 | sudo dyskctl mount -a ${ACCOUNT} -l {KEY} --pageblob-name {PAGEBLOBNAME} --container-name {CONTAINERNAME} --auto-lease 22 | ``` 23 | 24 | If the page blob was leased you can supply lease via ```--leaseid``` argument or use ```--break-lease``` to break the existing lease and create a new lease. Note: Breaking lease can be dangrous if applications are using it (and can not handle losing lease). 25 | 26 | > follow [101-mount-create](../101-mount-create/readme.md) to format and use the disk 27 | -------------------------------------------------------------------------------- /dyskctl/vendor/github.com/fsnotify/fsnotify/fen.go: -------------------------------------------------------------------------------- 1 | // Copyright 2010 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // +build solaris 6 | 7 | package fsnotify 8 | 9 | import ( 10 | "errors" 11 | ) 12 | 13 | // Watcher watches a set of files, delivering events to a channel. 14 | type Watcher struct { 15 | Events chan Event 16 | Errors chan error 17 | } 18 | 19 | // NewWatcher establishes a new watcher with the underlying OS and begins waiting for events. 20 | func NewWatcher() (*Watcher, error) { 21 | return nil, errors.New("FEN based watcher not yet supported for fsnotify\n") 22 | } 23 | 24 | // Close removes all watches and closes the events channel. 25 | func (w *Watcher) Close() error { 26 | return nil 27 | } 28 | 29 | // Add starts watching the named file or directory (non-recursively). 30 | func (w *Watcher) Add(name string) error { 31 | return nil 32 | } 33 | 34 | // Remove stops watching the the named file or directory (non-recursively). 35 | func (w *Watcher) Remove(name string) error { 36 | return nil 37 | } 38 | -------------------------------------------------------------------------------- /dyskctl/vendor/github.com/spf13/afero/mem/dir.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2014 Steve Francia . 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // http://www.apache.org/licenses/LICENSE-2.0 7 | // 8 | // Unless required by applicable law or agreed to in writing, software 9 | // distributed under the License is distributed on an "AS IS" BASIS, 10 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package mem 15 | 16 | type Dir interface { 17 | Len() int 18 | Names() []string 19 | Files() []*FileData 20 | Add(*FileData) 21 | Remove(*FileData) 22 | } 23 | 24 | func RemoveFromMemDir(dir *FileData, f *FileData) { 25 | dir.memDir.Remove(f) 26 | } 27 | 28 | func AddToMemDir(dir *FileData, f *FileData) { 29 | dir.memDir.Add(f) 30 | } 31 | 32 | func InitializeDir(d *FileData) { 33 | if d.memDir == nil { 34 | d.dir = true 35 | d.memDir = &DirMap{} 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /dyskctl/vendor/github.com/marstr/guid/LICENSE.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 Martin Strobel 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /dyskctl/vendor/github.com/spf13/cast/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Steve Francia 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /dyskctl/vendor/github.com/spf13/viper/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Steve Francia 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /dyskctl/vendor/github.com/satori/go.uuid/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (C) 2013-2016 by Maxim Bublis 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /dyskctl/vendor/github.com/spf13/jwalterweatherman/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Steve Francia 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /dyskctl/vendor/github.com/rubiojr/go-vhd/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Sergio Rubio 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /dyskctl/vendor/github.com/mitchellh/mapstructure/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2013 Mitchell Hashimoto 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /dyskctl/vendor/github.com/pelletier/go-toml/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2013 - 2017 Thomas Pelletier, Eric Anderton 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /license.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) Microsoft Corporation. All rights reserved. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE 22 | -------------------------------------------------------------------------------- /dyskctl/vendor/github.com/Azure/azure-sdk-for-go/storage/commonsasuri.go: -------------------------------------------------------------------------------- 1 | package storage 2 | 3 | // Copyright 2017 Microsoft Corporation 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | import ( 18 | "net/url" 19 | "time" 20 | ) 21 | 22 | // SASOptions includes options used by SAS URIs for different 23 | // services and resources. 24 | type SASOptions struct { 25 | APIVersion string 26 | Start time.Time 27 | Expiry time.Time 28 | IP string 29 | UseHTTPS bool 30 | Identifier string 31 | } 32 | 33 | func addQueryParameter(query url.Values, key, value string) url.Values { 34 | if value != "" { 35 | query.Add(key, value) 36 | } 37 | return query 38 | } 39 | -------------------------------------------------------------------------------- /tools/verification/__add_remove_format_dysk.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -eo pipefail 4 | account="$1" 5 | key="$2" 6 | DYSKCTL="$3" 7 | COUNT="$4" 8 | FORMAT="$5" 9 | echo "COUNT:$COUNT $FORMAT" 10 | 11 | for (( idx=1; idx<=${COUNT}; idx++)); 12 | do 13 | echo "at ${idx}/${COUNT}" 14 | echo "Adding an auto create disk 1 gb" 15 | device_name=$(sudo ${DYSKCTL} mount auto-create -a "${account}" -k "${key}" --size 1 -o json | jq -r '.Name' || echo -n "") 16 | 17 | if [[ -z "$device_name" ]]; then 18 | echo "Test failed" 19 | exit 1 20 | fi 21 | 22 | echo "Added deviceName:$device_name" 23 | 24 | if [[ -z "$(lsblk | grep "$device_name" || echo -n "")" ]]; then 25 | echo "Test failed: Unable to find $device_name in blk devices" 26 | lsblk 27 | exit 1 28 | else 29 | echo "$device_name found in blk devices" 30 | fi 31 | 32 | if [[ "FORMAT" == "${FORMAT}" ]];then 33 | echo "Formatting: ${device_name}" 34 | sudo mkfs.ext4 /dev/${device_name} 35 | fi 36 | 37 | echo "Removing deviceName:$device_name" 38 | sudo ${DYSKCTL} unmount -d "$device_name" 39 | 40 | if [[ ! -z "$(lsblk | grep "$device_name" || echo -n "")" ]]; then 41 | echo "Test failed: $device_name STILL in blk devices" 42 | lsblk 43 | exit 1 44 | fi 45 | 46 | done 47 | -------------------------------------------------------------------------------- /dyskctl/vendor/github.com/mitchellh/mapstructure/error.go: -------------------------------------------------------------------------------- 1 | package mapstructure 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "sort" 7 | "strings" 8 | ) 9 | 10 | // Error implements the error interface and can represents multiple 11 | // errors that occur in the course of a single decode. 12 | type Error struct { 13 | Errors []string 14 | } 15 | 16 | func (e *Error) Error() string { 17 | points := make([]string, len(e.Errors)) 18 | for i, err := range e.Errors { 19 | points[i] = fmt.Sprintf("* %s", err) 20 | } 21 | 22 | sort.Strings(points) 23 | return fmt.Sprintf( 24 | "%d error(s) decoding:\n\n%s", 25 | len(e.Errors), strings.Join(points, "\n")) 26 | } 27 | 28 | // WrappedErrors implements the errwrap.Wrapper interface to make this 29 | // return value more useful with the errwrap and go-multierror libraries. 30 | func (e *Error) WrappedErrors() []error { 31 | if e == nil { 32 | return nil 33 | } 34 | 35 | result := make([]error, len(e.Errors)) 36 | for i, e := range e.Errors { 37 | result[i] = errors.New(e) 38 | } 39 | 40 | return result 41 | } 42 | 43 | func appendErrors(errors []string, err error) []string { 44 | switch e := err.(type) { 45 | case *Error: 46 | return append(errors, e.Errors...) 47 | default: 48 | return append(errors, e.Error()) 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /dyskctl/vendor/github.com/dgrijalva/jwt-go/signing_method.go: -------------------------------------------------------------------------------- 1 | package jwt 2 | 3 | import ( 4 | "sync" 5 | ) 6 | 7 | var signingMethods = map[string]func() SigningMethod{} 8 | var signingMethodLock = new(sync.RWMutex) 9 | 10 | // Implement SigningMethod to add new methods for signing or verifying tokens. 11 | type SigningMethod interface { 12 | Verify(signingString, signature string, key interface{}) error // Returns nil if signature is valid 13 | Sign(signingString string, key interface{}) (string, error) // Returns encoded signature or error 14 | Alg() string // returns the alg identifier for this method (example: 'HS256') 15 | } 16 | 17 | // Register the "alg" name and a factory function for signing method. 18 | // This is typically done during init() in the method's implementation 19 | func RegisterSigningMethod(alg string, f func() SigningMethod) { 20 | signingMethodLock.Lock() 21 | defer signingMethodLock.Unlock() 22 | 23 | signingMethods[alg] = f 24 | } 25 | 26 | // Get a signing method from an "alg" string 27 | func GetSigningMethod(alg string) (method SigningMethod) { 28 | signingMethodLock.RLock() 29 | defer signingMethodLock.RUnlock() 30 | 31 | if methodF, ok := signingMethods[alg]; ok { 32 | method = methodF() 33 | } 34 | return 35 | } 36 | -------------------------------------------------------------------------------- /tools/verification/v_add_format_remove_add.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Adds a disk 3 | # formats the disk 4 | # removes that disk 5 | # adds another disk 6 | 7 | set -eo pipefail 8 | DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" 9 | account="$1" 10 | key="$2" 11 | DYSKCTL="$3" 12 | 13 | 14 | echo "Adding an auto create disk 1 gb" 15 | device_name=$(sudo ${DYSKCTL} mount auto-create -a "${account}" -k "${key}" --size 1 -o json | jq -r '.Name' || echo -n "") 16 | 17 | if [[ -z "$device_name" ]]; then 18 | echo "Test failed" 19 | exit 1 20 | fi 21 | 22 | echo "Added deviceName:$device_name" 23 | 24 | if [[ -z "$(lsblk | grep "$device_name" || echo -n "")" ]]; then 25 | echo "Test failed: Unable to find $device_name in blk devices" 26 | lsblk 27 | exit 1 28 | else 29 | echo "$device_name found in blk devices" 30 | fi 31 | 32 | echo "formatting.." 33 | sudo mkfs.ext4 /dev/${device_name} 34 | 35 | echo "Removing *formatted* deviceName:$device_name" 36 | sudo ${DYSKCTL} unmount -d "$device_name" 37 | 38 | if [[ ! -z "$(lsblk | grep "$device_name" || echo -n "")" ]]; then 39 | echo "Test failed: $device_name STILL in blk devices" 40 | lsblk 41 | exit 1 42 | fi 43 | 44 | ## Calling simle add remove 45 | echo "calling simple add remove script" 46 | "${DIR}"/v_simple_add_remove.sh "${account}" "${key}" "${DYSKCTL}" 47 | 48 | -------------------------------------------------------------------------------- /dyskctl/Makefile: -------------------------------------------------------------------------------- 1 | binary := dyskctl 2 | 3 | all: clean deps build authors 4 | 5 | .PHONY: build 6 | build: ## Builds the `dyskctl` executable 7 | @echo "Building..." 8 | $Q cp -Rf cmd vendor/github.com/khenidak/dysk/dyskctl/ 9 | $Q cp -Rf main.go vendor/github.com/khenidak/dysk/dyskctl/ 10 | $Q cp -Rf ../pkg/client vendor/github.com/khenidak/dysk/pkg/ 11 | $Q CGO_ENABLED=0 go build . 12 | 13 | .PHONY: deps 14 | deps: ## Runs `dep ensure` 15 | @echo "Ensuring Dependencies..." 16 | $Q go env 17 | $Q dep ensure 18 | 19 | .PHONY: clean 20 | clean: ## Cleanup any build binaries 21 | @echo "Clean..." 22 | $Q rm -rf $(binary) 23 | 24 | .PHONY: fmt 25 | fmt: ## Verifies all files have been `gofmt`ed 26 | @echo "+ $@" 27 | @gofmt -s -l . | grep -v vendor | tee /dev/stderr 28 | 29 | .PHONY: lint 30 | lint: ## Verifies `golint` passes 31 | @echo "+ $@" 32 | @golint ./... | grep -v vendor | tee /dev/stderr 33 | 34 | .PHONY: authors 35 | authors: 36 | $Q git log --all --format='%aN <%cE>' | sort -u | sed -n '/github/!p' > GITAUTHORS 37 | $Q cat AUTHORS GITAUTHORS | sort -u > NEWAUTHORS 38 | $Q mv NEWAUTHORS AUTHORS 39 | $Q rm -f NEWAUTHORS 40 | $Q rm -f GITAUTHORS 41 | 42 | .PHONY: help 43 | help: ## Prints out this help information 44 | @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' -------------------------------------------------------------------------------- /dyskctl/vendor/github.com/inconshreveable/mousetrap/trap_windows_1.4.go: -------------------------------------------------------------------------------- 1 | // +build windows 2 | // +build go1.4 3 | 4 | package mousetrap 5 | 6 | import ( 7 | "os" 8 | "syscall" 9 | "unsafe" 10 | ) 11 | 12 | func getProcessEntry(pid int) (*syscall.ProcessEntry32, error) { 13 | snapshot, err := syscall.CreateToolhelp32Snapshot(syscall.TH32CS_SNAPPROCESS, 0) 14 | if err != nil { 15 | return nil, err 16 | } 17 | defer syscall.CloseHandle(snapshot) 18 | var procEntry syscall.ProcessEntry32 19 | procEntry.Size = uint32(unsafe.Sizeof(procEntry)) 20 | if err = syscall.Process32First(snapshot, &procEntry); err != nil { 21 | return nil, err 22 | } 23 | for { 24 | if procEntry.ProcessID == uint32(pid) { 25 | return &procEntry, nil 26 | } 27 | err = syscall.Process32Next(snapshot, &procEntry) 28 | if err != nil { 29 | return nil, err 30 | } 31 | } 32 | } 33 | 34 | // StartedByExplorer returns true if the program was invoked by the user double-clicking 35 | // on the executable from explorer.exe 36 | // 37 | // It is conservative and returns false if any of the internal calls fail. 38 | // It does not guarantee that the program was run from a terminal. It only can tell you 39 | // whether it was launched from explorer.exe 40 | func StartedByExplorer() bool { 41 | pe, err := getProcessEntry(os.Getppid()) 42 | if err != nil { 43 | return false 44 | } 45 | return "explorer.exe" == syscall.UTF16ToString(pe.ExeFile[:]) 46 | } 47 | -------------------------------------------------------------------------------- /dyskctl/vendor/github.com/hashicorp/hcl/hcl/token/position.go: -------------------------------------------------------------------------------- 1 | package token 2 | 3 | import "fmt" 4 | 5 | // Pos describes an arbitrary source position 6 | // including the file, line, and column location. 7 | // A Position is valid if the line number is > 0. 8 | type Pos struct { 9 | Filename string // filename, if any 10 | Offset int // offset, starting at 0 11 | Line int // line number, starting at 1 12 | Column int // column number, starting at 1 (character count) 13 | } 14 | 15 | // IsValid returns true if the position is valid. 16 | func (p *Pos) IsValid() bool { return p.Line > 0 } 17 | 18 | // String returns a string in one of several forms: 19 | // 20 | // file:line:column valid position with file name 21 | // line:column valid position without file name 22 | // file invalid position with file name 23 | // - invalid position without file name 24 | func (p Pos) String() string { 25 | s := p.Filename 26 | if p.IsValid() { 27 | if s != "" { 28 | s += ":" 29 | } 30 | s += fmt.Sprintf("%d:%d", p.Line, p.Column) 31 | } 32 | if s == "" { 33 | s = "-" 34 | } 35 | return s 36 | } 37 | 38 | // Before reports whether the position p is before u. 39 | func (p Pos) Before(u Pos) bool { 40 | return u.Offset > p.Offset || u.Line > p.Line 41 | } 42 | 43 | // After reports whether the position p is after u. 44 | func (p Pos) After(u Pos) bool { 45 | return u.Offset < p.Offset || u.Line < p.Line 46 | } 47 | -------------------------------------------------------------------------------- /dyskctl/vendor/gopkg.in/yaml.v2/LICENSE.libyaml: -------------------------------------------------------------------------------- 1 | The following files were ported to Go from C files of libyaml, and thus 2 | are still covered by their original copyright and license: 3 | 4 | apic.go 5 | emitterc.go 6 | parserc.go 7 | readerc.go 8 | scannerc.go 9 | writerc.go 10 | yamlh.go 11 | yamlprivateh.go 12 | 13 | Copyright (c) 2006 Kirill Simonov 14 | 15 | Permission is hereby granted, free of charge, to any person obtaining a copy of 16 | this software and associated documentation files (the "Software"), to deal in 17 | the Software without restriction, including without limitation the rights to 18 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 19 | of the Software, and to permit persons to whom the Software is furnished to do 20 | so, subject to the following conditions: 21 | 22 | The above copyright notice and this permission notice shall be included in all 23 | copies or substantial portions of the Software. 24 | 25 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 26 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 27 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 28 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 29 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 30 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 31 | SOFTWARE. 32 | -------------------------------------------------------------------------------- /dyskctl/vendor/github.com/hashicorp/hcl/json/token/position.go: -------------------------------------------------------------------------------- 1 | package token 2 | 3 | import "fmt" 4 | 5 | // Pos describes an arbitrary source position 6 | // including the file, line, and column location. 7 | // A Position is valid if the line number is > 0. 8 | type Pos struct { 9 | Filename string // filename, if any 10 | Offset int // offset, starting at 0 11 | Line int // line number, starting at 1 12 | Column int // column number, starting at 1 (character count) 13 | } 14 | 15 | // IsValid returns true if the position is valid. 16 | func (p *Pos) IsValid() bool { return p.Line > 0 } 17 | 18 | // String returns a string in one of several forms: 19 | // 20 | // file:line:column valid position with file name 21 | // line:column valid position without file name 22 | // file invalid position with file name 23 | // - invalid position without file name 24 | func (p Pos) String() string { 25 | s := p.Filename 26 | if p.IsValid() { 27 | if s != "" { 28 | s += ":" 29 | } 30 | s += fmt.Sprintf("%d:%d", p.Line, p.Column) 31 | } 32 | if s == "" { 33 | s = "-" 34 | } 35 | return s 36 | } 37 | 38 | // Before reports whether the position p is before u. 39 | func (p Pos) Before(u Pos) bool { 40 | return u.Offset > p.Offset || u.Line > p.Line 41 | } 42 | 43 | // After reports whether the position p is after u. 44 | func (p Pos) After(u Pos) bool { 45 | return u.Offset < p.Offset || u.Line < p.Line 46 | } 47 | -------------------------------------------------------------------------------- /dyskctl/vendor/github.com/magiconair/properties/LICENSE: -------------------------------------------------------------------------------- 1 | goproperties - properties file decoder for Go 2 | 3 | Copyright (c) 2013-2014 - Frank Schroeder 4 | 5 | All rights reserved. 6 | 7 | Redistribution and use in source and binary forms, with or without 8 | modification, are permitted provided that the following conditions are met: 9 | 10 | 1. Redistributions of source code must retain the above copyright notice, this 11 | list of conditions and the following disclaimer. 12 | 2. Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 17 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 20 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 23 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 25 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | -------------------------------------------------------------------------------- /dyskctl/vendor/github.com/Azure/go-autorest/autorest/version.go: -------------------------------------------------------------------------------- 1 | package autorest 2 | 3 | // Copyright 2017 Microsoft Corporation 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | import ( 18 | "bytes" 19 | "fmt" 20 | "strings" 21 | "sync" 22 | ) 23 | 24 | const ( 25 | major = 8 26 | minor = 0 27 | patch = 0 28 | tag = "" 29 | ) 30 | 31 | var once sync.Once 32 | var version string 33 | 34 | // Version returns the semantic version (see http://semver.org). 35 | func Version() string { 36 | once.Do(func() { 37 | semver := fmt.Sprintf("%d.%d.%d", major, minor, patch) 38 | verBuilder := bytes.NewBufferString(semver) 39 | if tag != "" && tag != "-" { 40 | updated := strings.TrimPrefix(tag, "-") 41 | _, err := verBuilder.WriteString("-" + updated) 42 | if err == nil { 43 | verBuilder = bytes.NewBufferString(semver) 44 | } 45 | } 46 | version = verBuilder.String() 47 | }) 48 | return version 49 | } 50 | -------------------------------------------------------------------------------- /dyskctl/vendor/github.com/rubiojr/go-vhd/debian/copyright: -------------------------------------------------------------------------------- 1 | Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ 2 | Upstream-Name: go-vhd 3 | Source: https://github.com/rubiojr/go-vhd 4 | 5 | Files: * 6 | Copyright: 2015 7 | License: MIT 8 | 9 | Files: debian/* 10 | Copyright: 2015 Sergio 11 | License: MIT 12 | 13 | License: MIT 14 | Permission is hereby granted, free of charge, to any person obtaining a 15 | copy of this software and associated documentation files (the "Software"), 16 | to deal in the Software without restriction, including without limitation 17 | the rights to use, copy, modify, merge, publish, distribute, sublicense, 18 | and/or sell copies of the Software, and to permit persons to whom the 19 | Software is furnished to do so, subject to the following conditions: 20 | . 21 | The above copyright notice and this permission notice shall be included 22 | in all copies or substantial portions of the Software. 23 | . 24 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 25 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 26 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 27 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 28 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 29 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 30 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 31 | -------------------------------------------------------------------------------- /tools/verification/__run_perf_test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -eo pipefail 4 | DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" 5 | 6 | account="$1" 7 | key="$2" 8 | DYSKCTL="$3" 9 | DYSK_SIZE="$4" 10 | FIO_FILE="$5" 11 | 12 | sudo mkdir -p /mnt/dysk01 13 | 14 | echo "Adding an auto create disk 4 TB" 15 | device_name=$(sudo ${DYSKCTL} mount auto-create -a "${account}" -k "${key}" --size ${DYSK_SIZE} -o json | jq -r '.Name' || echo -n "") 16 | 17 | if [[ -z "$device_name" ]]; then 18 | echo "Test failed" 19 | exit 1 20 | fi 21 | 22 | echo "Added deviceName:$device_name" 23 | 24 | if [[ -z "$(lsblk | grep "$device_name" || echo -n "")" ]]; then 25 | echo "Test failed: Unable to find $device_name in blk devices" 26 | lsblk 27 | exit 1 28 | else 29 | echo "$device_name found in blk devices" 30 | fi 31 | 32 | 33 | echo "formatting /dev/${device_name}" 34 | sudo mkfs.ext4 /dev/${device_name} 35 | 36 | echo "mounting /dev/${device_name} to /mnt/dysk01" 37 | sudo mount -o '_netdev,x-systemd.device-bound' /dev/${device_name} /mnt/dysk01 38 | echo "running fio" 39 | 40 | sudo fio "${FIO_FILE}" 41 | 42 | echo "fio done!" 43 | echo "unmounting the mount point /mnt/dysk01" 44 | sudo umount /mnt/dysk01 45 | 46 | echo "Removing deviceName:$device_name" 47 | sudo ${DYSKCTL} unmount -d "$device_name" 48 | 49 | if [[ ! -z "$(lsblk | grep "$device_name" || echo -n "")" ]]; then 50 | echo "Test failed: $device_name STILL in blk devices" 51 | lsblk 52 | exit 1 53 | fi 54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /dyskctl/vendor/github.com/hashicorp/hcl/hcl/ast/walk.go: -------------------------------------------------------------------------------- 1 | package ast 2 | 3 | import "fmt" 4 | 5 | // WalkFunc describes a function to be called for each node during a Walk. The 6 | // returned node can be used to rewrite the AST. Walking stops the returned 7 | // bool is false. 8 | type WalkFunc func(Node) (Node, bool) 9 | 10 | // Walk traverses an AST in depth-first order: It starts by calling fn(node); 11 | // node must not be nil. If fn returns true, Walk invokes fn recursively for 12 | // each of the non-nil children of node, followed by a call of fn(nil). The 13 | // returned node of fn can be used to rewrite the passed node to fn. 14 | func Walk(node Node, fn WalkFunc) Node { 15 | rewritten, ok := fn(node) 16 | if !ok { 17 | return rewritten 18 | } 19 | 20 | switch n := node.(type) { 21 | case *File: 22 | n.Node = Walk(n.Node, fn) 23 | case *ObjectList: 24 | for i, item := range n.Items { 25 | n.Items[i] = Walk(item, fn).(*ObjectItem) 26 | } 27 | case *ObjectKey: 28 | // nothing to do 29 | case *ObjectItem: 30 | for i, k := range n.Keys { 31 | n.Keys[i] = Walk(k, fn).(*ObjectKey) 32 | } 33 | 34 | if n.Val != nil { 35 | n.Val = Walk(n.Val, fn) 36 | } 37 | case *LiteralType: 38 | // nothing to do 39 | case *ListType: 40 | for i, l := range n.List { 41 | n.List[i] = Walk(l, fn) 42 | } 43 | case *ObjectType: 44 | n.List = Walk(n.List, fn).(*ObjectList) 45 | default: 46 | // should we panic here? 47 | fmt.Printf("unknown type: %T\n", n) 48 | } 49 | 50 | fn(nil) 51 | return rewritten 52 | } 53 | -------------------------------------------------------------------------------- /dyskctl/vendor/github.com/spf13/jwalterweatherman/log_counter.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2016 Steve Francia . 2 | // 3 | // Use of this source code is governed by an MIT-style 4 | // license that can be found in the LICENSE file. 5 | 6 | package jwalterweatherman 7 | 8 | import ( 9 | "sync/atomic" 10 | ) 11 | 12 | type logCounter struct { 13 | counter uint64 14 | } 15 | 16 | func (c *logCounter) incr() { 17 | atomic.AddUint64(&c.counter, 1) 18 | } 19 | 20 | func (c *logCounter) resetCounter() { 21 | atomic.StoreUint64(&c.counter, 0) 22 | } 23 | 24 | func (c *logCounter) getCount() uint64 { 25 | return atomic.LoadUint64(&c.counter) 26 | } 27 | 28 | func (c *logCounter) Write(p []byte) (n int, err error) { 29 | c.incr() 30 | return len(p), nil 31 | } 32 | 33 | // LogCountForLevel returns the number of log invocations for a given threshold. 34 | func (n *Notepad) LogCountForLevel(l Threshold) uint64 { 35 | return n.logCounters[l].getCount() 36 | } 37 | 38 | // LogCountForLevelsGreaterThanorEqualTo returns the number of log invocations 39 | // greater than or equal to a given threshold. 40 | func (n *Notepad) LogCountForLevelsGreaterThanorEqualTo(threshold Threshold) uint64 { 41 | var cnt uint64 42 | 43 | for i := int(threshold); i < len(n.logCounters); i++ { 44 | cnt += n.LogCountForLevel(Threshold(i)) 45 | } 46 | 47 | return cnt 48 | } 49 | 50 | // ResetLogCounters resets the invocation counters for all levels. 51 | func (n *Notepad) ResetLogCounters() { 52 | for _, np := range n.logCounters { 53 | np.resetCounter() 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /dyskctl/vendor/github.com/spf13/afero/mem/dirmap.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2015 Steve Francia . 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // http://www.apache.org/licenses/LICENSE-2.0 7 | // 8 | // Unless required by applicable law or agreed to in writing, software 9 | // distributed under the License is distributed on an "AS IS" BASIS, 10 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package mem 15 | 16 | import "sort" 17 | 18 | type DirMap map[string]*FileData 19 | 20 | func (m DirMap) Len() int { return len(m) } 21 | func (m DirMap) Add(f *FileData) { m[f.name] = f } 22 | func (m DirMap) Remove(f *FileData) { delete(m, f.name) } 23 | func (m DirMap) Files() (files []*FileData) { 24 | for _, f := range m { 25 | files = append(files, f) 26 | } 27 | sort.Sort(filesSorter(files)) 28 | return files 29 | } 30 | 31 | // implement sort.Interface for []*FileData 32 | type filesSorter []*FileData 33 | 34 | func (s filesSorter) Len() int { return len(s) } 35 | func (s filesSorter) Swap(i, j int) { s[i], s[j] = s[j], s[i] } 36 | func (s filesSorter) Less(i, j int) bool { return s[i].name < s[j].name } 37 | 38 | func (m DirMap) Names() (names []string) { 39 | for x := range m { 40 | names = append(names, x) 41 | } 42 | return names 43 | } 44 | -------------------------------------------------------------------------------- /dyskctl/vendor/github.com/spf13/viper/flags.go: -------------------------------------------------------------------------------- 1 | package viper 2 | 3 | import "github.com/spf13/pflag" 4 | 5 | // FlagValueSet is an interface that users can implement 6 | // to bind a set of flags to viper. 7 | type FlagValueSet interface { 8 | VisitAll(fn func(FlagValue)) 9 | } 10 | 11 | // FlagValue is an interface that users can implement 12 | // to bind different flags to viper. 13 | type FlagValue interface { 14 | HasChanged() bool 15 | Name() string 16 | ValueString() string 17 | ValueType() string 18 | } 19 | 20 | // pflagValueSet is a wrapper around *pflag.ValueSet 21 | // that implements FlagValueSet. 22 | type pflagValueSet struct { 23 | flags *pflag.FlagSet 24 | } 25 | 26 | // VisitAll iterates over all *pflag.Flag inside the *pflag.FlagSet. 27 | func (p pflagValueSet) VisitAll(fn func(flag FlagValue)) { 28 | p.flags.VisitAll(func(flag *pflag.Flag) { 29 | fn(pflagValue{flag}) 30 | }) 31 | } 32 | 33 | // pflagValue is a wrapper aroung *pflag.flag 34 | // that implements FlagValue 35 | type pflagValue struct { 36 | flag *pflag.Flag 37 | } 38 | 39 | // HasChanges returns whether the flag has changes or not. 40 | func (p pflagValue) HasChanged() bool { 41 | return p.flag.Changed 42 | } 43 | 44 | // Name returns the name of the flag. 45 | func (p pflagValue) Name() string { 46 | return p.flag.Name 47 | } 48 | 49 | // ValueString returns the value of the flag as a string. 50 | func (p pflagValue) ValueString() string { 51 | return p.flag.Value.String() 52 | } 53 | 54 | // ValueType returns the type of the flag as a string. 55 | func (p pflagValue) ValueType() string { 56 | return p.flag.Value.Type() 57 | } 58 | -------------------------------------------------------------------------------- /dyskctl/vendor/github.com/spf13/pflag/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012 Alex Ogier. All rights reserved. 2 | Copyright (c) 2012 The Go Authors. All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are 6 | met: 7 | 8 | * Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | * Redistributions in binary form must reproduce the above 11 | copyright notice, this list of conditions and the following disclaimer 12 | in the documentation and/or other materials provided with the 13 | distribution. 14 | * Neither the name of Google Inc. nor the names of its 15 | contributors may be used to endorse or promote products derived from 16 | this software without specific prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | -------------------------------------------------------------------------------- /dyskctl/vendor/github.com/fsnotify/fsnotify/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012 The Go Authors. All rights reserved. 2 | Copyright (c) 2012 fsnotify Authors. All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are 6 | met: 7 | 8 | * Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | * Redistributions in binary form must reproduce the above 11 | copyright notice, this list of conditions and the following disclaimer 12 | in the documentation and/or other materials provided with the 13 | distribution. 14 | * Neither the name of Google Inc. nor the names of its 15 | contributors may be used to endorse or promote products derived from 16 | this software without specific prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | -------------------------------------------------------------------------------- /module/ioctl_cmds.md: -------------------------------------------------------------------------------- 1 | # Command List 2 | 1. Mount 3 | 2. Unmount 4 | 3. Get Dysk 5 | 3. List Dysks (Names & Major/minors only) 6 | 7 | > All input commands are read at max 2048 bytes.Including a null terminator for the entire command and each entry. All responses are max 2048 bytes including a null terminator 8 | 9 | 10 | ## General Error Response 11 | In case of error the following will be used 12 | 13 | ``` 14 | ERR\n 15 | {Message} 16 | ``` 17 | 18 | # Mount 19 | 20 | ## Request 21 | 22 | ``` 23 | TYPE\n # Max 2 (R ReadOnly RW ReadWrite) 24 | DeviceName\n # Max 32 desired device name *unique per all dysks and existing disks 25 | SectorCount\n # size_t sector count. 26 | Account Name\n # max 256 27 | Account Key\n #max 128 28 | Disk Path \n # Max 1024 include the extention if any sample: /xxx/xxx/xx.xx 29 | Host\n # Max 512 Full host name sample: dysk.core.blob.windows.core 30 | IP\n # max 32 ip host name. 31 | Lease-Id\n # max 64 32 | 0 or 1 \n # is vhd 33 | ``` 34 | 35 | 36 | ## Response 37 | Error Message or 38 | 39 | ``` 40 | OK\n 41 | {REQUEST MESSAGE}\n 42 | Major\n 43 | Minor\n 44 | ``` 45 | 46 | # Unmount 47 | 48 | ## Request 49 | 50 | ``` 51 | DeviceName\n 52 | ``` 53 | 54 | ## Response 55 | 56 | Error Message or 57 | 58 | ``` 59 | OK\n 60 | ``` 61 | 62 | # Get Dysk 63 | 64 | ## Request 65 | 66 | ``` 67 | GET\n 68 | DeviceName\n 69 | ``` 70 | 71 | ## Response 72 | 73 | Error Message or 74 | 75 | ``` 76 | Ok\n 77 | {Mount Response Message}\n' 78 | ``` 79 | 80 | # List 81 | 82 | ## Request 83 | 84 | ``` 85 | LIST 86 | ``` 87 | 88 | ## Resonse 89 | 90 | Error Message or 91 | 92 | ``` 93 | OK\n 94 | devicename major:minor\n 95 | ... 96 | ``` 97 | -------------------------------------------------------------------------------- /dyskctl/vendor/github.com/Azure/azure-sdk-for-go/storage/odata.go: -------------------------------------------------------------------------------- 1 | package storage 2 | 3 | // Copyright 2017 Microsoft Corporation 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | // MetadataLevel determines if operations should return a paylod, 18 | // and it level of detail. 19 | type MetadataLevel string 20 | 21 | // This consts are meant to help with Odata supported operations 22 | const ( 23 | OdataTypeSuffix = "@odata.type" 24 | 25 | // Types 26 | 27 | OdataBinary = "Edm.Binary" 28 | OdataDateTime = "Edm.DateTime" 29 | OdataGUID = "Edm.Guid" 30 | OdataInt64 = "Edm.Int64" 31 | 32 | // Query options 33 | 34 | OdataFilter = "$filter" 35 | OdataOrderBy = "$orderby" 36 | OdataTop = "$top" 37 | OdataSkip = "$skip" 38 | OdataCount = "$count" 39 | OdataExpand = "$expand" 40 | OdataSelect = "$select" 41 | OdataSearch = "$search" 42 | 43 | EmptyPayload MetadataLevel = "" 44 | NoMetadata MetadataLevel = "application/json;odata=nometadata" 45 | MinimalMetadata MetadataLevel = "application/json;odata=minimalmetadata" 46 | FullMetadata MetadataLevel = "application/json;odata=fullmetadata" 47 | ) 48 | -------------------------------------------------------------------------------- /dyskctl/vendor/github.com/Azure/go-autorest/autorest/retriablerequest.go: -------------------------------------------------------------------------------- 1 | package autorest 2 | 3 | // Copyright 2017 Microsoft Corporation 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | import ( 18 | "bytes" 19 | "io" 20 | "io/ioutil" 21 | "net/http" 22 | ) 23 | 24 | // NewRetriableRequest returns a wrapper around an HTTP request that support retry logic. 25 | func NewRetriableRequest(req *http.Request) *RetriableRequest { 26 | return &RetriableRequest{req: req} 27 | } 28 | 29 | // Request returns the wrapped HTTP request. 30 | func (rr *RetriableRequest) Request() *http.Request { 31 | return rr.req 32 | } 33 | 34 | func (rr *RetriableRequest) prepareFromByteReader() (err error) { 35 | // fall back to making a copy (only do this once) 36 | b := []byte{} 37 | if rr.req.ContentLength > 0 { 38 | b = make([]byte, rr.req.ContentLength) 39 | _, err = io.ReadFull(rr.req.Body, b) 40 | if err != nil { 41 | return err 42 | } 43 | } else { 44 | b, err = ioutil.ReadAll(rr.req.Body) 45 | if err != nil { 46 | return err 47 | } 48 | } 49 | rr.br = bytes.NewReader(b) 50 | rr.req.Body = ioutil.NopCloser(rr.br) 51 | return err 52 | } 53 | -------------------------------------------------------------------------------- /kubernetes/flexvolume/examples/readme.md: -------------------------------------------------------------------------------- 1 | # Statefulset using dysk 2 | 3 | 4 | ## Prereq 5 | 6 | [Install](../readme.md) dysk on you kubernetes cluster 7 | 8 | ## Deployment 9 | 10 | 1. Deploy the storage class 11 | 12 | ``` 13 | kubectl create -f storageclass.yaml 14 | ``` 15 | 16 | > Although flex volume does not support dynamic provisioning, the storage class helps in binding pvs to claims created by statefulset's claim template. 17 | 18 | 19 | 2. Create secret 20 | 21 | ``` 22 | kubectl create secret generic xdysk --from-literal accountname={ACCOUNT NAME} --from-literal accountkey="{ACCOUNT KEY}" --type="azure/dysk" 23 | ``` 24 | 25 | 26 | 3. Create dysks 27 | 28 | Create 32 page blob (100GiB each) 29 | 30 | > in this example we are using ```convert-pv``` dyskctl command to quickly create pvs. This commands creates page blob and convert dysk object to kubernetes PVs 31 | 32 | ``` 33 | for idx in {1..32} \ 34 | do \ 35 | dyskctl -a {ACCOUNT NAME} -k {ACCOUNT KEY} -o json --size 100 | \ 36 | dyskctl convert-pv --secret-name xdysk --labels pvCollection=pvC01 --storageclass-name flexvoldysk01 | kubectl create -f -\ 37 | done 38 | ``` 39 | 40 | > The label created on the PV and storage class name are used by claim template (on the statefulset) to bind PVCs<=>PVs. 41 | 42 | 4. Create the stateful set 43 | 44 | ``` 45 | kubectl create -f ./nginx-statefulset.yaml 46 | ``` 47 | 48 | > Statefulset pods are create sequentially. 49 | 50 | 5. Watch pods light up 51 | 52 | ``` 53 | watch kubectl get po 54 | ``` 55 | 56 | 6. Simulate loss of node to watch pods moving quickly between nodes (because of dysk mount speed) 57 | 58 | ``` 59 | kubectl drain {NODE NAME} --grace-period 0 --ignore-daemonsets 60 | ``` 61 | -------------------------------------------------------------------------------- /dyskctl/vendor/github.com/rubiojr/go-vhd/vhd/util.go: -------------------------------------------------------------------------------- 1 | package vhd 2 | 3 | import ( 4 | "encoding/binary" 5 | "encoding/hex" 6 | "fmt" 7 | "os" 8 | "strings" 9 | "unicode/utf16" 10 | "unicode/utf8" 11 | ) 12 | 13 | // https://groups.google.com/forum/#!msg/golang-nuts/d0nF_k4dSx4/rPGgfXv6QCoJ 14 | func uuidgen() string { 15 | b := uuidgenBytes() 16 | return fmt.Sprintf("%x-%x-%x-%x-%x", 17 | b[0:4], b[4:6], b[6:8], b[8:10], b[10:]) 18 | } 19 | 20 | func fmtField(name, value string) { 21 | fmt.Printf("%-25s%s\n", name+":", value) 22 | } 23 | 24 | func uuidgenBytes() []byte { 25 | f, err := os.Open("/dev/urandom") 26 | check(err) 27 | b := make([]byte, 16) 28 | f.Read(b) 29 | return b 30 | } 31 | 32 | func check(e error) { 33 | if e != nil { 34 | panic(e) 35 | } 36 | } 37 | 38 | func hexs(a []byte) string { 39 | return "0x" + hex.EncodeToString(a[:]) 40 | } 41 | 42 | func uuid(a []byte) string { 43 | return fmt.Sprintf("%08x-%04x-%04x-%04x-%04x", 44 | a[:4], 45 | a[4:6], 46 | a[6:8], 47 | a[8:10], 48 | a[10:16]) 49 | } 50 | 51 | func uuidToBytes(uuid string) []byte { 52 | s := strings.Replace(uuid, "-", "", -1) 53 | h, err := hex.DecodeString(s) 54 | check(err) 55 | 56 | return h 57 | } 58 | 59 | /* 60 | utf16BytesToString converts UTF-16 encoded bytes, in big or 61 | little endian byte order, to a UTF-8 encoded string. 62 | http://stackoverflow.com/a/15794113 63 | */ 64 | func utf16BytesToString(b []byte, o binary.ByteOrder) string { 65 | utf := make([]uint16, (len(b)+(2-1))/2) 66 | for i := 0; i+(2-1) < len(b); i += 2 { 67 | utf[i/2] = o.Uint16(b[i:]) 68 | } 69 | if len(b)/2 < len(utf) { 70 | utf[len(utf)-1] = utf8.RuneError 71 | } 72 | return string(utf16.Decode(utf)) 73 | } 74 | -------------------------------------------------------------------------------- /dyskctl/vendor/github.com/spf13/afero/readonlyfs.go: -------------------------------------------------------------------------------- 1 | package afero 2 | 3 | import ( 4 | "os" 5 | "syscall" 6 | "time" 7 | ) 8 | 9 | type ReadOnlyFs struct { 10 | source Fs 11 | } 12 | 13 | func NewReadOnlyFs(source Fs) Fs { 14 | return &ReadOnlyFs{source: source} 15 | } 16 | 17 | func (r *ReadOnlyFs) ReadDir(name string) ([]os.FileInfo, error) { 18 | return ReadDir(r.source, name) 19 | } 20 | 21 | func (r *ReadOnlyFs) Chtimes(n string, a, m time.Time) error { 22 | return syscall.EPERM 23 | } 24 | 25 | func (r *ReadOnlyFs) Chmod(n string, m os.FileMode) error { 26 | return syscall.EPERM 27 | } 28 | 29 | func (r *ReadOnlyFs) Name() string { 30 | return "ReadOnlyFilter" 31 | } 32 | 33 | func (r *ReadOnlyFs) Stat(name string) (os.FileInfo, error) { 34 | return r.source.Stat(name) 35 | } 36 | 37 | func (r *ReadOnlyFs) Rename(o, n string) error { 38 | return syscall.EPERM 39 | } 40 | 41 | func (r *ReadOnlyFs) RemoveAll(p string) error { 42 | return syscall.EPERM 43 | } 44 | 45 | func (r *ReadOnlyFs) Remove(n string) error { 46 | return syscall.EPERM 47 | } 48 | 49 | func (r *ReadOnlyFs) OpenFile(name string, flag int, perm os.FileMode) (File, error) { 50 | if flag&(os.O_WRONLY|syscall.O_RDWR|os.O_APPEND|os.O_CREATE|os.O_TRUNC) != 0 { 51 | return nil, syscall.EPERM 52 | } 53 | return r.source.OpenFile(name, flag, perm) 54 | } 55 | 56 | func (r *ReadOnlyFs) Open(n string) (File, error) { 57 | return r.source.Open(n) 58 | } 59 | 60 | func (r *ReadOnlyFs) Mkdir(n string, p os.FileMode) error { 61 | return syscall.EPERM 62 | } 63 | 64 | func (r *ReadOnlyFs) MkdirAll(n string, p os.FileMode) error { 65 | return syscall.EPERM 66 | } 67 | 68 | func (r *ReadOnlyFs) Create(n string) (File, error) { 69 | return nil, syscall.EPERM 70 | } 71 | -------------------------------------------------------------------------------- /dyskctl/vendor/github.com/Azure/go-autorest/autorest/retriablerequest_1.7.go: -------------------------------------------------------------------------------- 1 | // +build !go1.8 2 | 3 | // Copyright 2017 Microsoft Corporation 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package autorest 18 | 19 | import ( 20 | "bytes" 21 | "io/ioutil" 22 | "net/http" 23 | ) 24 | 25 | // RetriableRequest provides facilities for retrying an HTTP request. 26 | type RetriableRequest struct { 27 | req *http.Request 28 | br *bytes.Reader 29 | } 30 | 31 | // Prepare signals that the request is about to be sent. 32 | func (rr *RetriableRequest) Prepare() (err error) { 33 | // preserve the request body; this is to support retry logic as 34 | // the underlying transport will always close the reqeust body 35 | if rr.req.Body != nil { 36 | if rr.br != nil { 37 | _, err = rr.br.Seek(0, 0 /*io.SeekStart*/) 38 | rr.req.Body = ioutil.NopCloser(rr.br) 39 | } 40 | if err != nil { 41 | return err 42 | } 43 | if rr.br == nil { 44 | // fall back to making a copy (only do this once) 45 | err = rr.prepareFromByteReader() 46 | } 47 | } 48 | return err 49 | } 50 | 51 | func removeRequestBody(req *http.Request) { 52 | req.Body = nil 53 | req.ContentLength = 0 54 | } 55 | -------------------------------------------------------------------------------- /dyskctl/vendor/github.com/dgrijalva/jwt-go/ecdsa_utils.go: -------------------------------------------------------------------------------- 1 | package jwt 2 | 3 | import ( 4 | "crypto/ecdsa" 5 | "crypto/x509" 6 | "encoding/pem" 7 | "errors" 8 | ) 9 | 10 | var ( 11 | ErrNotECPublicKey = errors.New("Key is not a valid ECDSA public key") 12 | ErrNotECPrivateKey = errors.New("Key is not a valid ECDSA private key") 13 | ) 14 | 15 | // Parse PEM encoded Elliptic Curve Private Key Structure 16 | func ParseECPrivateKeyFromPEM(key []byte) (*ecdsa.PrivateKey, error) { 17 | var err error 18 | 19 | // Parse PEM block 20 | var block *pem.Block 21 | if block, _ = pem.Decode(key); block == nil { 22 | return nil, ErrKeyMustBePEMEncoded 23 | } 24 | 25 | // Parse the key 26 | var parsedKey interface{} 27 | if parsedKey, err = x509.ParseECPrivateKey(block.Bytes); err != nil { 28 | return nil, err 29 | } 30 | 31 | var pkey *ecdsa.PrivateKey 32 | var ok bool 33 | if pkey, ok = parsedKey.(*ecdsa.PrivateKey); !ok { 34 | return nil, ErrNotECPrivateKey 35 | } 36 | 37 | return pkey, nil 38 | } 39 | 40 | // Parse PEM encoded PKCS1 or PKCS8 public key 41 | func ParseECPublicKeyFromPEM(key []byte) (*ecdsa.PublicKey, error) { 42 | var err error 43 | 44 | // Parse PEM block 45 | var block *pem.Block 46 | if block, _ = pem.Decode(key); block == nil { 47 | return nil, ErrKeyMustBePEMEncoded 48 | } 49 | 50 | // Parse the key 51 | var parsedKey interface{} 52 | if parsedKey, err = x509.ParsePKIXPublicKey(block.Bytes); err != nil { 53 | if cert, err := x509.ParseCertificate(block.Bytes); err == nil { 54 | parsedKey = cert.PublicKey 55 | } else { 56 | return nil, err 57 | } 58 | } 59 | 60 | var pkey *ecdsa.PublicKey 61 | var ok bool 62 | if pkey, ok = parsedKey.(*ecdsa.PublicKey); !ok { 63 | return nil, ErrNotECPublicKey 64 | } 65 | 66 | return pkey, nil 67 | } 68 | -------------------------------------------------------------------------------- /examples/101-mount-create/readme.md: -------------------------------------------------------------------------------- 1 | # Mount (automatically created dysk) - 256GB 2 | 3 | 4 | 1. Mount (dyskctl will create the page blob for you) 5 | ``` 6 | sudo ${DYSKCTL} mount auto-create -a "${ACCOUNT}" -k "${KEY}" --size 256 -o json 7 | ``` 8 | 9 | 2. dysk will be created at blob container named ```dysks``` with random page blob and device name. 10 | 3. to find the newly mounted disk 11 | 12 | ``` 13 | lsblk 14 | 15 | #dysk randomly created names formatted as ```dyskxxxx``` 16 | ``` 17 | 18 | 4. Format the newly mounted disk 19 | 20 | ``` 21 | sudo mkfs.ext4 /dev/${DEVICE_NAME} 22 | ``` 23 | 24 | 5. Mount the newly mounted disk 25 | 26 | ``` 27 | sudo mkdir /mnt/dysk 28 | sudo mount -o '_netdev' /dev/${DEVICE_NAME} /mnt/dysk 29 | 30 | ``` 31 | 32 | > if systemd is your init system you will need `x-systemd.device-bound` [option](https://www.freedesktop.org/software/systemd/man/systemd.mount.html). 33 | 34 | 6. Use the disk 35 | 7. Unmounting the device 36 | 37 | ``` 38 | # unmount the mount point 39 | sudo umount /mnt/dysk 40 | 41 | # unmount dysk 42 | 43 | sudo dyskctl unmount -d ${DEVICE_NAME} 44 | ``` 45 | 46 | > dysk - by default - creates dysks as vhds (with vhd footer written). These dysks can be attached as data disks (on unmanaged VMs) via azure. Follow [these steps](https://docs.microsoft.com/en-us/azure/virtual-machines/linux/attach-disk-portal) to attach dysk as data disk. If you want disks without vhd footer use ```-vhd false``` argument to dyskctl. 47 | 48 | 49 | # deleting dysks 50 | 51 | dysk provide an easy tool to delete page blobs (there is **no undo** for this operation) 52 | 53 | ``` 54 | sudo ./dyskctl delete -a ${ACCOUNT} -k {KEY} --container-name {CONTAINERNAME} --pageblob-name {PAGEBLOBNAME} 55 | ``` 56 | 57 | > TIP: use ```break-lease``` if the page blob is leased 58 | -------------------------------------------------------------------------------- /dyskctl/vendor/github.com/fsnotify/fsnotify/fsnotify.go: -------------------------------------------------------------------------------- 1 | // Copyright 2012 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // +build !plan9 6 | 7 | // Package fsnotify provides a platform-independent interface for file system notifications. 8 | package fsnotify 9 | 10 | import ( 11 | "bytes" 12 | "errors" 13 | "fmt" 14 | ) 15 | 16 | // Event represents a single file system notification. 17 | type Event struct { 18 | Name string // Relative path to the file or directory. 19 | Op Op // File operation that triggered the event. 20 | } 21 | 22 | // Op describes a set of file operations. 23 | type Op uint32 24 | 25 | // These are the generalized file operations that can trigger a notification. 26 | const ( 27 | Create Op = 1 << iota 28 | Write 29 | Remove 30 | Rename 31 | Chmod 32 | ) 33 | 34 | func (op Op) String() string { 35 | // Use a buffer for efficient string concatenation 36 | var buffer bytes.Buffer 37 | 38 | if op&Create == Create { 39 | buffer.WriteString("|CREATE") 40 | } 41 | if op&Remove == Remove { 42 | buffer.WriteString("|REMOVE") 43 | } 44 | if op&Write == Write { 45 | buffer.WriteString("|WRITE") 46 | } 47 | if op&Rename == Rename { 48 | buffer.WriteString("|RENAME") 49 | } 50 | if op&Chmod == Chmod { 51 | buffer.WriteString("|CHMOD") 52 | } 53 | if buffer.Len() == 0 { 54 | return "" 55 | } 56 | return buffer.String()[1:] // Strip leading pipe 57 | } 58 | 59 | // String returns a string representation of the event in the form 60 | // "file: REMOVE|WRITE|..." 61 | func (e Event) String() string { 62 | return fmt.Sprintf("%q: %s", e.Name, e.Op.String()) 63 | } 64 | 65 | // Common errors that can be reported by a watcher 66 | var ErrEventOverflow = errors.New("fsnotify queue overflow") 67 | -------------------------------------------------------------------------------- /dyskctl/vendor/github.com/Azure/azure-sdk-for-go/storage/queueserviceclient.go: -------------------------------------------------------------------------------- 1 | package storage 2 | 3 | // Copyright 2017 Microsoft Corporation 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | // QueueServiceClient contains operations for Microsoft Azure Queue Storage 18 | // Service. 19 | type QueueServiceClient struct { 20 | client Client 21 | auth authentication 22 | } 23 | 24 | // GetServiceProperties gets the properties of your storage account's queue service. 25 | // See: https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/get-queue-service-properties 26 | func (q *QueueServiceClient) GetServiceProperties() (*ServiceProperties, error) { 27 | return q.client.getServiceProperties(queueServiceName, q.auth) 28 | } 29 | 30 | // SetServiceProperties sets the properties of your storage account's queue service. 31 | // See: https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/set-queue-service-properties 32 | func (q *QueueServiceClient) SetServiceProperties(props ServiceProperties) error { 33 | return q.client.setServiceProperties(props, queueServiceName, q.auth) 34 | } 35 | 36 | // GetQueueReference returns a Container object for the specified queue name. 37 | func (q *QueueServiceClient) GetQueueReference(name string) *Queue { 38 | return &Queue{ 39 | qsc: q, 40 | Name: name, 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /dyskctl/vendor/github.com/dgrijalva/jwt-go/none.go: -------------------------------------------------------------------------------- 1 | package jwt 2 | 3 | // Implements the none signing method. This is required by the spec 4 | // but you probably should never use it. 5 | var SigningMethodNone *signingMethodNone 6 | 7 | const UnsafeAllowNoneSignatureType unsafeNoneMagicConstant = "none signing method allowed" 8 | 9 | var NoneSignatureTypeDisallowedError error 10 | 11 | type signingMethodNone struct{} 12 | type unsafeNoneMagicConstant string 13 | 14 | func init() { 15 | SigningMethodNone = &signingMethodNone{} 16 | NoneSignatureTypeDisallowedError = NewValidationError("'none' signature type is not allowed", ValidationErrorSignatureInvalid) 17 | 18 | RegisterSigningMethod(SigningMethodNone.Alg(), func() SigningMethod { 19 | return SigningMethodNone 20 | }) 21 | } 22 | 23 | func (m *signingMethodNone) Alg() string { 24 | return "none" 25 | } 26 | 27 | // Only allow 'none' alg type if UnsafeAllowNoneSignatureType is specified as the key 28 | func (m *signingMethodNone) Verify(signingString, signature string, key interface{}) (err error) { 29 | // Key must be UnsafeAllowNoneSignatureType to prevent accidentally 30 | // accepting 'none' signing method 31 | if _, ok := key.(unsafeNoneMagicConstant); !ok { 32 | return NoneSignatureTypeDisallowedError 33 | } 34 | // If signing method is none, signature must be an empty string 35 | if signature != "" { 36 | return NewValidationError( 37 | "'none' signing method with non-empty signature", 38 | ValidationErrorSignatureInvalid, 39 | ) 40 | } 41 | 42 | // Accept 'none' signing method. 43 | return nil 44 | } 45 | 46 | // Only allow 'none' signing if UnsafeAllowNoneSignatureType is specified as the key 47 | func (m *signingMethodNone) Sign(signingString string, key interface{}) (string, error) { 48 | if _, ok := key.(unsafeNoneMagicConstant); ok { 49 | return "", nil 50 | } 51 | return "", NoneSignatureTypeDisallowedError 52 | } 53 | -------------------------------------------------------------------------------- /dyskctl/vendor/github.com/dgrijalva/jwt-go/rsa_utils.go: -------------------------------------------------------------------------------- 1 | package jwt 2 | 3 | import ( 4 | "crypto/rsa" 5 | "crypto/x509" 6 | "encoding/pem" 7 | "errors" 8 | ) 9 | 10 | var ( 11 | ErrKeyMustBePEMEncoded = errors.New("Invalid Key: Key must be PEM encoded PKCS1 or PKCS8 private key") 12 | ErrNotRSAPrivateKey = errors.New("Key is not a valid RSA private key") 13 | ErrNotRSAPublicKey = errors.New("Key is not a valid RSA public key") 14 | ) 15 | 16 | // Parse PEM encoded PKCS1 or PKCS8 private key 17 | func ParseRSAPrivateKeyFromPEM(key []byte) (*rsa.PrivateKey, error) { 18 | var err error 19 | 20 | // Parse PEM block 21 | var block *pem.Block 22 | if block, _ = pem.Decode(key); block == nil { 23 | return nil, ErrKeyMustBePEMEncoded 24 | } 25 | 26 | var parsedKey interface{} 27 | if parsedKey, err = x509.ParsePKCS1PrivateKey(block.Bytes); err != nil { 28 | if parsedKey, err = x509.ParsePKCS8PrivateKey(block.Bytes); err != nil { 29 | return nil, err 30 | } 31 | } 32 | 33 | var pkey *rsa.PrivateKey 34 | var ok bool 35 | if pkey, ok = parsedKey.(*rsa.PrivateKey); !ok { 36 | return nil, ErrNotRSAPrivateKey 37 | } 38 | 39 | return pkey, nil 40 | } 41 | 42 | // Parse PEM encoded PKCS1 or PKCS8 public key 43 | func ParseRSAPublicKeyFromPEM(key []byte) (*rsa.PublicKey, error) { 44 | var err error 45 | 46 | // Parse PEM block 47 | var block *pem.Block 48 | if block, _ = pem.Decode(key); block == nil { 49 | return nil, ErrKeyMustBePEMEncoded 50 | } 51 | 52 | // Parse the key 53 | var parsedKey interface{} 54 | if parsedKey, err = x509.ParsePKIXPublicKey(block.Bytes); err != nil { 55 | if cert, err := x509.ParseCertificate(block.Bytes); err == nil { 56 | parsedKey = cert.PublicKey 57 | } else { 58 | return nil, err 59 | } 60 | } 61 | 62 | var pkey *rsa.PublicKey 63 | var ok bool 64 | if pkey, ok = parsedKey.(*rsa.PublicKey); !ok { 65 | return nil, ErrNotRSAPublicKey 66 | } 67 | 68 | return pkey, nil 69 | } 70 | -------------------------------------------------------------------------------- /examples/readme.md: -------------------------------------------------------------------------------- 1 | # Before you begin 2 | 3 | ## Pre-req 4 | 1. [Install dysk kernel module and dyskctl cli](../docs/build-install.md) 5 | 2. dysk depends on Azure Storage (Page Blobs). Follow the below steps to create azure storage account via the cli 6 | 7 | **Install and configure azure cli** 8 | 1. [Install azure cli] (https://docs.microsoft.com/en-us/cli/azure/install-azure-cli?view=azure-cli-latest). 9 | 2. Login with ```az login ``` 10 | 3. Set your active subscription with ```az subscription set -s {AZURE-SUB-ID}``` 11 | 4. Check your active subscription with ```az account listi -o table``` 12 | 13 | **Create storage account** 14 | 15 | Names etc..: 16 | ``` 17 | export RG="mydyskrg" 18 | export ACCOUNT="dysktestaccount01" 19 | ``` 20 | 21 | 1. Create a resource group with ```az group create --name ${RG} --location westus``` 22 | 2. Create a storage account with ``` az storage account create -n ${ACCOUNT} -g ${RG} -l westus --sku Standard_LRS ``` 23 | 24 | > If you are running dysk locally then choose azure location closest to you. If you are running on Azure then choose the **same** azure region where your test VM are. 25 | 26 | 3. Get account key via ```export KEY="$(az storage account keys list -g ${RG} -n ${ACCOUNT} | jq -r '.[0].value')" 27 | 28 | 29 | ## Premium vs Standard Storage Accounts SKUs 30 | 31 | Details here: https://docs.microsoft.com/en-us/azure/azure-subscription-service-limits 32 | tl;dr: 33 | Premium SKU will give you higher iops for larger page blobs (Highest iops achieved at 4TB page blobs). Standard accounts will give you flat iops for all page blobs sizes but but with lower cieling and capped at the storage account level. 34 | 35 | **How can make the best selection** 36 | 1. If you want fastest iops you will have to go for largest page blob on premium sku. 37 | 2. For any other iops go for standard sku and span them over large number of accounts 38 | 39 | > max # of accounts per subscription is 200 account (250 with a support request). 40 | 41 | Enjoy the Examples! 42 | -------------------------------------------------------------------------------- /dyskctl/vendor/github.com/fsnotify/fsnotify/AUTHORS: -------------------------------------------------------------------------------- 1 | # Names should be added to this file as 2 | # Name or Organization 3 | # The email address is not required for organizations. 4 | 5 | # You can update this list using the following command: 6 | # 7 | # $ git shortlog -se | awk '{print $2 " " $3 " " $4}' 8 | 9 | # Please keep the list sorted. 10 | 11 | Aaron L 12 | Adrien Bustany 13 | Amit Krishnan 14 | Anmol Sethi 15 | Bjørn Erik Pedersen 16 | Bruno Bigras 17 | Caleb Spare 18 | Case Nelson 19 | Chris Howey 20 | Christoffer Buchholz 21 | Daniel Wagner-Hall 22 | Dave Cheney 23 | Evan Phoenix 24 | Francisco Souza 25 | Hari haran 26 | John C Barstow 27 | Kelvin Fo 28 | Ken-ichirou MATSUZAWA 29 | Matt Layher 30 | Nathan Youngman 31 | Nickolai Zeldovich 32 | Patrick 33 | Paul Hammond 34 | Pawel Knap 35 | Pieter Droogendijk 36 | Pursuit92 37 | Riku Voipio 38 | Rob Figueiredo 39 | Rodrigo Chiossi 40 | Slawek Ligus 41 | Soge Zhang 42 | Tiffany Jernigan 43 | Tilak Sharma 44 | Tom Payne 45 | Travis Cline 46 | Tudor Golubenco 47 | Vahe Khachikyan 48 | Yukang 49 | bronze1man 50 | debrando 51 | henrikedwards 52 | 铁哥 53 | -------------------------------------------------------------------------------- /dyskctl/vendor/github.com/Azure/go-autorest/autorest/retriablerequest_1.8.go: -------------------------------------------------------------------------------- 1 | // +build go1.8 2 | 3 | // Copyright 2017 Microsoft Corporation 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package autorest 18 | 19 | import ( 20 | "bytes" 21 | "io" 22 | "io/ioutil" 23 | "net/http" 24 | ) 25 | 26 | // RetriableRequest provides facilities for retrying an HTTP request. 27 | type RetriableRequest struct { 28 | req *http.Request 29 | rc io.ReadCloser 30 | br *bytes.Reader 31 | } 32 | 33 | // Prepare signals that the request is about to be sent. 34 | func (rr *RetriableRequest) Prepare() (err error) { 35 | // preserve the request body; this is to support retry logic as 36 | // the underlying transport will always close the reqeust body 37 | if rr.req.Body != nil { 38 | if rr.rc != nil { 39 | rr.req.Body = rr.rc 40 | } else if rr.br != nil { 41 | _, err = rr.br.Seek(0, io.SeekStart) 42 | rr.req.Body = ioutil.NopCloser(rr.br) 43 | } 44 | if err != nil { 45 | return err 46 | } 47 | if rr.req.GetBody != nil { 48 | // this will allow us to preserve the body without having to 49 | // make a copy. note we need to do this on each iteration 50 | rr.rc, err = rr.req.GetBody() 51 | if err != nil { 52 | return err 53 | } 54 | } else if rr.br == nil { 55 | // fall back to making a copy (only do this once) 56 | err = rr.prepareFromByteReader() 57 | } 58 | } 59 | return err 60 | } 61 | 62 | func removeRequestBody(req *http.Request) { 63 | req.Body = nil 64 | req.GetBody = nil 65 | req.ContentLength = 0 66 | } 67 | -------------------------------------------------------------------------------- /dyskctl/vendor/github.com/dgrijalva/jwt-go/errors.go: -------------------------------------------------------------------------------- 1 | package jwt 2 | 3 | import ( 4 | "errors" 5 | ) 6 | 7 | // Error constants 8 | var ( 9 | ErrInvalidKey = errors.New("key is invalid") 10 | ErrInvalidKeyType = errors.New("key is of invalid type") 11 | ErrHashUnavailable = errors.New("the requested hash function is unavailable") 12 | ) 13 | 14 | // The errors that might occur when parsing and validating a token 15 | const ( 16 | ValidationErrorMalformed uint32 = 1 << iota // Token is malformed 17 | ValidationErrorUnverifiable // Token could not be verified because of signing problems 18 | ValidationErrorSignatureInvalid // Signature validation failed 19 | 20 | // Standard Claim validation errors 21 | ValidationErrorAudience // AUD validation failed 22 | ValidationErrorExpired // EXP validation failed 23 | ValidationErrorIssuedAt // IAT validation failed 24 | ValidationErrorIssuer // ISS validation failed 25 | ValidationErrorNotValidYet // NBF validation failed 26 | ValidationErrorId // JTI validation failed 27 | ValidationErrorClaimsInvalid // Generic claims validation error 28 | ) 29 | 30 | // Helper for constructing a ValidationError with a string error message 31 | func NewValidationError(errorText string, errorFlags uint32) *ValidationError { 32 | return &ValidationError{ 33 | text: errorText, 34 | Errors: errorFlags, 35 | } 36 | } 37 | 38 | // The error from Parse if token is not valid 39 | type ValidationError struct { 40 | Inner error // stores the error returned by external dependencies, i.e.: KeyFunc 41 | Errors uint32 // bitfield. see ValidationError... constants 42 | text string // errors that do not have a valid error just have text 43 | } 44 | 45 | // Validation error is an error type 46 | func (e ValidationError) Error() string { 47 | if e.Inner != nil { 48 | return e.Inner.Error() 49 | } else if e.text != "" { 50 | return e.text 51 | } else { 52 | return "token is invalid" 53 | } 54 | } 55 | 56 | // No errors 57 | func (e *ValidationError) valid() bool { 58 | return e.Errors == 0 59 | } 60 | -------------------------------------------------------------------------------- /dyskctl/vendor/github.com/pelletier/go-toml/keysparsing.go: -------------------------------------------------------------------------------- 1 | // Parsing keys handling both bare and quoted keys. 2 | 3 | package toml 4 | 5 | import ( 6 | "bytes" 7 | "errors" 8 | "fmt" 9 | "unicode" 10 | ) 11 | 12 | func parseKey(key string) ([]string, error) { 13 | groups := []string{} 14 | var buffer bytes.Buffer 15 | inQuotes := false 16 | wasInQuotes := false 17 | escapeNext := false 18 | ignoreSpace := true 19 | expectDot := false 20 | 21 | for _, char := range key { 22 | if ignoreSpace { 23 | if char == ' ' { 24 | continue 25 | } 26 | ignoreSpace = false 27 | } 28 | if escapeNext { 29 | buffer.WriteRune(char) 30 | escapeNext = false 31 | continue 32 | } 33 | switch char { 34 | case '\\': 35 | escapeNext = true 36 | continue 37 | case '"': 38 | if inQuotes { 39 | groups = append(groups, buffer.String()) 40 | buffer.Reset() 41 | wasInQuotes = true 42 | } 43 | inQuotes = !inQuotes 44 | expectDot = false 45 | case '.': 46 | if inQuotes { 47 | buffer.WriteRune(char) 48 | } else { 49 | if !wasInQuotes { 50 | if buffer.Len() == 0 { 51 | return nil, errors.New("empty table key") 52 | } 53 | groups = append(groups, buffer.String()) 54 | buffer.Reset() 55 | } 56 | ignoreSpace = true 57 | expectDot = false 58 | wasInQuotes = false 59 | } 60 | case ' ': 61 | if inQuotes { 62 | buffer.WriteRune(char) 63 | } else { 64 | expectDot = true 65 | } 66 | default: 67 | if !inQuotes && !isValidBareChar(char) { 68 | return nil, fmt.Errorf("invalid bare character: %c", char) 69 | } 70 | if !inQuotes && expectDot { 71 | return nil, errors.New("what?") 72 | } 73 | buffer.WriteRune(char) 74 | expectDot = false 75 | } 76 | } 77 | if inQuotes { 78 | return nil, errors.New("mismatched quotes") 79 | } 80 | if escapeNext { 81 | return nil, errors.New("unfinished escape sequence") 82 | } 83 | if buffer.Len() > 0 { 84 | groups = append(groups, buffer.String()) 85 | } 86 | if len(groups) == 0 { 87 | return nil, errors.New("empty key") 88 | } 89 | return groups, nil 90 | } 91 | 92 | func isValidBareChar(r rune) bool { 93 | return isAlphanumeric(r) || r == '-' || unicode.IsNumber(r) 94 | } 95 | -------------------------------------------------------------------------------- /dyskctl/vendor/github.com/Azure/azure-sdk-for-go/storage/storagepolicy.go: -------------------------------------------------------------------------------- 1 | package storage 2 | 3 | // Copyright 2017 Microsoft Corporation 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | import ( 18 | "strings" 19 | "time" 20 | ) 21 | 22 | // AccessPolicyDetailsXML has specifics about an access policy 23 | // annotated with XML details. 24 | type AccessPolicyDetailsXML struct { 25 | StartTime time.Time `xml:"Start"` 26 | ExpiryTime time.Time `xml:"Expiry"` 27 | Permission string `xml:"Permission"` 28 | } 29 | 30 | // SignedIdentifier is a wrapper for a specific policy 31 | type SignedIdentifier struct { 32 | ID string `xml:"Id"` 33 | AccessPolicy AccessPolicyDetailsXML `xml:"AccessPolicy"` 34 | } 35 | 36 | // SignedIdentifiers part of the response from GetPermissions call. 37 | type SignedIdentifiers struct { 38 | SignedIdentifiers []SignedIdentifier `xml:"SignedIdentifier"` 39 | } 40 | 41 | // AccessPolicy is the response type from the GetPermissions call. 42 | type AccessPolicy struct { 43 | SignedIdentifiersList SignedIdentifiers `xml:"SignedIdentifiers"` 44 | } 45 | 46 | // convertAccessPolicyToXMLStructs converts between AccessPolicyDetails which is a struct better for API usage to the 47 | // AccessPolicy struct which will get converted to XML. 48 | func convertAccessPolicyToXMLStructs(id string, startTime time.Time, expiryTime time.Time, permissions string) SignedIdentifier { 49 | return SignedIdentifier{ 50 | ID: id, 51 | AccessPolicy: AccessPolicyDetailsXML{ 52 | StartTime: startTime.UTC().Round(time.Second), 53 | ExpiryTime: expiryTime.UTC().Round(time.Second), 54 | Permission: permissions, 55 | }, 56 | } 57 | } 58 | 59 | func updatePermissions(permissions, permission string) bool { 60 | return strings.Contains(permissions, permission) 61 | } 62 | -------------------------------------------------------------------------------- /dyskctl/vendor/github.com/magiconair/properties/parser.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017 Frank Schroeder. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package properties 6 | 7 | import ( 8 | "fmt" 9 | "runtime" 10 | ) 11 | 12 | type parser struct { 13 | lex *lexer 14 | } 15 | 16 | func parse(input string) (properties *Properties, err error) { 17 | p := &parser{lex: lex(input)} 18 | defer p.recover(&err) 19 | 20 | properties = NewProperties() 21 | key := "" 22 | comments := []string{} 23 | 24 | for { 25 | token := p.expectOneOf(itemComment, itemKey, itemEOF) 26 | switch token.typ { 27 | case itemEOF: 28 | goto done 29 | case itemComment: 30 | comments = append(comments, token.val) 31 | continue 32 | case itemKey: 33 | key = token.val 34 | if _, ok := properties.m[key]; !ok { 35 | properties.k = append(properties.k, key) 36 | } 37 | } 38 | 39 | token = p.expectOneOf(itemValue, itemEOF) 40 | if len(comments) > 0 { 41 | properties.c[key] = comments 42 | comments = []string{} 43 | } 44 | switch token.typ { 45 | case itemEOF: 46 | properties.m[key] = "" 47 | goto done 48 | case itemValue: 49 | properties.m[key] = token.val 50 | } 51 | } 52 | 53 | done: 54 | return properties, nil 55 | } 56 | 57 | func (p *parser) errorf(format string, args ...interface{}) { 58 | format = fmt.Sprintf("properties: Line %d: %s", p.lex.lineNumber(), format) 59 | panic(fmt.Errorf(format, args...)) 60 | } 61 | 62 | func (p *parser) expect(expected itemType) (token item) { 63 | token = p.lex.nextItem() 64 | if token.typ != expected { 65 | p.unexpected(token) 66 | } 67 | return token 68 | } 69 | 70 | func (p *parser) expectOneOf(expected ...itemType) (token item) { 71 | token = p.lex.nextItem() 72 | for _, v := range expected { 73 | if token.typ == v { 74 | return token 75 | } 76 | } 77 | p.unexpected(token) 78 | panic("unexpected token") 79 | } 80 | 81 | func (p *parser) unexpected(token item) { 82 | p.errorf(token.String()) 83 | } 84 | 85 | // recover is the handler that turns panics into returns from the top level of Parse. 86 | func (p *parser) recover(errp *error) { 87 | e := recover() 88 | if e != nil { 89 | if _, ok := e.(runtime.Error); ok { 90 | panic(e) 91 | } 92 | *errp = e.(error) 93 | } 94 | return 95 | } 96 | -------------------------------------------------------------------------------- /dyskctl/vendor/github.com/Azure/go-autorest/autorest/adal/sender.go: -------------------------------------------------------------------------------- 1 | package adal 2 | 3 | // Copyright 2017 Microsoft Corporation 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | import ( 18 | "net/http" 19 | ) 20 | 21 | const ( 22 | contentType = "Content-Type" 23 | mimeTypeFormPost = "application/x-www-form-urlencoded" 24 | ) 25 | 26 | // Sender is the interface that wraps the Do method to send HTTP requests. 27 | // 28 | // The standard http.Client conforms to this interface. 29 | type Sender interface { 30 | Do(*http.Request) (*http.Response, error) 31 | } 32 | 33 | // SenderFunc is a method that implements the Sender interface. 34 | type SenderFunc func(*http.Request) (*http.Response, error) 35 | 36 | // Do implements the Sender interface on SenderFunc. 37 | func (sf SenderFunc) Do(r *http.Request) (*http.Response, error) { 38 | return sf(r) 39 | } 40 | 41 | // SendDecorator takes and possibily decorates, by wrapping, a Sender. Decorators may affect the 42 | // http.Request and pass it along or, first, pass the http.Request along then react to the 43 | // http.Response result. 44 | type SendDecorator func(Sender) Sender 45 | 46 | // CreateSender creates, decorates, and returns, as a Sender, the default http.Client. 47 | func CreateSender(decorators ...SendDecorator) Sender { 48 | return DecorateSender(&http.Client{}, decorators...) 49 | } 50 | 51 | // DecorateSender accepts a Sender and a, possibly empty, set of SendDecorators, which is applies to 52 | // the Sender. Decorators are applied in the order received, but their affect upon the request 53 | // depends on whether they are a pre-decorator (change the http.Request and then pass it along) or a 54 | // post-decorator (pass the http.Request along and react to the results in http.Response). 55 | func DecorateSender(s Sender, decorators ...SendDecorator) Sender { 56 | for _, decorate := range decorators { 57 | s = decorate(s) 58 | } 59 | return s 60 | } 61 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | SHELL := /bin/bash 2 | MKFILE_DIR:=$(shell dirname $(realpath $(lastword $(MAKEFILE_LIST)))) 3 | 4 | DYSK_CLI_TAG ?= khenidak/dysk-cli:0.6 5 | DYSK_INSTALLER_TAG ?= khenidak/dysk-installer:0.6 6 | DYSK_FLEXVOL_INSTALLER_TAG ?= khenidak/dysk-flexvol-installer:0.6 7 | 8 | MODULE_DIR = "$(MKFILE_DIR)/module" 9 | CLI_DIR = "$(MKFILE_DIR)/dyskctl" 10 | TOOLS_CLI = "$(MKFILE_DIR)/tools/dysk-cli" 11 | FLEXVOL_DIR="$(MKFILE_DIR)/kubernetes" 12 | TOOLS_FLEXVOL_INSTALLER="$(MKFILE_DIR)/tools/flexvol-installer" 13 | TOOLS_DYSK_INSTALLER = "$(MKFILE_DIR)/tools/dysk-installer" 14 | VERIFICATION_SCRIPT="$(MKFILE_DIR)/tools/verification/verify.sh" 15 | 16 | .PHONY: help build-module clean-module build-cli clean-cli push-cli-image 17 | ## Self help 18 | help: 19 | @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' 20 | 21 | build-module: ## builds kernel module 22 | $(MAKE) -C $(MODULE_DIR) all 23 | 24 | install-module: | build-module ## installs kernel module 25 | @if [[ "" != "1`lsmod | egrep dysk`" ]]; then \ 26 | echo "module already installed"; \ 27 | else \ 28 | sudo insmod "$(MKFILE_DIR)/module/dysk.ko"; \ 29 | fi 30 | 31 | verify: ## runs verification tests 32 | @$(VERIFICATION_SCRIPT) "VERIFY" 33 | 34 | verify-perf: ## runs perf tests 35 | @$(VERIFICATION_SCRIPT) "PERF" 36 | 37 | clean-module: ## cleans kernel module 38 | $(MAKE) -C $(MODULE_DIR) clean 39 | 40 | build-cli: ## build dysk cli 41 | $(MAKE) -C $(CLI_DIR) deps build 42 | 43 | clean-cli: ## clean dysk cli 44 | $(MAKE) -C $(CLI_DIR) clean 45 | 46 | push-cli-image: #| build-cli ## build + push dysk cli docker image 47 | @cp $(CLI_DIR)/dyskctl $(TOOLS_CLI)/dyskctl 48 | @docker build --tag $(DYSK_CLI_TAG) $(TOOLS_CLI) 49 | # TODO: Check before push for existing image.. 50 | @docker push $(DYSK_CLI_TAG) 51 | @rm $(TOOLS_CLI)/dyskctl 52 | 53 | push-dysk-installer-image: ## build + push kernel module installer docker iamge 54 | #TODO: parameterize tag used by scirpt to install the module 55 | @docker build --tag $(DYSK_INSTALLER_TAG) $(TOOLS_DYSK_INSTALLER) 56 | @docker push $(DYSK_INSTALLER_TAG) 57 | 58 | push-flexvol-installer-image: #| build-cli ## build + push dysk flex vol installer 59 | @cp $(CLI_DIR)/dyskctl $(TOOLS_FLEXVOL_INSTALLER)/dyskctl 60 | @cp $(FLEXVOL_DIR)/dysk $(TOOLS_FLEXVOL_INSTALLER)/dysk 61 | @docker build --tag $(DYSK_FLEXVOL_INSTALLER_TAG) $(TOOLS_FLEXVOL_INSTALLER) 62 | # TODO: Check before push for existing image.. 63 | @docker push $(DYSK_FLEXVOL_INSTALLER_TAG) 64 | @rm $(TOOLS_FLEXVOL_INSTALLER)/dyskctl 65 | @rm $(TOOLS_FLEXVOL_INSTALLER)/dysk 66 | 67 | 68 | -------------------------------------------------------------------------------- /tools/dysk-installer/install.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | set -eo pipefail 3 | 4 | dysk_base_dir=${DYSK_BASE_DIR:-"/tmp"} 5 | dysk_tag=${DYSK_TAG:-"f02fbe61750fc050d759366b9647e7ea6c159e16"} 6 | dysk_src="${dysk_base_dir}/${dysk_tag}/dysk/" 7 | install_mode="${INSTALL_MODE:-"STANDALONE"}" 8 | function clone_dysk() 9 | { 10 | if [[ ! -d "${dysk_src}" ]]; then 11 | echo "INF: No dysk source found @ ${dysk_src} .. cloning" 12 | dysk_parent_dir="$(dirname "${dysk_src}")" 13 | 14 | mkdir -p "${dysk_parent_dir}" 15 | cd "${dysk_parent_dir}" 16 | 17 | git clone https://github.com/khenidak/dysk.git 18 | cd "${dysk_src}" 19 | git checkout "${dysk_tag}" 20 | else 21 | cd "${dysk_src}" 22 | echo "INF: found dysk source @ ${dysk_src}. will pull to ensure latest udpates" 23 | git pull 24 | fi 25 | } 26 | 27 | function build_dysk() 28 | { 29 | clone_dysk 30 | if [[ ! -d "/lib/modules/$(uname -r)" ]]; then 31 | echo "INF: headers for $(uname -r) were not found, downloading" 32 | apt update && apt install linux-headers-$(uname -r) 33 | fi 34 | 35 | cd "${dysk_src}/module/" 36 | if [[ ! -f "${dysk_src}/module/dysk.ko" ]]; then 37 | echo "INF: ${dysk_src}/module/dysk.ko is not there, building it" 38 | make clean && make 39 | fi 40 | } 41 | 42 | function dysk_bin_ok() 43 | { 44 | local dysk_ver_m="" 45 | 46 | # Source there? 47 | if [[ ! -d "${dysk_src}" ]]; then 48 | echo -n "0" 49 | return 50 | fi 51 | 52 | # built before? 53 | if [[ ! -f "${dysk_src}/module/dysk.ko" ]];then 54 | echo -n "0" 55 | return 56 | fi 57 | 58 | cd "${dysk_src}/module/" 59 | 60 | # Match version magic? 61 | dysk_ver_m="$(modinfo dysk.ko | grep vermagic | awk '{print $2}')" 62 | if [[ "$dysk_ver_m" != "$(uname -r)" ]]; then 63 | echo -n "0" 64 | fi 65 | } 66 | function install_dysk_module() 67 | { 68 | #if installed 69 | if [[ "" == "$(lsmod | grep dysk)" ]]; then 70 | # if bin ok 71 | if [[ "0" == "$(dysk_bin_ok)" ]];then 72 | build_dysk 73 | fi 74 | # install 75 | echo "INF: installing dysk kernel module tag:${dysk_tag}" 76 | insmod "${dysk_src}/module/dysk.ko" 77 | else 78 | echo "INF: dysk found on this machine" 79 | fi 80 | 81 | #modinfo dysk 82 | } 83 | 84 | function main() 85 | { 86 | install_dysk_module 87 | if [[ "STANDALONE" != "${install_mode}" ]]; then 88 | #https://github.com/kubernetes/kubernetes/issues/17182 89 | # if we are running on kubernetes cluster as a daemon set we should 90 | # not exit otherwise, container will restart and goes into crashloop (even if exit code is 0) 91 | while true; do echo "install done, daemonset sleeping" && sleep 300; done 92 | fi 93 | } 94 | 95 | #start here.. 96 | main 97 | 98 | -------------------------------------------------------------------------------- /dyskctl/vendor/github.com/Azure/go-autorest/autorest/adal/persist.go: -------------------------------------------------------------------------------- 1 | package adal 2 | 3 | // Copyright 2017 Microsoft Corporation 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | import ( 18 | "encoding/json" 19 | "fmt" 20 | "io/ioutil" 21 | "os" 22 | "path/filepath" 23 | ) 24 | 25 | // LoadToken restores a Token object from a file located at 'path'. 26 | func LoadToken(path string) (*Token, error) { 27 | file, err := os.Open(path) 28 | if err != nil { 29 | return nil, fmt.Errorf("failed to open file (%s) while loading token: %v", path, err) 30 | } 31 | defer file.Close() 32 | 33 | var token Token 34 | 35 | dec := json.NewDecoder(file) 36 | if err = dec.Decode(&token); err != nil { 37 | return nil, fmt.Errorf("failed to decode contents of file (%s) into Token representation: %v", path, err) 38 | } 39 | return &token, nil 40 | } 41 | 42 | // SaveToken persists an oauth token at the given location on disk. 43 | // It moves the new file into place so it can safely be used to replace an existing file 44 | // that maybe accessed by multiple processes. 45 | func SaveToken(path string, mode os.FileMode, token Token) error { 46 | dir := filepath.Dir(path) 47 | err := os.MkdirAll(dir, os.ModePerm) 48 | if err != nil { 49 | return fmt.Errorf("failed to create directory (%s) to store token in: %v", dir, err) 50 | } 51 | 52 | newFile, err := ioutil.TempFile(dir, "token") 53 | if err != nil { 54 | return fmt.Errorf("failed to create the temp file to write the token: %v", err) 55 | } 56 | tempPath := newFile.Name() 57 | 58 | if err := json.NewEncoder(newFile).Encode(token); err != nil { 59 | return fmt.Errorf("failed to encode token to file (%s) while saving token: %v", tempPath, err) 60 | } 61 | if err := newFile.Close(); err != nil { 62 | return fmt.Errorf("failed to close temp file %s: %v", tempPath, err) 63 | } 64 | 65 | // Atomic replace to avoid multi-writer file corruptions 66 | if err := os.Rename(tempPath, path); err != nil { 67 | return fmt.Errorf("failed to move temporary token to desired output location. src=%s dst=%s: %v", tempPath, path, err) 68 | } 69 | if err := os.Chmod(path, mode); err != nil { 70 | return fmt.Errorf("failed to chmod the token file %s: %v", path, err) 71 | } 72 | return nil 73 | } 74 | -------------------------------------------------------------------------------- /dyskctl/vendor/github.com/pelletier/go-toml/token.go: -------------------------------------------------------------------------------- 1 | package toml 2 | 3 | import ( 4 | "fmt" 5 | "strconv" 6 | "unicode" 7 | ) 8 | 9 | // Define tokens 10 | type tokenType int 11 | 12 | const ( 13 | eof = -(iota + 1) 14 | ) 15 | 16 | const ( 17 | tokenError tokenType = iota 18 | tokenEOF 19 | tokenComment 20 | tokenKey 21 | tokenString 22 | tokenInteger 23 | tokenTrue 24 | tokenFalse 25 | tokenFloat 26 | tokenEqual 27 | tokenLeftBracket 28 | tokenRightBracket 29 | tokenLeftCurlyBrace 30 | tokenRightCurlyBrace 31 | tokenLeftParen 32 | tokenRightParen 33 | tokenDoubleLeftBracket 34 | tokenDoubleRightBracket 35 | tokenDate 36 | tokenKeyGroup 37 | tokenKeyGroupArray 38 | tokenComma 39 | tokenColon 40 | tokenDollar 41 | tokenStar 42 | tokenQuestion 43 | tokenDot 44 | tokenDotDot 45 | tokenEOL 46 | ) 47 | 48 | var tokenTypeNames = []string{ 49 | "Error", 50 | "EOF", 51 | "Comment", 52 | "Key", 53 | "String", 54 | "Integer", 55 | "True", 56 | "False", 57 | "Float", 58 | "=", 59 | "[", 60 | "]", 61 | "{", 62 | "}", 63 | "(", 64 | ")", 65 | "]]", 66 | "[[", 67 | "Date", 68 | "KeyGroup", 69 | "KeyGroupArray", 70 | ",", 71 | ":", 72 | "$", 73 | "*", 74 | "?", 75 | ".", 76 | "..", 77 | "EOL", 78 | } 79 | 80 | type token struct { 81 | Position 82 | typ tokenType 83 | val string 84 | } 85 | 86 | func (tt tokenType) String() string { 87 | idx := int(tt) 88 | if idx < len(tokenTypeNames) { 89 | return tokenTypeNames[idx] 90 | } 91 | return "Unknown" 92 | } 93 | 94 | func (t token) Int() int { 95 | if result, err := strconv.Atoi(t.val); err != nil { 96 | panic(err) 97 | } else { 98 | return result 99 | } 100 | } 101 | 102 | func (t token) String() string { 103 | switch t.typ { 104 | case tokenEOF: 105 | return "EOF" 106 | case tokenError: 107 | return t.val 108 | } 109 | 110 | return fmt.Sprintf("%q", t.val) 111 | } 112 | 113 | func isSpace(r rune) bool { 114 | return r == ' ' || r == '\t' 115 | } 116 | 117 | func isAlphanumeric(r rune) bool { 118 | return unicode.IsLetter(r) || r == '_' 119 | } 120 | 121 | func isKeyChar(r rune) bool { 122 | // Keys start with the first character that isn't whitespace or [ and end 123 | // with the last non-whitespace character before the equals sign. Keys 124 | // cannot contain a # character." 125 | return !(r == '\r' || r == '\n' || r == eof || r == '=') 126 | } 127 | 128 | func isKeyStartChar(r rune) bool { 129 | return !(isSpace(r) || r == '\r' || r == '\n' || r == eof || r == '[') 130 | } 131 | 132 | func isDigit(r rune) bool { 133 | return unicode.IsNumber(r) 134 | } 135 | 136 | func isHexDigit(r rune) bool { 137 | return isDigit(r) || 138 | (r >= 'a' && r <= 'f') || 139 | (r >= 'A' && r <= 'F') 140 | } 141 | -------------------------------------------------------------------------------- /dyskctl/vendor/github.com/Azure/go-autorest/autorest/adal/config.go: -------------------------------------------------------------------------------- 1 | package adal 2 | 3 | // Copyright 2017 Microsoft Corporation 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | import ( 18 | "fmt" 19 | "net/url" 20 | ) 21 | 22 | const ( 23 | activeDirectoryAPIVersion = "1.0" 24 | ) 25 | 26 | // OAuthConfig represents the endpoints needed 27 | // in OAuth operations 28 | type OAuthConfig struct { 29 | AuthorityEndpoint url.URL 30 | AuthorizeEndpoint url.URL 31 | TokenEndpoint url.URL 32 | DeviceCodeEndpoint url.URL 33 | } 34 | 35 | // IsZero returns true if the OAuthConfig object is zero-initialized. 36 | func (oac OAuthConfig) IsZero() bool { 37 | return oac == OAuthConfig{} 38 | } 39 | 40 | func validateStringParam(param, name string) error { 41 | if len(param) == 0 { 42 | return fmt.Errorf("parameter '" + name + "' cannot be empty") 43 | } 44 | return nil 45 | } 46 | 47 | // NewOAuthConfig returns an OAuthConfig with tenant specific urls 48 | func NewOAuthConfig(activeDirectoryEndpoint, tenantID string) (*OAuthConfig, error) { 49 | if err := validateStringParam(activeDirectoryEndpoint, "activeDirectoryEndpoint"); err != nil { 50 | return nil, err 51 | } 52 | // it's legal for tenantID to be empty so don't validate it 53 | const activeDirectoryEndpointTemplate = "%s/oauth2/%s?api-version=%s" 54 | u, err := url.Parse(activeDirectoryEndpoint) 55 | if err != nil { 56 | return nil, err 57 | } 58 | authorityURL, err := u.Parse(tenantID) 59 | if err != nil { 60 | return nil, err 61 | } 62 | authorizeURL, err := u.Parse(fmt.Sprintf(activeDirectoryEndpointTemplate, tenantID, "authorize", activeDirectoryAPIVersion)) 63 | if err != nil { 64 | return nil, err 65 | } 66 | tokenURL, err := u.Parse(fmt.Sprintf(activeDirectoryEndpointTemplate, tenantID, "token", activeDirectoryAPIVersion)) 67 | if err != nil { 68 | return nil, err 69 | } 70 | deviceCodeURL, err := u.Parse(fmt.Sprintf(activeDirectoryEndpointTemplate, tenantID, "devicecode", activeDirectoryAPIVersion)) 71 | if err != nil { 72 | return nil, err 73 | } 74 | 75 | return &OAuthConfig{ 76 | AuthorityEndpoint: *authorityURL, 77 | AuthorizeEndpoint: *authorizeURL, 78 | TokenEndpoint: *tokenURL, 79 | DeviceCodeEndpoint: *deviceCodeURL, 80 | }, nil 81 | } 82 | -------------------------------------------------------------------------------- /dyskctl/vendor/github.com/dgrijalva/jwt-go/hmac.go: -------------------------------------------------------------------------------- 1 | package jwt 2 | 3 | import ( 4 | "crypto" 5 | "crypto/hmac" 6 | "errors" 7 | ) 8 | 9 | // Implements the HMAC-SHA family of signing methods signing methods 10 | type SigningMethodHMAC struct { 11 | Name string 12 | Hash crypto.Hash 13 | } 14 | 15 | // Specific instances for HS256 and company 16 | var ( 17 | SigningMethodHS256 *SigningMethodHMAC 18 | SigningMethodHS384 *SigningMethodHMAC 19 | SigningMethodHS512 *SigningMethodHMAC 20 | ErrSignatureInvalid = errors.New("signature is invalid") 21 | ) 22 | 23 | func init() { 24 | // HS256 25 | SigningMethodHS256 = &SigningMethodHMAC{"HS256", crypto.SHA256} 26 | RegisterSigningMethod(SigningMethodHS256.Alg(), func() SigningMethod { 27 | return SigningMethodHS256 28 | }) 29 | 30 | // HS384 31 | SigningMethodHS384 = &SigningMethodHMAC{"HS384", crypto.SHA384} 32 | RegisterSigningMethod(SigningMethodHS384.Alg(), func() SigningMethod { 33 | return SigningMethodHS384 34 | }) 35 | 36 | // HS512 37 | SigningMethodHS512 = &SigningMethodHMAC{"HS512", crypto.SHA512} 38 | RegisterSigningMethod(SigningMethodHS512.Alg(), func() SigningMethod { 39 | return SigningMethodHS512 40 | }) 41 | } 42 | 43 | func (m *SigningMethodHMAC) Alg() string { 44 | return m.Name 45 | } 46 | 47 | // Verify the signature of HSXXX tokens. Returns nil if the signature is valid. 48 | func (m *SigningMethodHMAC) Verify(signingString, signature string, key interface{}) error { 49 | // Verify the key is the right type 50 | keyBytes, ok := key.([]byte) 51 | if !ok { 52 | return ErrInvalidKeyType 53 | } 54 | 55 | // Decode signature, for comparison 56 | sig, err := DecodeSegment(signature) 57 | if err != nil { 58 | return err 59 | } 60 | 61 | // Can we use the specified hashing method? 62 | if !m.Hash.Available() { 63 | return ErrHashUnavailable 64 | } 65 | 66 | // This signing method is symmetric, so we validate the signature 67 | // by reproducing the signature from the signing string and key, then 68 | // comparing that against the provided signature. 69 | hasher := hmac.New(m.Hash.New, keyBytes) 70 | hasher.Write([]byte(signingString)) 71 | if !hmac.Equal(sig, hasher.Sum(nil)) { 72 | return ErrSignatureInvalid 73 | } 74 | 75 | // No validation errors. Signature is good. 76 | return nil 77 | } 78 | 79 | // Implements the Sign method from SigningMethod for this signing method. 80 | // Key must be []byte 81 | func (m *SigningMethodHMAC) Sign(signingString string, key interface{}) (string, error) { 82 | if keyBytes, ok := key.([]byte); ok { 83 | if !m.Hash.Available() { 84 | return "", ErrHashUnavailable 85 | } 86 | 87 | hasher := hmac.New(m.Hash.New, keyBytes) 88 | hasher.Write([]byte(signingString)) 89 | 90 | return EncodeSegment(hasher.Sum(nil)), nil 91 | } 92 | 93 | return "", ErrInvalidKey 94 | } 95 | -------------------------------------------------------------------------------- /dyskctl/vendor/gopkg.in/yaml.v2/writerc.go: -------------------------------------------------------------------------------- 1 | package yaml 2 | 3 | // Set the writer error and return false. 4 | func yaml_emitter_set_writer_error(emitter *yaml_emitter_t, problem string) bool { 5 | emitter.error = yaml_WRITER_ERROR 6 | emitter.problem = problem 7 | return false 8 | } 9 | 10 | // Flush the output buffer. 11 | func yaml_emitter_flush(emitter *yaml_emitter_t) bool { 12 | if emitter.write_handler == nil { 13 | panic("write handler not set") 14 | } 15 | 16 | // Check if the buffer is empty. 17 | if emitter.buffer_pos == 0 { 18 | return true 19 | } 20 | 21 | // If the output encoding is UTF-8, we don't need to recode the buffer. 22 | if emitter.encoding == yaml_UTF8_ENCODING { 23 | if err := emitter.write_handler(emitter, emitter.buffer[:emitter.buffer_pos]); err != nil { 24 | return yaml_emitter_set_writer_error(emitter, "write error: "+err.Error()) 25 | } 26 | emitter.buffer_pos = 0 27 | return true 28 | } 29 | 30 | // Recode the buffer into the raw buffer. 31 | var low, high int 32 | if emitter.encoding == yaml_UTF16LE_ENCODING { 33 | low, high = 0, 1 34 | } else { 35 | high, low = 1, 0 36 | } 37 | 38 | pos := 0 39 | for pos < emitter.buffer_pos { 40 | // See the "reader.c" code for more details on UTF-8 encoding. Note 41 | // that we assume that the buffer contains a valid UTF-8 sequence. 42 | 43 | // Read the next UTF-8 character. 44 | octet := emitter.buffer[pos] 45 | 46 | var w int 47 | var value rune 48 | switch { 49 | case octet&0x80 == 0x00: 50 | w, value = 1, rune(octet&0x7F) 51 | case octet&0xE0 == 0xC0: 52 | w, value = 2, rune(octet&0x1F) 53 | case octet&0xF0 == 0xE0: 54 | w, value = 3, rune(octet&0x0F) 55 | case octet&0xF8 == 0xF0: 56 | w, value = 4, rune(octet&0x07) 57 | } 58 | for k := 1; k < w; k++ { 59 | octet = emitter.buffer[pos+k] 60 | value = (value << 6) + (rune(octet) & 0x3F) 61 | } 62 | pos += w 63 | 64 | // Write the character. 65 | if value < 0x10000 { 66 | var b [2]byte 67 | b[high] = byte(value >> 8) 68 | b[low] = byte(value & 0xFF) 69 | emitter.raw_buffer = append(emitter.raw_buffer, b[0], b[1]) 70 | } else { 71 | // Write the character using a surrogate pair (check "reader.c"). 72 | var b [4]byte 73 | value -= 0x10000 74 | b[high] = byte(0xD8 + (value >> 18)) 75 | b[low] = byte((value >> 10) & 0xFF) 76 | b[high+2] = byte(0xDC + ((value >> 8) & 0xFF)) 77 | b[low+2] = byte(value & 0xFF) 78 | emitter.raw_buffer = append(emitter.raw_buffer, b[0], b[1], b[2], b[3]) 79 | } 80 | } 81 | 82 | // Write the raw buffer. 83 | if err := emitter.write_handler(emitter, emitter.raw_buffer); err != nil { 84 | return yaml_emitter_set_writer_error(emitter, "write error: "+err.Error()) 85 | } 86 | emitter.buffer_pos = 0 87 | emitter.raw_buffer = emitter.raw_buffer[:0] 88 | return true 89 | } 90 | -------------------------------------------------------------------------------- /dyskctl/vendor/github.com/inconshreveable/mousetrap/trap_windows.go: -------------------------------------------------------------------------------- 1 | // +build windows 2 | // +build !go1.4 3 | 4 | package mousetrap 5 | 6 | import ( 7 | "fmt" 8 | "os" 9 | "syscall" 10 | "unsafe" 11 | ) 12 | 13 | const ( 14 | // defined by the Win32 API 15 | th32cs_snapprocess uintptr = 0x2 16 | ) 17 | 18 | var ( 19 | kernel = syscall.MustLoadDLL("kernel32.dll") 20 | CreateToolhelp32Snapshot = kernel.MustFindProc("CreateToolhelp32Snapshot") 21 | Process32First = kernel.MustFindProc("Process32FirstW") 22 | Process32Next = kernel.MustFindProc("Process32NextW") 23 | ) 24 | 25 | // ProcessEntry32 structure defined by the Win32 API 26 | type processEntry32 struct { 27 | dwSize uint32 28 | cntUsage uint32 29 | th32ProcessID uint32 30 | th32DefaultHeapID int 31 | th32ModuleID uint32 32 | cntThreads uint32 33 | th32ParentProcessID uint32 34 | pcPriClassBase int32 35 | dwFlags uint32 36 | szExeFile [syscall.MAX_PATH]uint16 37 | } 38 | 39 | func getProcessEntry(pid int) (pe *processEntry32, err error) { 40 | snapshot, _, e1 := CreateToolhelp32Snapshot.Call(th32cs_snapprocess, uintptr(0)) 41 | if snapshot == uintptr(syscall.InvalidHandle) { 42 | err = fmt.Errorf("CreateToolhelp32Snapshot: %v", e1) 43 | return 44 | } 45 | defer syscall.CloseHandle(syscall.Handle(snapshot)) 46 | 47 | var processEntry processEntry32 48 | processEntry.dwSize = uint32(unsafe.Sizeof(processEntry)) 49 | ok, _, e1 := Process32First.Call(snapshot, uintptr(unsafe.Pointer(&processEntry))) 50 | if ok == 0 { 51 | err = fmt.Errorf("Process32First: %v", e1) 52 | return 53 | } 54 | 55 | for { 56 | if processEntry.th32ProcessID == uint32(pid) { 57 | pe = &processEntry 58 | return 59 | } 60 | 61 | ok, _, e1 = Process32Next.Call(snapshot, uintptr(unsafe.Pointer(&processEntry))) 62 | if ok == 0 { 63 | err = fmt.Errorf("Process32Next: %v", e1) 64 | return 65 | } 66 | } 67 | } 68 | 69 | func getppid() (pid int, err error) { 70 | pe, err := getProcessEntry(os.Getpid()) 71 | if err != nil { 72 | return 73 | } 74 | 75 | pid = int(pe.th32ParentProcessID) 76 | return 77 | } 78 | 79 | // StartedByExplorer returns true if the program was invoked by the user double-clicking 80 | // on the executable from explorer.exe 81 | // 82 | // It is conservative and returns false if any of the internal calls fail. 83 | // It does not guarantee that the program was run from a terminal. It only can tell you 84 | // whether it was launched from explorer.exe 85 | func StartedByExplorer() bool { 86 | ppid, err := getppid() 87 | if err != nil { 88 | return false 89 | } 90 | 91 | pe, err := getProcessEntry(ppid) 92 | if err != nil { 93 | return false 94 | } 95 | 96 | name := syscall.UTF16ToString(pe.szExeFile[:]) 97 | return name == "explorer.exe" 98 | } 99 | -------------------------------------------------------------------------------- /dyskctl/vendor/github.com/spf13/afero/os.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2014 Steve Francia . 2 | // Copyright 2013 tsuru authors. All rights reserved. 3 | // 4 | // Licensed under the Apache License, Version 2.0 (the "License"); 5 | // you may not use this file except in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package afero 16 | 17 | import ( 18 | "os" 19 | "time" 20 | ) 21 | 22 | // OsFs is a Fs implementation that uses functions provided by the os package. 23 | // 24 | // For details in any method, check the documentation of the os package 25 | // (http://golang.org/pkg/os/). 26 | type OsFs struct{} 27 | 28 | func NewOsFs() Fs { 29 | return &OsFs{} 30 | } 31 | 32 | func (OsFs) Name() string { return "OsFs" } 33 | 34 | func (OsFs) Create(name string) (File, error) { 35 | f, e := os.Create(name) 36 | if f == nil { 37 | // while this looks strange, we need to return a bare nil (of type nil) not 38 | // a nil value of type *os.File or nil won't be nil 39 | return nil, e 40 | } 41 | return f, e 42 | } 43 | 44 | func (OsFs) Mkdir(name string, perm os.FileMode) error { 45 | return os.Mkdir(name, perm) 46 | } 47 | 48 | func (OsFs) MkdirAll(path string, perm os.FileMode) error { 49 | return os.MkdirAll(path, perm) 50 | } 51 | 52 | func (OsFs) Open(name string) (File, error) { 53 | f, e := os.Open(name) 54 | if f == nil { 55 | // while this looks strange, we need to return a bare nil (of type nil) not 56 | // a nil value of type *os.File or nil won't be nil 57 | return nil, e 58 | } 59 | return f, e 60 | } 61 | 62 | func (OsFs) OpenFile(name string, flag int, perm os.FileMode) (File, error) { 63 | f, e := os.OpenFile(name, flag, perm) 64 | if f == nil { 65 | // while this looks strange, we need to return a bare nil (of type nil) not 66 | // a nil value of type *os.File or nil won't be nil 67 | return nil, e 68 | } 69 | return f, e 70 | } 71 | 72 | func (OsFs) Remove(name string) error { 73 | return os.Remove(name) 74 | } 75 | 76 | func (OsFs) RemoveAll(path string) error { 77 | return os.RemoveAll(path) 78 | } 79 | 80 | func (OsFs) Rename(oldname, newname string) error { 81 | return os.Rename(oldname, newname) 82 | } 83 | 84 | func (OsFs) Stat(name string) (os.FileInfo, error) { 85 | return os.Stat(name) 86 | } 87 | 88 | func (OsFs) Chmod(name string, mode os.FileMode) error { 89 | return os.Chmod(name, mode) 90 | } 91 | 92 | func (OsFs) Chtimes(name string, atime time.Time, mtime time.Time) error { 93 | return os.Chtimes(name, atime, mtime) 94 | } 95 | -------------------------------------------------------------------------------- /dyskctl/vendor/github.com/dgrijalva/jwt-go/rsa.go: -------------------------------------------------------------------------------- 1 | package jwt 2 | 3 | import ( 4 | "crypto" 5 | "crypto/rand" 6 | "crypto/rsa" 7 | ) 8 | 9 | // Implements the RSA family of signing methods signing methods 10 | type SigningMethodRSA struct { 11 | Name string 12 | Hash crypto.Hash 13 | } 14 | 15 | // Specific instances for RS256 and company 16 | var ( 17 | SigningMethodRS256 *SigningMethodRSA 18 | SigningMethodRS384 *SigningMethodRSA 19 | SigningMethodRS512 *SigningMethodRSA 20 | ) 21 | 22 | func init() { 23 | // RS256 24 | SigningMethodRS256 = &SigningMethodRSA{"RS256", crypto.SHA256} 25 | RegisterSigningMethod(SigningMethodRS256.Alg(), func() SigningMethod { 26 | return SigningMethodRS256 27 | }) 28 | 29 | // RS384 30 | SigningMethodRS384 = &SigningMethodRSA{"RS384", crypto.SHA384} 31 | RegisterSigningMethod(SigningMethodRS384.Alg(), func() SigningMethod { 32 | return SigningMethodRS384 33 | }) 34 | 35 | // RS512 36 | SigningMethodRS512 = &SigningMethodRSA{"RS512", crypto.SHA512} 37 | RegisterSigningMethod(SigningMethodRS512.Alg(), func() SigningMethod { 38 | return SigningMethodRS512 39 | }) 40 | } 41 | 42 | func (m *SigningMethodRSA) Alg() string { 43 | return m.Name 44 | } 45 | 46 | // Implements the Verify method from SigningMethod 47 | // For this signing method, must be an rsa.PublicKey structure. 48 | func (m *SigningMethodRSA) Verify(signingString, signature string, key interface{}) error { 49 | var err error 50 | 51 | // Decode the signature 52 | var sig []byte 53 | if sig, err = DecodeSegment(signature); err != nil { 54 | return err 55 | } 56 | 57 | var rsaKey *rsa.PublicKey 58 | var ok bool 59 | 60 | if rsaKey, ok = key.(*rsa.PublicKey); !ok { 61 | return ErrInvalidKeyType 62 | } 63 | 64 | // Create hasher 65 | if !m.Hash.Available() { 66 | return ErrHashUnavailable 67 | } 68 | hasher := m.Hash.New() 69 | hasher.Write([]byte(signingString)) 70 | 71 | // Verify the signature 72 | return rsa.VerifyPKCS1v15(rsaKey, m.Hash, hasher.Sum(nil), sig) 73 | } 74 | 75 | // Implements the Sign method from SigningMethod 76 | // For this signing method, must be an rsa.PrivateKey structure. 77 | func (m *SigningMethodRSA) Sign(signingString string, key interface{}) (string, error) { 78 | var rsaKey *rsa.PrivateKey 79 | var ok bool 80 | 81 | // Validate type of key 82 | if rsaKey, ok = key.(*rsa.PrivateKey); !ok { 83 | return "", ErrInvalidKey 84 | } 85 | 86 | // Create the hasher 87 | if !m.Hash.Available() { 88 | return "", ErrHashUnavailable 89 | } 90 | 91 | hasher := m.Hash.New() 92 | hasher.Write([]byte(signingString)) 93 | 94 | // Sign the string and return the encoded bytes 95 | if sigBytes, err := rsa.SignPKCS1v15(rand.Reader, rsaKey, m.Hash, hasher.Sum(nil)); err == nil { 96 | return EncodeSegment(sigBytes), nil 97 | } else { 98 | return "", err 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /tools/verification/verify.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -eo pipefail 4 | 5 | DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" 6 | V_SETTINGS=${V_SETTINGS:-"${DIR}/settings.json"} 7 | V_RUN_TYPE="$1" 8 | 9 | V_ACCOUNT_NAME="" 10 | V_ACCOUNT_KEY="" 11 | 12 | V_TESTS=() 13 | V_TEST_FORMAT="{\"name\" : \"%s\", \"script\" : \"%s\" , \"type\" : \"%s\" }" 14 | 15 | DYSKCTL="${DIR}/../../dyskctl/dyskctl" 16 | 17 | function ensure_ready() 18 | { 19 | if [[ "" == "$(which jq)" ]];then 20 | echo "jq does not exist, please install jq" 21 | exit 1 22 | fi 23 | 24 | if [[ "" == "$(which fio)" ]];then 25 | echo "fio does not exist, please install fio" 26 | exit 1 27 | fi 28 | 29 | if [[ ! -f "${V_SETTINGS}" ]]; then 30 | echo "settings file at ${V_SETTINGS} does not exist" 31 | exit 1 32 | fi 33 | 34 | echo "using settings file:${V_SETTINGS}" 35 | V_ACCOUNT_NAME="$(cat "${V_SETTINGS}" | jq -r '.account //empty')" 36 | V_ACCOUNT_KEY="$(cat "${V_SETTINGS}" | jq -r '.key //empty')" 37 | 38 | if [[ -z "$V_ACCOUNT_NAME}" || -z "$V_ACCOUNT_KEY" ]]; then 39 | echo "invalid account name or key" 40 | exit 1 41 | fi 42 | } 43 | 44 | function add_test() 45 | { 46 | local test_name="$1" 47 | local test_script="$2" 48 | local test_type="$3" 49 | 50 | local v_test="$(printf "${V_TEST_FORMAT}" "${test_name}" "${test_script}" "${test_type}")" 51 | 52 | V_TESTS+=("${v_test}") 53 | } 54 | 55 | 56 | function run_tests() 57 | { 58 | for vt in "${V_TESTS[@]}" 59 | do 60 | local test_name="$(echo -n "${vt}" | jq -r '.name //empty')" 61 | local test_script="$(echo -n "${vt}" | jq -r '.script //empty')" 62 | local test_type="$(echo -n "${vt}" | jq -r '.type //empty')" 63 | if [[ -z "${test_name}" || ! -f "${DIR}/${test_script}" ]];then 64 | echo "skipping test:[${test_name}] script:[${test_script}] because name is empty script file does not exist" 65 | else 66 | if [[ "${V_RUN_TYPE}" == "${test_type}" ]];then 67 | echo "==>START TEST - ${test_type}: ${test_name} SCRIPT:${test_script}" 68 | "${DIR}/${test_script}" "${V_ACCOUNT_NAME}" "${V_ACCOUNT_KEY}" "${DYSKCTL}" 69 | echo "==>END TEST - ${test_type}: ${test_name} SCRIPT:${test_script}" 70 | fi 71 | fi 72 | done 73 | } 74 | 75 | 76 | #verify tests 77 | add_test "Simple add/remove" "v_simple_add_remove.sh" "VERIFY" 78 | add_test "mount read only" "v_mount_ro.sh" "VERIFY" 79 | add_test "Add, format, remove, add another" "v_add_format_remove_add.sh" "VERIFY" 80 | add_test "add remove 128 dysks" "v_add_remove_128dysks.sh" "VERIFY" 81 | add_test "Add/Format/Remove 10 dysks" "v_add_format_remove_10dysks.sh" "VERIFY" 82 | 83 | #perf tests 84 | #add_test "Basic perf tests" "p_basic_io.sh" "PERF" 85 | 86 | 87 | # START HERE 88 | ensure_ready 89 | 90 | if [[ -z "${V_RUN_TYPE}" ]]; then 91 | echo "No run type, setting it to VERIFY" 92 | V_RUN_TYPE="VERIFY" 93 | fi 94 | 95 | run_tests 96 | 97 | -------------------------------------------------------------------------------- /dyskctl/vendor/gopkg.in/yaml.v2/sorter.go: -------------------------------------------------------------------------------- 1 | package yaml 2 | 3 | import ( 4 | "reflect" 5 | "unicode" 6 | ) 7 | 8 | type keyList []reflect.Value 9 | 10 | func (l keyList) Len() int { return len(l) } 11 | func (l keyList) Swap(i, j int) { l[i], l[j] = l[j], l[i] } 12 | func (l keyList) Less(i, j int) bool { 13 | a := l[i] 14 | b := l[j] 15 | ak := a.Kind() 16 | bk := b.Kind() 17 | for (ak == reflect.Interface || ak == reflect.Ptr) && !a.IsNil() { 18 | a = a.Elem() 19 | ak = a.Kind() 20 | } 21 | for (bk == reflect.Interface || bk == reflect.Ptr) && !b.IsNil() { 22 | b = b.Elem() 23 | bk = b.Kind() 24 | } 25 | af, aok := keyFloat(a) 26 | bf, bok := keyFloat(b) 27 | if aok && bok { 28 | if af != bf { 29 | return af < bf 30 | } 31 | if ak != bk { 32 | return ak < bk 33 | } 34 | return numLess(a, b) 35 | } 36 | if ak != reflect.String || bk != reflect.String { 37 | return ak < bk 38 | } 39 | ar, br := []rune(a.String()), []rune(b.String()) 40 | for i := 0; i < len(ar) && i < len(br); i++ { 41 | if ar[i] == br[i] { 42 | continue 43 | } 44 | al := unicode.IsLetter(ar[i]) 45 | bl := unicode.IsLetter(br[i]) 46 | if al && bl { 47 | return ar[i] < br[i] 48 | } 49 | if al || bl { 50 | return bl 51 | } 52 | var ai, bi int 53 | var an, bn int64 54 | for ai = i; ai < len(ar) && unicode.IsDigit(ar[ai]); ai++ { 55 | an = an*10 + int64(ar[ai]-'0') 56 | } 57 | for bi = i; bi < len(br) && unicode.IsDigit(br[bi]); bi++ { 58 | bn = bn*10 + int64(br[bi]-'0') 59 | } 60 | if an != bn { 61 | return an < bn 62 | } 63 | if ai != bi { 64 | return ai < bi 65 | } 66 | return ar[i] < br[i] 67 | } 68 | return len(ar) < len(br) 69 | } 70 | 71 | // keyFloat returns a float value for v if it is a number/bool 72 | // and whether it is a number/bool or not. 73 | func keyFloat(v reflect.Value) (f float64, ok bool) { 74 | switch v.Kind() { 75 | case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 76 | return float64(v.Int()), true 77 | case reflect.Float32, reflect.Float64: 78 | return v.Float(), true 79 | case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: 80 | return float64(v.Uint()), true 81 | case reflect.Bool: 82 | if v.Bool() { 83 | return 1, true 84 | } 85 | return 0, true 86 | } 87 | return 0, false 88 | } 89 | 90 | // numLess returns whether a < b. 91 | // a and b must necessarily have the same kind. 92 | func numLess(a, b reflect.Value) bool { 93 | switch a.Kind() { 94 | case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 95 | return a.Int() < b.Int() 96 | case reflect.Float32, reflect.Float64: 97 | return a.Float() < b.Float() 98 | case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: 99 | return a.Uint() < b.Uint() 100 | case reflect.Bool: 101 | return !a.Bool() && b.Bool() 102 | } 103 | panic("not a number") 104 | } 105 | -------------------------------------------------------------------------------- /dyskctl/vendor/github.com/dgrijalva/jwt-go/map_claims.go: -------------------------------------------------------------------------------- 1 | package jwt 2 | 3 | import ( 4 | "encoding/json" 5 | "errors" 6 | // "fmt" 7 | ) 8 | 9 | // Claims type that uses the map[string]interface{} for JSON decoding 10 | // This is the default claims type if you don't supply one 11 | type MapClaims map[string]interface{} 12 | 13 | // Compares the aud claim against cmp. 14 | // If required is false, this method will return true if the value matches or is unset 15 | func (m MapClaims) VerifyAudience(cmp string, req bool) bool { 16 | aud, _ := m["aud"].(string) 17 | return verifyAud(aud, cmp, req) 18 | } 19 | 20 | // Compares the exp claim against cmp. 21 | // If required is false, this method will return true if the value matches or is unset 22 | func (m MapClaims) VerifyExpiresAt(cmp int64, req bool) bool { 23 | switch exp := m["exp"].(type) { 24 | case float64: 25 | return verifyExp(int64(exp), cmp, req) 26 | case json.Number: 27 | v, _ := exp.Int64() 28 | return verifyExp(v, cmp, req) 29 | } 30 | return req == false 31 | } 32 | 33 | // Compares the iat claim against cmp. 34 | // If required is false, this method will return true if the value matches or is unset 35 | func (m MapClaims) VerifyIssuedAt(cmp int64, req bool) bool { 36 | switch iat := m["iat"].(type) { 37 | case float64: 38 | return verifyIat(int64(iat), cmp, req) 39 | case json.Number: 40 | v, _ := iat.Int64() 41 | return verifyIat(v, cmp, req) 42 | } 43 | return req == false 44 | } 45 | 46 | // Compares the iss claim against cmp. 47 | // If required is false, this method will return true if the value matches or is unset 48 | func (m MapClaims) VerifyIssuer(cmp string, req bool) bool { 49 | iss, _ := m["iss"].(string) 50 | return verifyIss(iss, cmp, req) 51 | } 52 | 53 | // Compares the nbf claim against cmp. 54 | // If required is false, this method will return true if the value matches or is unset 55 | func (m MapClaims) VerifyNotBefore(cmp int64, req bool) bool { 56 | switch nbf := m["nbf"].(type) { 57 | case float64: 58 | return verifyNbf(int64(nbf), cmp, req) 59 | case json.Number: 60 | v, _ := nbf.Int64() 61 | return verifyNbf(v, cmp, req) 62 | } 63 | return req == false 64 | } 65 | 66 | // Validates time based claims "exp, iat, nbf". 67 | // There is no accounting for clock skew. 68 | // As well, if any of the above claims are not in the token, it will still 69 | // be considered a valid claim. 70 | func (m MapClaims) Valid() error { 71 | vErr := new(ValidationError) 72 | now := TimeFunc().Unix() 73 | 74 | if m.VerifyExpiresAt(now, false) == false { 75 | vErr.Inner = errors.New("Token is expired") 76 | vErr.Errors |= ValidationErrorExpired 77 | } 78 | 79 | if m.VerifyIssuedAt(now, false) == false { 80 | vErr.Inner = errors.New("Token used before issued") 81 | vErr.Errors |= ValidationErrorIssuedAt 82 | } 83 | 84 | if m.VerifyNotBefore(now, false) == false { 85 | vErr.Inner = errors.New("Token is not valid yet") 86 | vErr.Errors |= ValidationErrorNotValidYet 87 | } 88 | 89 | if vErr.valid() { 90 | return nil 91 | } 92 | 93 | return vErr 94 | } 95 | -------------------------------------------------------------------------------- /docs/design.md: -------------------------------------------------------------------------------- 1 | # Design # 2 | 3 | ## Contrasting Dysk to Existing Data Disks ## 4 | 5 | Existing data disks follow the following path: 6 | 1. Disks are attached to hosts which performs all network calls to Azure Storage on behalf of VMs. 7 | 2. Disk are then availed via hypervisor to VM SCSI devices. 8 | 9 | Dysk are block devices running in your VMs are all network calls to Azure Storage are originated from your kernel. 10 | 11 | ## Dysk Components ## 12 | 13 | 1. Dysk LKM 14 | 1. Char Device: Because we don't have H/W involved, there are not IRQ to notify kernel when disks are pluggedi/unplugged. We relay on IOCTL performed against this char device. 15 | 2. Dysk bdd: Manages current list of mount dysks and integrates dysks with kernel block I/O interfaces. 16 | 3. Dysk Block Device: Created dynamically in resonse to ``` mount ``` IOCTL. 17 | 4. Worker: Performs asynchronous execution. 18 | 5. AZ: manages Azure page blob REST API calls. All calls are nonblocking. 19 | 2. Dysk Client 20 | 1. Go based client side package (executes IOCTL) that can be wrapped in any executable. 21 | 2. CLI that wraps the above package. 22 | 23 | > Due to the fact that Linux kernel does not support TLS all calls are executed against the HTTP endpoint its highly advisable that you use [Azure VNET service endpoints](https://docs.microsoft.com/en-us/azure/virtual-network/virtual-network-service-endpoints-overview). This will not expose your storage account (nor its traffic) outside your VNET. On-Prem VMs can VPN into this VNET to access the storage accounts. 24 | 25 | 26 | ## Handling Failed Disks ## 27 | 28 | Disks can fail for many reasons such as network(non transient failure), page blob deletion and breaking Azure Storage lease. Once any of these conditions is true, the following is executed: 29 | 30 | 1. The failed disk is marked as failed. 31 | 2. Any new requests will be canceled with [-EIO](http://www.virtsync.com/c-error-codes-include-errno) returned to userspace. 32 | 3. Any pending request will be canceled and -EIO is returned to userspace. 33 | 4. Disk is removed gracefuly. 34 | 35 | > at which point processes attempting to read/write from disks will handle the error using standard error handling. 36 | 37 | ## Handling Throttled Disks ## 38 | 39 | Once Azure Storage throttle a disk, dysk gracefully handles this event and pauses new I/O requests for 3 seconds before retrying the requests. 40 | 41 | ## Handling Cluster Split Brains Scenarios ## 42 | 43 | Dysk is designed to work in high density orchesterated compute envrionment. Specifically, containers orchesterted by Kubernetes. In this scenario pods declare thier storage requirements via specs (PV/PVC)[https://kubernetes.io/docs/concepts/storage/persistent-volumes/]. At any point of time a node or more carrying a large number of containers and disk might be in a network split. Where containers keep on running but nodes fail to report healthy state to master. Because disks are not *attached* perse a volume driver can break the existing lease and create new one then mount dysks on healthy nodes. Existing dysks will gracefull fail as described above. 44 | 45 | -------------------------------------------------------------------------------- /dyskctl/cmd/converter.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "fmt" 5 | "path" 6 | "strings" 7 | 8 | "github.com/khenidak/dysk/pkg/client" 9 | ) 10 | 11 | type SecretRef struct { 12 | Name string `json:"name"` 13 | Namespace *string `json:"namespace,omitempty"` 14 | } 15 | type FlexVol struct { 16 | Driver string `json:"driver"` 17 | FSType *string `json:"fsType"` 18 | ReadOnly bool `json:"readOnly"` 19 | SecretRef *SecretRef `json:"secretRef"` 20 | Options map[string]string `json:"options"` 21 | } 22 | type Metadata struct { 23 | Name string `json:"name"` 24 | Namespace *string `json:"namespace,omitempty"` 25 | Labels *map[string]string `json:"labels, omitempty"` 26 | } 27 | type Capacity struct { 28 | Storage string `json:"storage"` 29 | } 30 | type Spec struct { 31 | AccessModes []string `json:"accessModes"` 32 | Capacity *Capacity `json:"capacity"` 33 | PersistentVolumeReclaimPolicy *string `json:"persistentVolumeReclaimPolicy,omitempty"` 34 | StorageClassName *string `json:"storageClassName,omitempty"` 35 | FlexVolume *FlexVol `json:"flexVolume"` 36 | } 37 | type PersistentVolume struct { 38 | ApiVersion string `json:"apiVersion"` 39 | Kind string `json:"kind"` 40 | 41 | Metadata *Metadata `json:"metadata"` 42 | Spec *Spec `json:"spec"` 43 | } 44 | 45 | func dysk2Pv(namespace string, reclaimPolicy string, accessMode string, secretName string, 46 | secretNamespace string, fsType string, readOnly bool, storageClassName string, labels map[string]string, d *client.Dysk) *PersistentVolume { 47 | 48 | container := path.Dir(d.Path) 49 | container = container[1:] 50 | blob := path.Base(d.Path) 51 | 52 | var opts = map[string]string{ 53 | "accountName": d.AccountName, 54 | "container": container, 55 | "blob": blob, 56 | } 57 | 58 | secretRef := &SecretRef{ 59 | Name: secretName, 60 | } 61 | 62 | // Hack broken api for v1.10.+ 63 | if "" != secretNamespace { 64 | secretRef.Namespace = &secretNamespace 65 | } 66 | storageGiB := fmt.Sprintf("%dGi", d.SizeGB) 67 | pv := &PersistentVolume{ 68 | Metadata: &Metadata{ 69 | Name: strings.ToLower(d.Name), 70 | }, 71 | Spec: &Spec{ 72 | Capacity: &Capacity{ 73 | Storage: storageGiB, 74 | }, 75 | FlexVolume: &FlexVol{ 76 | Driver: "azure/dysk", 77 | ReadOnly: readOnly, 78 | Options: opts, 79 | SecretRef: secretRef, 80 | }, 81 | }, 82 | } 83 | 84 | if "" != storageClassName { 85 | pv.Spec.StorageClassName = &storageClassName 86 | } 87 | 88 | if "" != fsType { 89 | pv.Spec.FlexVolume.FSType = &fsType 90 | } 91 | 92 | if 0 < len(labels) { 93 | pv.Metadata.Labels = &labels 94 | } 95 | 96 | if "" != namespace { 97 | pv.Metadata.Namespace = &namespace 98 | } 99 | pv.Spec.AccessModes = []string{accessMode} 100 | pv.Kind = "PersistentVolume" 101 | pv.ApiVersion = "v1" 102 | return pv 103 | } 104 | -------------------------------------------------------------------------------- /dyskctl/vendor/github.com/spf13/cobra/args.go: -------------------------------------------------------------------------------- 1 | package cobra 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | type PositionalArgs func(cmd *Command, args []string) error 8 | 9 | // Legacy arg validation has the following behaviour: 10 | // - root commands with no subcommands can take arbitrary arguments 11 | // - root commands with subcommands will do subcommand validity checking 12 | // - subcommands will always accept arbitrary arguments 13 | func legacyArgs(cmd *Command, args []string) error { 14 | // no subcommand, always take args 15 | if !cmd.HasSubCommands() { 16 | return nil 17 | } 18 | 19 | // root command with subcommands, do subcommand checking 20 | if !cmd.HasParent() && len(args) > 0 { 21 | return fmt.Errorf("unknown command %q for %q%s", args[0], cmd.CommandPath(), cmd.findSuggestions(args[0])) 22 | } 23 | return nil 24 | } 25 | 26 | // NoArgs returns an error if any args are included 27 | func NoArgs(cmd *Command, args []string) error { 28 | if len(args) > 0 { 29 | return fmt.Errorf("unknown command %q for %q", args[0], cmd.CommandPath()) 30 | } 31 | return nil 32 | } 33 | 34 | // OnlyValidArgs returns an error if any args are not in the list of ValidArgs 35 | func OnlyValidArgs(cmd *Command, args []string) error { 36 | if len(cmd.ValidArgs) > 0 { 37 | for _, v := range args { 38 | if !stringInSlice(v, cmd.ValidArgs) { 39 | return fmt.Errorf("invalid argument %q for %q%s", v, cmd.CommandPath(), cmd.findSuggestions(args[0])) 40 | } 41 | } 42 | } 43 | return nil 44 | } 45 | 46 | func stringInSlice(a string, list []string) bool { 47 | for _, b := range list { 48 | if b == a { 49 | return true 50 | } 51 | } 52 | return false 53 | } 54 | 55 | // ArbitraryArgs never returns an error 56 | func ArbitraryArgs(cmd *Command, args []string) error { 57 | return nil 58 | } 59 | 60 | // MinimumNArgs returns an error if there is not at least N args 61 | func MinimumNArgs(n int) PositionalArgs { 62 | return func(cmd *Command, args []string) error { 63 | if len(args) < n { 64 | return fmt.Errorf("requires at least %d arg(s), only received %d", n, len(args)) 65 | } 66 | return nil 67 | } 68 | } 69 | 70 | // MaximumNArgs returns an error if there are more than N args 71 | func MaximumNArgs(n int) PositionalArgs { 72 | return func(cmd *Command, args []string) error { 73 | if len(args) > n { 74 | return fmt.Errorf("accepts at most %d arg(s), received %d", n, len(args)) 75 | } 76 | return nil 77 | } 78 | } 79 | 80 | // ExactArgs returns an error if there are not exactly n args 81 | func ExactArgs(n int) PositionalArgs { 82 | return func(cmd *Command, args []string) error { 83 | if len(args) != n { 84 | return fmt.Errorf("accepts %d arg(s), received %d", n, len(args)) 85 | } 86 | return nil 87 | } 88 | } 89 | 90 | // RangeArgs returns an error if the number of args is not within the expected range 91 | func RangeArgs(min int, max int) PositionalArgs { 92 | return func(cmd *Command, args []string) error { 93 | if len(args) < min || len(args) > max { 94 | return fmt.Errorf("accepts between %d and %d arg(s), received %d", min, max, len(args)) 95 | } 96 | return nil 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /dyskctl/vendor/github.com/spf13/pflag/int.go: -------------------------------------------------------------------------------- 1 | package pflag 2 | 3 | import "strconv" 4 | 5 | // -- int Value 6 | type intValue int 7 | 8 | func newIntValue(val int, p *int) *intValue { 9 | *p = val 10 | return (*intValue)(p) 11 | } 12 | 13 | func (i *intValue) Set(s string) error { 14 | v, err := strconv.ParseInt(s, 0, 64) 15 | *i = intValue(v) 16 | return err 17 | } 18 | 19 | func (i *intValue) Type() string { 20 | return "int" 21 | } 22 | 23 | func (i *intValue) String() string { return strconv.Itoa(int(*i)) } 24 | 25 | func intConv(sval string) (interface{}, error) { 26 | return strconv.Atoi(sval) 27 | } 28 | 29 | // GetInt return the int value of a flag with the given name 30 | func (f *FlagSet) GetInt(name string) (int, error) { 31 | val, err := f.getFlagType(name, "int", intConv) 32 | if err != nil { 33 | return 0, err 34 | } 35 | return val.(int), nil 36 | } 37 | 38 | // IntVar defines an int flag with specified name, default value, and usage string. 39 | // The argument p points to an int variable in which to store the value of the flag. 40 | func (f *FlagSet) IntVar(p *int, name string, value int, usage string) { 41 | f.VarP(newIntValue(value, p), name, "", usage) 42 | } 43 | 44 | // IntVarP is like IntVar, but accepts a shorthand letter that can be used after a single dash. 45 | func (f *FlagSet) IntVarP(p *int, name, shorthand string, value int, usage string) { 46 | f.VarP(newIntValue(value, p), name, shorthand, usage) 47 | } 48 | 49 | // IntVar defines an int flag with specified name, default value, and usage string. 50 | // The argument p points to an int variable in which to store the value of the flag. 51 | func IntVar(p *int, name string, value int, usage string) { 52 | CommandLine.VarP(newIntValue(value, p), name, "", usage) 53 | } 54 | 55 | // IntVarP is like IntVar, but accepts a shorthand letter that can be used after a single dash. 56 | func IntVarP(p *int, name, shorthand string, value int, usage string) { 57 | CommandLine.VarP(newIntValue(value, p), name, shorthand, usage) 58 | } 59 | 60 | // Int defines an int flag with specified name, default value, and usage string. 61 | // The return value is the address of an int variable that stores the value of the flag. 62 | func (f *FlagSet) Int(name string, value int, usage string) *int { 63 | p := new(int) 64 | f.IntVarP(p, name, "", value, usage) 65 | return p 66 | } 67 | 68 | // IntP is like Int, but accepts a shorthand letter that can be used after a single dash. 69 | func (f *FlagSet) IntP(name, shorthand string, value int, usage string) *int { 70 | p := new(int) 71 | f.IntVarP(p, name, shorthand, value, usage) 72 | return p 73 | } 74 | 75 | // Int defines an int flag with specified name, default value, and usage string. 76 | // The return value is the address of an int variable that stores the value of the flag. 77 | func Int(name string, value int, usage string) *int { 78 | return CommandLine.IntP(name, "", value, usage) 79 | } 80 | 81 | // IntP is like Int, but accepts a shorthand letter that can be used after a single dash. 82 | func IntP(name, shorthand string, value int, usage string) *int { 83 | return CommandLine.IntP(name, shorthand, value, usage) 84 | } 85 | -------------------------------------------------------------------------------- /dyskctl/vendor/github.com/spf13/cobra/cobra/cmd/license_mit.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2015 Steve Francia . 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // http://www.apache.org/licenses/LICENSE-2.0 7 | // 8 | // Unless required by applicable law or agreed to in writing, software 9 | // distributed under the License is distributed on an "AS IS" BASIS, 10 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | // Parts inspired by https://github.com/ryanuber/go-license 15 | 16 | package cmd 17 | 18 | func initMit() { 19 | Licenses["mit"] = License{ 20 | Name: "MIT License", 21 | PossibleMatches: []string{"mit"}, 22 | Header: ` 23 | Permission is hereby granted, free of charge, to any person obtaining a copy 24 | of this software and associated documentation files (the "Software"), to deal 25 | in the Software without restriction, including without limitation the rights 26 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 27 | copies of the Software, and to permit persons to whom the Software is 28 | furnished to do so, subject to the following conditions: 29 | 30 | The above copyright notice and this permission notice shall be included in 31 | all copies or substantial portions of the Software. 32 | 33 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 34 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 35 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 36 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 37 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 38 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 39 | THE SOFTWARE.`, 40 | Text: `The MIT License (MIT) 41 | 42 | {{ .copyright }} 43 | 44 | Permission is hereby granted, free of charge, to any person obtaining a copy 45 | of this software and associated documentation files (the "Software"), to deal 46 | in the Software without restriction, including without limitation the rights 47 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 48 | copies of the Software, and to permit persons to whom the Software is 49 | furnished to do so, subject to the following conditions: 50 | 51 | The above copyright notice and this permission notice shall be included in 52 | all copies or substantial portions of the Software. 53 | 54 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 55 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 56 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 57 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 58 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 59 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 60 | THE SOFTWARE. 61 | `, 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /kubernetes/flexvolume/deployment/dysk-flexvol-installer.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Namespace 3 | metadata: 4 | name: dysk 5 | --- 6 | apiVersion: extensions/v1beta1 7 | kind: DaemonSet 8 | metadata: 9 | labels: 10 | dyskComponent: kernel-flexvol-installer 11 | name: dysk-flexvol-installer 12 | namespace: dysk 13 | spec: 14 | template: 15 | metadata: 16 | labels: 17 | dyskComponent: dysk-kubernetes-installer 18 | spec: 19 | tolerations: 20 | - key: node-role.kubernetes.io/master 21 | operator: Equal 22 | value: "true" 23 | effect: NoSchedule 24 | containers: 25 | #this image installs the flex vol driver and its deps 26 | # mount your flex vols directory to this container 27 | # and set TARGET_DIR env var. 28 | # * for acs-engine 0.12 and later the directory is /etc/kubernetes/volumeplugins 29 | # * for acs-engine <0.12 you will need to set vol directory follow https://github.com/khenidak/dysk/tree/master/kubernetes for details 30 | # * if you have used flex before on your cluster, use same directory 31 | # set TARGET_DIR env var and mount the same directory to to the container 32 | - name: flexvol-driver-installer 33 | image: "khenidak/dysk-flexvol-installer:0.6" 34 | env: 35 | #forces the container not to exit 36 | # to solve for this https://github.com/kubernetes/kubernetes/issues/17182 37 | # until it is fixed 38 | - name: TARGET_DIR 39 | value: "/etc/kubernetes/volumeplugins" 40 | volumeMounts: 41 | - mountPath: "/etc/kubernetes/volumeplugins" 42 | name: volplugins 43 | # this image installs kernel module according to 44 | # to the kernel loaded on host. currently it downloads 45 | # the entire github repo, as we move to beta code will 46 | # be part of the image 47 | - name: kernel-module-installer 48 | image: "khenidak/dysk-installer:0.6" 49 | env: 50 | #forces the container not to exit 51 | # to solve for this https://github.com/kubernetes/kubernetes/issues/17182 52 | # until it is fixed 53 | - name: INSTALL_MODE 54 | value: "kubernetes" 55 | #use this to control which version of dysk module 56 | # do you want to install 57 | - name: DYSK_TAG 58 | value: f02fbe61750fc050d759366b9647e7ea6c159e16 59 | resources: 60 | requests: 61 | cpu: 100m 62 | securityContext: 63 | privileged: true 64 | volumeMounts: 65 | - mountPath: "/usr/src" 66 | name: src 67 | - mountPath: "/lib/modules" 68 | name: modules 69 | readOnly: true 70 | # Todo: flex vol installer container 71 | volumes: 72 | - hostPath: 73 | path: "/usr/src" 74 | name: src 75 | - hostPath: 76 | path: "/lib/modules" 77 | name: modules 78 | - hostPath: 79 | path: "/etc/kubernetes/volumeplugins" #Modify this directory if your nodes are using a different one 80 | name: volplugins 81 | nodeSelector: 82 | beta.kubernetes.io/os: linux 83 | -------------------------------------------------------------------------------- /dyskctl/vendor/github.com/spf13/pflag/golangflag.go: -------------------------------------------------------------------------------- 1 | // Copyright 2009 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package pflag 6 | 7 | import ( 8 | goflag "flag" 9 | "reflect" 10 | "strings" 11 | ) 12 | 13 | // flagValueWrapper implements pflag.Value around a flag.Value. The main 14 | // difference here is the addition of the Type method that returns a string 15 | // name of the type. As this is generally unknown, we approximate that with 16 | // reflection. 17 | type flagValueWrapper struct { 18 | inner goflag.Value 19 | flagType string 20 | } 21 | 22 | // We are just copying the boolFlag interface out of goflag as that is what 23 | // they use to decide if a flag should get "true" when no arg is given. 24 | type goBoolFlag interface { 25 | goflag.Value 26 | IsBoolFlag() bool 27 | } 28 | 29 | func wrapFlagValue(v goflag.Value) Value { 30 | // If the flag.Value happens to also be a pflag.Value, just use it directly. 31 | if pv, ok := v.(Value); ok { 32 | return pv 33 | } 34 | 35 | pv := &flagValueWrapper{ 36 | inner: v, 37 | } 38 | 39 | t := reflect.TypeOf(v) 40 | if t.Kind() == reflect.Interface || t.Kind() == reflect.Ptr { 41 | t = t.Elem() 42 | } 43 | 44 | pv.flagType = strings.TrimSuffix(t.Name(), "Value") 45 | return pv 46 | } 47 | 48 | func (v *flagValueWrapper) String() string { 49 | return v.inner.String() 50 | } 51 | 52 | func (v *flagValueWrapper) Set(s string) error { 53 | return v.inner.Set(s) 54 | } 55 | 56 | func (v *flagValueWrapper) Type() string { 57 | return v.flagType 58 | } 59 | 60 | // PFlagFromGoFlag will return a *pflag.Flag given a *flag.Flag 61 | // If the *flag.Flag.Name was a single character (ex: `v`) it will be accessiblei 62 | // with both `-v` and `--v` in flags. If the golang flag was more than a single 63 | // character (ex: `verbose`) it will only be accessible via `--verbose` 64 | func PFlagFromGoFlag(goflag *goflag.Flag) *Flag { 65 | // Remember the default value as a string; it won't change. 66 | flag := &Flag{ 67 | Name: goflag.Name, 68 | Usage: goflag.Usage, 69 | Value: wrapFlagValue(goflag.Value), 70 | // Looks like golang flags don't set DefValue correctly :-( 71 | //DefValue: goflag.DefValue, 72 | DefValue: goflag.Value.String(), 73 | } 74 | // Ex: if the golang flag was -v, allow both -v and --v to work 75 | if len(flag.Name) == 1 { 76 | flag.Shorthand = flag.Name 77 | } 78 | if fv, ok := goflag.Value.(goBoolFlag); ok && fv.IsBoolFlag() { 79 | flag.NoOptDefVal = "true" 80 | } 81 | return flag 82 | } 83 | 84 | // AddGoFlag will add the given *flag.Flag to the pflag.FlagSet 85 | func (f *FlagSet) AddGoFlag(goflag *goflag.Flag) { 86 | if f.Lookup(goflag.Name) != nil { 87 | return 88 | } 89 | newflag := PFlagFromGoFlag(goflag) 90 | f.AddFlag(newflag) 91 | } 92 | 93 | // AddGoFlagSet will add the given *flag.FlagSet to the pflag.FlagSet 94 | func (f *FlagSet) AddGoFlagSet(newSet *goflag.FlagSet) { 95 | if newSet == nil { 96 | return 97 | } 98 | newSet.VisitAll(func(goflag *goflag.Flag) { 99 | f.AddGoFlag(goflag) 100 | }) 101 | } 102 | -------------------------------------------------------------------------------- /dyskctl/vendor/github.com/spf13/afero/httpFs.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2014 Steve Francia . 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // http://www.apache.org/licenses/LICENSE-2.0 7 | // 8 | // Unless required by applicable law or agreed to in writing, software 9 | // distributed under the License is distributed on an "AS IS" BASIS, 10 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package afero 15 | 16 | import ( 17 | "errors" 18 | "net/http" 19 | "os" 20 | "path" 21 | "path/filepath" 22 | "strings" 23 | "time" 24 | ) 25 | 26 | type httpDir struct { 27 | basePath string 28 | fs HttpFs 29 | } 30 | 31 | func (d httpDir) Open(name string) (http.File, error) { 32 | if filepath.Separator != '/' && strings.IndexRune(name, filepath.Separator) >= 0 || 33 | strings.Contains(name, "\x00") { 34 | return nil, errors.New("http: invalid character in file path") 35 | } 36 | dir := string(d.basePath) 37 | if dir == "" { 38 | dir = "." 39 | } 40 | 41 | f, err := d.fs.Open(filepath.Join(dir, filepath.FromSlash(path.Clean("/"+name)))) 42 | if err != nil { 43 | return nil, err 44 | } 45 | return f, nil 46 | } 47 | 48 | type HttpFs struct { 49 | source Fs 50 | } 51 | 52 | func NewHttpFs(source Fs) *HttpFs { 53 | return &HttpFs{source: source} 54 | } 55 | 56 | func (h HttpFs) Dir(s string) *httpDir { 57 | return &httpDir{basePath: s, fs: h} 58 | } 59 | 60 | func (h HttpFs) Name() string { return "h HttpFs" } 61 | 62 | func (h HttpFs) Create(name string) (File, error) { 63 | return h.source.Create(name) 64 | } 65 | 66 | func (h HttpFs) Chmod(name string, mode os.FileMode) error { 67 | return h.source.Chmod(name, mode) 68 | } 69 | 70 | func (h HttpFs) Chtimes(name string, atime time.Time, mtime time.Time) error { 71 | return h.source.Chtimes(name, atime, mtime) 72 | } 73 | 74 | func (h HttpFs) Mkdir(name string, perm os.FileMode) error { 75 | return h.source.Mkdir(name, perm) 76 | } 77 | 78 | func (h HttpFs) MkdirAll(path string, perm os.FileMode) error { 79 | return h.source.MkdirAll(path, perm) 80 | } 81 | 82 | func (h HttpFs) Open(name string) (http.File, error) { 83 | f, err := h.source.Open(name) 84 | if err == nil { 85 | if httpfile, ok := f.(http.File); ok { 86 | return httpfile, nil 87 | } 88 | } 89 | return nil, err 90 | } 91 | 92 | func (h HttpFs) OpenFile(name string, flag int, perm os.FileMode) (File, error) { 93 | return h.source.OpenFile(name, flag, perm) 94 | } 95 | 96 | func (h HttpFs) Remove(name string) error { 97 | return h.source.Remove(name) 98 | } 99 | 100 | func (h HttpFs) RemoveAll(path string) error { 101 | return h.source.RemoveAll(path) 102 | } 103 | 104 | func (h HttpFs) Rename(oldname, newname string) error { 105 | return h.source.Rename(oldname, newname) 106 | } 107 | 108 | func (h HttpFs) Stat(name string) (os.FileInfo, error) { 109 | return h.source.Stat(name) 110 | } 111 | -------------------------------------------------------------------------------- /dyskctl/vendor/github.com/spf13/pflag/string.go: -------------------------------------------------------------------------------- 1 | package pflag 2 | 3 | // -- string Value 4 | type stringValue string 5 | 6 | func newStringValue(val string, p *string) *stringValue { 7 | *p = val 8 | return (*stringValue)(p) 9 | } 10 | 11 | func (s *stringValue) Set(val string) error { 12 | *s = stringValue(val) 13 | return nil 14 | } 15 | func (s *stringValue) Type() string { 16 | return "string" 17 | } 18 | 19 | func (s *stringValue) String() string { return string(*s) } 20 | 21 | func stringConv(sval string) (interface{}, error) { 22 | return sval, nil 23 | } 24 | 25 | // GetString return the string value of a flag with the given name 26 | func (f *FlagSet) GetString(name string) (string, error) { 27 | val, err := f.getFlagType(name, "string", stringConv) 28 | if err != nil { 29 | return "", err 30 | } 31 | return val.(string), nil 32 | } 33 | 34 | // StringVar defines a string flag with specified name, default value, and usage string. 35 | // The argument p points to a string variable in which to store the value of the flag. 36 | func (f *FlagSet) StringVar(p *string, name string, value string, usage string) { 37 | f.VarP(newStringValue(value, p), name, "", usage) 38 | } 39 | 40 | // StringVarP is like StringVar, but accepts a shorthand letter that can be used after a single dash. 41 | func (f *FlagSet) StringVarP(p *string, name, shorthand string, value string, usage string) { 42 | f.VarP(newStringValue(value, p), name, shorthand, usage) 43 | } 44 | 45 | // StringVar defines a string flag with specified name, default value, and usage string. 46 | // The argument p points to a string variable in which to store the value of the flag. 47 | func StringVar(p *string, name string, value string, usage string) { 48 | CommandLine.VarP(newStringValue(value, p), name, "", usage) 49 | } 50 | 51 | // StringVarP is like StringVar, but accepts a shorthand letter that can be used after a single dash. 52 | func StringVarP(p *string, name, shorthand string, value string, usage string) { 53 | CommandLine.VarP(newStringValue(value, p), name, shorthand, usage) 54 | } 55 | 56 | // String defines a string flag with specified name, default value, and usage string. 57 | // The return value is the address of a string variable that stores the value of the flag. 58 | func (f *FlagSet) String(name string, value string, usage string) *string { 59 | p := new(string) 60 | f.StringVarP(p, name, "", value, usage) 61 | return p 62 | } 63 | 64 | // StringP is like String, but accepts a shorthand letter that can be used after a single dash. 65 | func (f *FlagSet) StringP(name, shorthand string, value string, usage string) *string { 66 | p := new(string) 67 | f.StringVarP(p, name, shorthand, value, usage) 68 | return p 69 | } 70 | 71 | // String defines a string flag with specified name, default value, and usage string. 72 | // The return value is the address of a string variable that stores the value of the flag. 73 | func String(name string, value string, usage string) *string { 74 | return CommandLine.StringP(name, "", value, usage) 75 | } 76 | 77 | // StringP is like String, but accepts a shorthand letter that can be used after a single dash. 78 | func StringP(name, shorthand string, value string, usage string) *string { 79 | return CommandLine.StringP(name, shorthand, value, usage) 80 | } 81 | -------------------------------------------------------------------------------- /dyskctl/vendor/github.com/hashicorp/hcl/json/token/token.go: -------------------------------------------------------------------------------- 1 | package token 2 | 3 | import ( 4 | "fmt" 5 | "strconv" 6 | 7 | hcltoken "github.com/hashicorp/hcl/hcl/token" 8 | ) 9 | 10 | // Token defines a single HCL token which can be obtained via the Scanner 11 | type Token struct { 12 | Type Type 13 | Pos Pos 14 | Text string 15 | } 16 | 17 | // Type is the set of lexical tokens of the HCL (HashiCorp Configuration Language) 18 | type Type int 19 | 20 | const ( 21 | // Special tokens 22 | ILLEGAL Type = iota 23 | EOF 24 | 25 | identifier_beg 26 | literal_beg 27 | NUMBER // 12345 28 | FLOAT // 123.45 29 | BOOL // true,false 30 | STRING // "abc" 31 | NULL // null 32 | literal_end 33 | identifier_end 34 | 35 | operator_beg 36 | LBRACK // [ 37 | LBRACE // { 38 | COMMA // , 39 | PERIOD // . 40 | COLON // : 41 | 42 | RBRACK // ] 43 | RBRACE // } 44 | 45 | operator_end 46 | ) 47 | 48 | var tokens = [...]string{ 49 | ILLEGAL: "ILLEGAL", 50 | 51 | EOF: "EOF", 52 | 53 | NUMBER: "NUMBER", 54 | FLOAT: "FLOAT", 55 | BOOL: "BOOL", 56 | STRING: "STRING", 57 | NULL: "NULL", 58 | 59 | LBRACK: "LBRACK", 60 | LBRACE: "LBRACE", 61 | COMMA: "COMMA", 62 | PERIOD: "PERIOD", 63 | COLON: "COLON", 64 | 65 | RBRACK: "RBRACK", 66 | RBRACE: "RBRACE", 67 | } 68 | 69 | // String returns the string corresponding to the token tok. 70 | func (t Type) String() string { 71 | s := "" 72 | if 0 <= t && t < Type(len(tokens)) { 73 | s = tokens[t] 74 | } 75 | if s == "" { 76 | s = "token(" + strconv.Itoa(int(t)) + ")" 77 | } 78 | return s 79 | } 80 | 81 | // IsIdentifier returns true for tokens corresponding to identifiers and basic 82 | // type literals; it returns false otherwise. 83 | func (t Type) IsIdentifier() bool { return identifier_beg < t && t < identifier_end } 84 | 85 | // IsLiteral returns true for tokens corresponding to basic type literals; it 86 | // returns false otherwise. 87 | func (t Type) IsLiteral() bool { return literal_beg < t && t < literal_end } 88 | 89 | // IsOperator returns true for tokens corresponding to operators and 90 | // delimiters; it returns false otherwise. 91 | func (t Type) IsOperator() bool { return operator_beg < t && t < operator_end } 92 | 93 | // String returns the token's literal text. Note that this is only 94 | // applicable for certain token types, such as token.IDENT, 95 | // token.STRING, etc.. 96 | func (t Token) String() string { 97 | return fmt.Sprintf("%s %s %s", t.Pos.String(), t.Type.String(), t.Text) 98 | } 99 | 100 | // HCLToken converts this token to an HCL token. 101 | // 102 | // The token type must be a literal type or this will panic. 103 | func (t Token) HCLToken() hcltoken.Token { 104 | switch t.Type { 105 | case BOOL: 106 | return hcltoken.Token{Type: hcltoken.BOOL, Text: t.Text} 107 | case FLOAT: 108 | return hcltoken.Token{Type: hcltoken.FLOAT, Text: t.Text} 109 | case NULL: 110 | return hcltoken.Token{Type: hcltoken.STRING, Text: ""} 111 | case NUMBER: 112 | return hcltoken.Token{Type: hcltoken.NUMBER, Text: t.Text} 113 | case STRING: 114 | return hcltoken.Token{Type: hcltoken.STRING, Text: t.Text, JSON: true} 115 | default: 116 | panic(fmt.Sprintf("unimplemented HCLToken for type: %s", t.Type)) 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /dyskctl/vendor/github.com/spf13/pflag/int64.go: -------------------------------------------------------------------------------- 1 | package pflag 2 | 3 | import "strconv" 4 | 5 | // -- int64 Value 6 | type int64Value int64 7 | 8 | func newInt64Value(val int64, p *int64) *int64Value { 9 | *p = val 10 | return (*int64Value)(p) 11 | } 12 | 13 | func (i *int64Value) Set(s string) error { 14 | v, err := strconv.ParseInt(s, 0, 64) 15 | *i = int64Value(v) 16 | return err 17 | } 18 | 19 | func (i *int64Value) Type() string { 20 | return "int64" 21 | } 22 | 23 | func (i *int64Value) String() string { return strconv.FormatInt(int64(*i), 10) } 24 | 25 | func int64Conv(sval string) (interface{}, error) { 26 | return strconv.ParseInt(sval, 0, 64) 27 | } 28 | 29 | // GetInt64 return the int64 value of a flag with the given name 30 | func (f *FlagSet) GetInt64(name string) (int64, error) { 31 | val, err := f.getFlagType(name, "int64", int64Conv) 32 | if err != nil { 33 | return 0, err 34 | } 35 | return val.(int64), nil 36 | } 37 | 38 | // Int64Var defines an int64 flag with specified name, default value, and usage string. 39 | // The argument p points to an int64 variable in which to store the value of the flag. 40 | func (f *FlagSet) Int64Var(p *int64, name string, value int64, usage string) { 41 | f.VarP(newInt64Value(value, p), name, "", usage) 42 | } 43 | 44 | // Int64VarP is like Int64Var, but accepts a shorthand letter that can be used after a single dash. 45 | func (f *FlagSet) Int64VarP(p *int64, name, shorthand string, value int64, usage string) { 46 | f.VarP(newInt64Value(value, p), name, shorthand, usage) 47 | } 48 | 49 | // Int64Var defines an int64 flag with specified name, default value, and usage string. 50 | // The argument p points to an int64 variable in which to store the value of the flag. 51 | func Int64Var(p *int64, name string, value int64, usage string) { 52 | CommandLine.VarP(newInt64Value(value, p), name, "", usage) 53 | } 54 | 55 | // Int64VarP is like Int64Var, but accepts a shorthand letter that can be used after a single dash. 56 | func Int64VarP(p *int64, name, shorthand string, value int64, usage string) { 57 | CommandLine.VarP(newInt64Value(value, p), name, shorthand, usage) 58 | } 59 | 60 | // Int64 defines an int64 flag with specified name, default value, and usage string. 61 | // The return value is the address of an int64 variable that stores the value of the flag. 62 | func (f *FlagSet) Int64(name string, value int64, usage string) *int64 { 63 | p := new(int64) 64 | f.Int64VarP(p, name, "", value, usage) 65 | return p 66 | } 67 | 68 | // Int64P is like Int64, but accepts a shorthand letter that can be used after a single dash. 69 | func (f *FlagSet) Int64P(name, shorthand string, value int64, usage string) *int64 { 70 | p := new(int64) 71 | f.Int64VarP(p, name, shorthand, value, usage) 72 | return p 73 | } 74 | 75 | // Int64 defines an int64 flag with specified name, default value, and usage string. 76 | // The return value is the address of an int64 variable that stores the value of the flag. 77 | func Int64(name string, value int64, usage string) *int64 { 78 | return CommandLine.Int64P(name, "", value, usage) 79 | } 80 | 81 | // Int64P is like Int64, but accepts a shorthand letter that can be used after a single dash. 82 | func Int64P(name, shorthand string, value int64, usage string) *int64 { 83 | return CommandLine.Int64P(name, shorthand, value, usage) 84 | } 85 | -------------------------------------------------------------------------------- /dyskctl/vendor/github.com/spf13/pflag/int8.go: -------------------------------------------------------------------------------- 1 | package pflag 2 | 3 | import "strconv" 4 | 5 | // -- int8 Value 6 | type int8Value int8 7 | 8 | func newInt8Value(val int8, p *int8) *int8Value { 9 | *p = val 10 | return (*int8Value)(p) 11 | } 12 | 13 | func (i *int8Value) Set(s string) error { 14 | v, err := strconv.ParseInt(s, 0, 8) 15 | *i = int8Value(v) 16 | return err 17 | } 18 | 19 | func (i *int8Value) Type() string { 20 | return "int8" 21 | } 22 | 23 | func (i *int8Value) String() string { return strconv.FormatInt(int64(*i), 10) } 24 | 25 | func int8Conv(sval string) (interface{}, error) { 26 | v, err := strconv.ParseInt(sval, 0, 8) 27 | if err != nil { 28 | return 0, err 29 | } 30 | return int8(v), nil 31 | } 32 | 33 | // GetInt8 return the int8 value of a flag with the given name 34 | func (f *FlagSet) GetInt8(name string) (int8, error) { 35 | val, err := f.getFlagType(name, "int8", int8Conv) 36 | if err != nil { 37 | return 0, err 38 | } 39 | return val.(int8), nil 40 | } 41 | 42 | // Int8Var defines an int8 flag with specified name, default value, and usage string. 43 | // The argument p points to an int8 variable in which to store the value of the flag. 44 | func (f *FlagSet) Int8Var(p *int8, name string, value int8, usage string) { 45 | f.VarP(newInt8Value(value, p), name, "", usage) 46 | } 47 | 48 | // Int8VarP is like Int8Var, but accepts a shorthand letter that can be used after a single dash. 49 | func (f *FlagSet) Int8VarP(p *int8, name, shorthand string, value int8, usage string) { 50 | f.VarP(newInt8Value(value, p), name, shorthand, usage) 51 | } 52 | 53 | // Int8Var defines an int8 flag with specified name, default value, and usage string. 54 | // The argument p points to an int8 variable in which to store the value of the flag. 55 | func Int8Var(p *int8, name string, value int8, usage string) { 56 | CommandLine.VarP(newInt8Value(value, p), name, "", usage) 57 | } 58 | 59 | // Int8VarP is like Int8Var, but accepts a shorthand letter that can be used after a single dash. 60 | func Int8VarP(p *int8, name, shorthand string, value int8, usage string) { 61 | CommandLine.VarP(newInt8Value(value, p), name, shorthand, usage) 62 | } 63 | 64 | // Int8 defines an int8 flag with specified name, default value, and usage string. 65 | // The return value is the address of an int8 variable that stores the value of the flag. 66 | func (f *FlagSet) Int8(name string, value int8, usage string) *int8 { 67 | p := new(int8) 68 | f.Int8VarP(p, name, "", value, usage) 69 | return p 70 | } 71 | 72 | // Int8P is like Int8, but accepts a shorthand letter that can be used after a single dash. 73 | func (f *FlagSet) Int8P(name, shorthand string, value int8, usage string) *int8 { 74 | p := new(int8) 75 | f.Int8VarP(p, name, shorthand, value, usage) 76 | return p 77 | } 78 | 79 | // Int8 defines an int8 flag with specified name, default value, and usage string. 80 | // The return value is the address of an int8 variable that stores the value of the flag. 81 | func Int8(name string, value int8, usage string) *int8 { 82 | return CommandLine.Int8P(name, "", value, usage) 83 | } 84 | 85 | // Int8P is like Int8, but accepts a shorthand letter that can be used after a single dash. 86 | func Int8P(name, shorthand string, value int8, usage string) *int8 { 87 | return CommandLine.Int8P(name, shorthand, value, usage) 88 | } 89 | -------------------------------------------------------------------------------- /dyskctl/vendor/github.com/spf13/pflag/uint.go: -------------------------------------------------------------------------------- 1 | package pflag 2 | 3 | import "strconv" 4 | 5 | // -- uint Value 6 | type uintValue uint 7 | 8 | func newUintValue(val uint, p *uint) *uintValue { 9 | *p = val 10 | return (*uintValue)(p) 11 | } 12 | 13 | func (i *uintValue) Set(s string) error { 14 | v, err := strconv.ParseUint(s, 0, 64) 15 | *i = uintValue(v) 16 | return err 17 | } 18 | 19 | func (i *uintValue) Type() string { 20 | return "uint" 21 | } 22 | 23 | func (i *uintValue) String() string { return strconv.FormatUint(uint64(*i), 10) } 24 | 25 | func uintConv(sval string) (interface{}, error) { 26 | v, err := strconv.ParseUint(sval, 0, 0) 27 | if err != nil { 28 | return 0, err 29 | } 30 | return uint(v), nil 31 | } 32 | 33 | // GetUint return the uint value of a flag with the given name 34 | func (f *FlagSet) GetUint(name string) (uint, error) { 35 | val, err := f.getFlagType(name, "uint", uintConv) 36 | if err != nil { 37 | return 0, err 38 | } 39 | return val.(uint), nil 40 | } 41 | 42 | // UintVar defines a uint flag with specified name, default value, and usage string. 43 | // The argument p points to a uint variable in which to store the value of the flag. 44 | func (f *FlagSet) UintVar(p *uint, name string, value uint, usage string) { 45 | f.VarP(newUintValue(value, p), name, "", usage) 46 | } 47 | 48 | // UintVarP is like UintVar, but accepts a shorthand letter that can be used after a single dash. 49 | func (f *FlagSet) UintVarP(p *uint, name, shorthand string, value uint, usage string) { 50 | f.VarP(newUintValue(value, p), name, shorthand, usage) 51 | } 52 | 53 | // UintVar defines a uint flag with specified name, default value, and usage string. 54 | // The argument p points to a uint variable in which to store the value of the flag. 55 | func UintVar(p *uint, name string, value uint, usage string) { 56 | CommandLine.VarP(newUintValue(value, p), name, "", usage) 57 | } 58 | 59 | // UintVarP is like UintVar, but accepts a shorthand letter that can be used after a single dash. 60 | func UintVarP(p *uint, name, shorthand string, value uint, usage string) { 61 | CommandLine.VarP(newUintValue(value, p), name, shorthand, usage) 62 | } 63 | 64 | // Uint defines a uint flag with specified name, default value, and usage string. 65 | // The return value is the address of a uint variable that stores the value of the flag. 66 | func (f *FlagSet) Uint(name string, value uint, usage string) *uint { 67 | p := new(uint) 68 | f.UintVarP(p, name, "", value, usage) 69 | return p 70 | } 71 | 72 | // UintP is like Uint, but accepts a shorthand letter that can be used after a single dash. 73 | func (f *FlagSet) UintP(name, shorthand string, value uint, usage string) *uint { 74 | p := new(uint) 75 | f.UintVarP(p, name, shorthand, value, usage) 76 | return p 77 | } 78 | 79 | // Uint defines a uint flag with specified name, default value, and usage string. 80 | // The return value is the address of a uint variable that stores the value of the flag. 81 | func Uint(name string, value uint, usage string) *uint { 82 | return CommandLine.UintP(name, "", value, usage) 83 | } 84 | 85 | // UintP is like Uint, but accepts a shorthand letter that can be used after a single dash. 86 | func UintP(name, shorthand string, value uint, usage string) *uint { 87 | return CommandLine.UintP(name, shorthand, value, usage) 88 | } 89 | -------------------------------------------------------------------------------- /dyskctl/vendor/github.com/spf13/pflag/count.go: -------------------------------------------------------------------------------- 1 | package pflag 2 | 3 | import "strconv" 4 | 5 | // -- count Value 6 | type countValue int 7 | 8 | func newCountValue(val int, p *int) *countValue { 9 | *p = val 10 | return (*countValue)(p) 11 | } 12 | 13 | func (i *countValue) Set(s string) error { 14 | v, err := strconv.ParseInt(s, 0, 64) 15 | // -1 means that no specific value was passed, so increment 16 | if v == -1 { 17 | *i = countValue(*i + 1) 18 | } else { 19 | *i = countValue(v) 20 | } 21 | return err 22 | } 23 | 24 | func (i *countValue) Type() string { 25 | return "count" 26 | } 27 | 28 | func (i *countValue) String() string { return strconv.Itoa(int(*i)) } 29 | 30 | func countConv(sval string) (interface{}, error) { 31 | i, err := strconv.Atoi(sval) 32 | if err != nil { 33 | return nil, err 34 | } 35 | return i, nil 36 | } 37 | 38 | // GetCount return the int value of a flag with the given name 39 | func (f *FlagSet) GetCount(name string) (int, error) { 40 | val, err := f.getFlagType(name, "count", countConv) 41 | if err != nil { 42 | return 0, err 43 | } 44 | return val.(int), nil 45 | } 46 | 47 | // CountVar defines a count flag with specified name, default value, and usage string. 48 | // The argument p points to an int variable in which to store the value of the flag. 49 | // A count flag will add 1 to its value evey time it is found on the command line 50 | func (f *FlagSet) CountVar(p *int, name string, usage string) { 51 | f.CountVarP(p, name, "", usage) 52 | } 53 | 54 | // CountVarP is like CountVar only take a shorthand for the flag name. 55 | func (f *FlagSet) CountVarP(p *int, name, shorthand string, usage string) { 56 | flag := f.VarPF(newCountValue(0, p), name, shorthand, usage) 57 | flag.NoOptDefVal = "-1" 58 | } 59 | 60 | // CountVar like CountVar only the flag is placed on the CommandLine instead of a given flag set 61 | func CountVar(p *int, name string, usage string) { 62 | CommandLine.CountVar(p, name, usage) 63 | } 64 | 65 | // CountVarP is like CountVar only take a shorthand for the flag name. 66 | func CountVarP(p *int, name, shorthand string, usage string) { 67 | CommandLine.CountVarP(p, name, shorthand, usage) 68 | } 69 | 70 | // Count defines a count flag with specified name, default value, and usage string. 71 | // The return value is the address of an int variable that stores the value of the flag. 72 | // A count flag will add 1 to its value evey time it is found on the command line 73 | func (f *FlagSet) Count(name string, usage string) *int { 74 | p := new(int) 75 | f.CountVarP(p, name, "", usage) 76 | return p 77 | } 78 | 79 | // CountP is like Count only takes a shorthand for the flag name. 80 | func (f *FlagSet) CountP(name, shorthand string, usage string) *int { 81 | p := new(int) 82 | f.CountVarP(p, name, shorthand, usage) 83 | return p 84 | } 85 | 86 | // Count defines a count flag with specified name, default value, and usage string. 87 | // The return value is the address of an int variable that stores the value of the flag. 88 | // A count flag will add 1 to its value evey time it is found on the command line 89 | func Count(name string, usage string) *int { 90 | return CommandLine.CountP(name, "", usage) 91 | } 92 | 93 | // CountP is like Count only takes a shorthand for the flag name. 94 | func CountP(name, shorthand string, usage string) *int { 95 | return CommandLine.CountP(name, shorthand, usage) 96 | } 97 | -------------------------------------------------------------------------------- /dyskctl/vendor/github.com/spf13/pflag/uint8.go: -------------------------------------------------------------------------------- 1 | package pflag 2 | 3 | import "strconv" 4 | 5 | // -- uint8 Value 6 | type uint8Value uint8 7 | 8 | func newUint8Value(val uint8, p *uint8) *uint8Value { 9 | *p = val 10 | return (*uint8Value)(p) 11 | } 12 | 13 | func (i *uint8Value) Set(s string) error { 14 | v, err := strconv.ParseUint(s, 0, 8) 15 | *i = uint8Value(v) 16 | return err 17 | } 18 | 19 | func (i *uint8Value) Type() string { 20 | return "uint8" 21 | } 22 | 23 | func (i *uint8Value) String() string { return strconv.FormatUint(uint64(*i), 10) } 24 | 25 | func uint8Conv(sval string) (interface{}, error) { 26 | v, err := strconv.ParseUint(sval, 0, 8) 27 | if err != nil { 28 | return 0, err 29 | } 30 | return uint8(v), nil 31 | } 32 | 33 | // GetUint8 return the uint8 value of a flag with the given name 34 | func (f *FlagSet) GetUint8(name string) (uint8, error) { 35 | val, err := f.getFlagType(name, "uint8", uint8Conv) 36 | if err != nil { 37 | return 0, err 38 | } 39 | return val.(uint8), nil 40 | } 41 | 42 | // Uint8Var defines a uint8 flag with specified name, default value, and usage string. 43 | // The argument p points to a uint8 variable in which to store the value of the flag. 44 | func (f *FlagSet) Uint8Var(p *uint8, name string, value uint8, usage string) { 45 | f.VarP(newUint8Value(value, p), name, "", usage) 46 | } 47 | 48 | // Uint8VarP is like Uint8Var, but accepts a shorthand letter that can be used after a single dash. 49 | func (f *FlagSet) Uint8VarP(p *uint8, name, shorthand string, value uint8, usage string) { 50 | f.VarP(newUint8Value(value, p), name, shorthand, usage) 51 | } 52 | 53 | // Uint8Var defines a uint8 flag with specified name, default value, and usage string. 54 | // The argument p points to a uint8 variable in which to store the value of the flag. 55 | func Uint8Var(p *uint8, name string, value uint8, usage string) { 56 | CommandLine.VarP(newUint8Value(value, p), name, "", usage) 57 | } 58 | 59 | // Uint8VarP is like Uint8Var, but accepts a shorthand letter that can be used after a single dash. 60 | func Uint8VarP(p *uint8, name, shorthand string, value uint8, usage string) { 61 | CommandLine.VarP(newUint8Value(value, p), name, shorthand, usage) 62 | } 63 | 64 | // Uint8 defines a uint8 flag with specified name, default value, and usage string. 65 | // The return value is the address of a uint8 variable that stores the value of the flag. 66 | func (f *FlagSet) Uint8(name string, value uint8, usage string) *uint8 { 67 | p := new(uint8) 68 | f.Uint8VarP(p, name, "", value, usage) 69 | return p 70 | } 71 | 72 | // Uint8P is like Uint8, but accepts a shorthand letter that can be used after a single dash. 73 | func (f *FlagSet) Uint8P(name, shorthand string, value uint8, usage string) *uint8 { 74 | p := new(uint8) 75 | f.Uint8VarP(p, name, shorthand, value, usage) 76 | return p 77 | } 78 | 79 | // Uint8 defines a uint8 flag with specified name, default value, and usage string. 80 | // The return value is the address of a uint8 variable that stores the value of the flag. 81 | func Uint8(name string, value uint8, usage string) *uint8 { 82 | return CommandLine.Uint8P(name, "", value, usage) 83 | } 84 | 85 | // Uint8P is like Uint8, but accepts a shorthand letter that can be used after a single dash. 86 | func Uint8P(name, shorthand string, value uint8, usage string) *uint8 { 87 | return CommandLine.Uint8P(name, shorthand, value, usage) 88 | } 89 | -------------------------------------------------------------------------------- /dyskctl/vendor/github.com/spf13/pflag/int32.go: -------------------------------------------------------------------------------- 1 | package pflag 2 | 3 | import "strconv" 4 | 5 | // -- int32 Value 6 | type int32Value int32 7 | 8 | func newInt32Value(val int32, p *int32) *int32Value { 9 | *p = val 10 | return (*int32Value)(p) 11 | } 12 | 13 | func (i *int32Value) Set(s string) error { 14 | v, err := strconv.ParseInt(s, 0, 32) 15 | *i = int32Value(v) 16 | return err 17 | } 18 | 19 | func (i *int32Value) Type() string { 20 | return "int32" 21 | } 22 | 23 | func (i *int32Value) String() string { return strconv.FormatInt(int64(*i), 10) } 24 | 25 | func int32Conv(sval string) (interface{}, error) { 26 | v, err := strconv.ParseInt(sval, 0, 32) 27 | if err != nil { 28 | return 0, err 29 | } 30 | return int32(v), nil 31 | } 32 | 33 | // GetInt32 return the int32 value of a flag with the given name 34 | func (f *FlagSet) GetInt32(name string) (int32, error) { 35 | val, err := f.getFlagType(name, "int32", int32Conv) 36 | if err != nil { 37 | return 0, err 38 | } 39 | return val.(int32), nil 40 | } 41 | 42 | // Int32Var defines an int32 flag with specified name, default value, and usage string. 43 | // The argument p points to an int32 variable in which to store the value of the flag. 44 | func (f *FlagSet) Int32Var(p *int32, name string, value int32, usage string) { 45 | f.VarP(newInt32Value(value, p), name, "", usage) 46 | } 47 | 48 | // Int32VarP is like Int32Var, but accepts a shorthand letter that can be used after a single dash. 49 | func (f *FlagSet) Int32VarP(p *int32, name, shorthand string, value int32, usage string) { 50 | f.VarP(newInt32Value(value, p), name, shorthand, usage) 51 | } 52 | 53 | // Int32Var defines an int32 flag with specified name, default value, and usage string. 54 | // The argument p points to an int32 variable in which to store the value of the flag. 55 | func Int32Var(p *int32, name string, value int32, usage string) { 56 | CommandLine.VarP(newInt32Value(value, p), name, "", usage) 57 | } 58 | 59 | // Int32VarP is like Int32Var, but accepts a shorthand letter that can be used after a single dash. 60 | func Int32VarP(p *int32, name, shorthand string, value int32, usage string) { 61 | CommandLine.VarP(newInt32Value(value, p), name, shorthand, usage) 62 | } 63 | 64 | // Int32 defines an int32 flag with specified name, default value, and usage string. 65 | // The return value is the address of an int32 variable that stores the value of the flag. 66 | func (f *FlagSet) Int32(name string, value int32, usage string) *int32 { 67 | p := new(int32) 68 | f.Int32VarP(p, name, "", value, usage) 69 | return p 70 | } 71 | 72 | // Int32P is like Int32, but accepts a shorthand letter that can be used after a single dash. 73 | func (f *FlagSet) Int32P(name, shorthand string, value int32, usage string) *int32 { 74 | p := new(int32) 75 | f.Int32VarP(p, name, shorthand, value, usage) 76 | return p 77 | } 78 | 79 | // Int32 defines an int32 flag with specified name, default value, and usage string. 80 | // The return value is the address of an int32 variable that stores the value of the flag. 81 | func Int32(name string, value int32, usage string) *int32 { 82 | return CommandLine.Int32P(name, "", value, usage) 83 | } 84 | 85 | // Int32P is like Int32, but accepts a shorthand letter that can be used after a single dash. 86 | func Int32P(name, shorthand string, value int32, usage string) *int32 { 87 | return CommandLine.Int32P(name, shorthand, value, usage) 88 | } 89 | -------------------------------------------------------------------------------- /tools/verification/v_mount_ro.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -eo pipefail 4 | account="$1" 5 | key="$2" 6 | DYSKCTL="$3" 7 | 8 | 9 | echo "Adding an auto create disk 4 gb" 10 | dysk_json="$(sudo ${DYSKCTL} mount auto-create -a "${account}" -k "${key}" --size 4 -o json)" 11 | 12 | device_name="$(echo "$dysk_json" | jq -r '.Name //empty')" 13 | dysk_path="$(echo "$dysk_json" | jq -r '.Path //empty')" 14 | lease_id="$(echo "$dysk_json" | jq -r '.LeaseId //empty')" 15 | mount_point="/mnt/dysk01" 16 | message="Hello, dysk!" 17 | 18 | echo "Created: $dysk_path with lease:$lease_id" 19 | if [[ -z "$device_name" ]]; then 20 | echo "Test failed" 21 | exit 1 22 | fi 23 | 24 | echo "Added deviceName:$device_name" 25 | 26 | if [[ -z "$(lsblk | grep "$device_name" || echo -n "")" ]]; then 27 | echo "Test failed: Unable to find $device_name in blk devices" 28 | lsblk 29 | exit 1 30 | else 31 | echo "$device_name found in blk devices" 32 | fi 33 | 34 | echo "formatting /dev/${device_name}" 35 | sudo mkfs.ext4 /dev/${device_name} 36 | 37 | echo "creating mountpoint ${mount_point}" 38 | sudo mkdir -p "${mount_point}" 39 | 40 | echo "mounting device /dev/${device_name} to ${mount_point}" 41 | sudo mount -o '_netdev,x-systemd.device-bound' /dev/${device_name} ${mount_point} 42 | 43 | echo "create test file ${mount_point}/hello.txt" 44 | echo ${message} | sudo tee ${mount_point}/hello.txt # mount point created at root owned directory 45 | 46 | 47 | echo "unmounting the mount point ${mount_point}" 48 | sudo umount ${mount_point} 49 | 50 | echo "Removing deviceName:$device_name" 51 | sudo ${DYSKCTL} unmount -d "$device_name" 52 | 53 | if [[ ! -z "$(lsblk | grep "$device_name" || echo -n "")" ]]; then 54 | echo "Test failed: $device_name STILL in blk devices" 55 | lsblk 56 | exit 1 57 | fi 58 | 59 | container="$(dirname "$dysk_path")" 60 | page_blob="$(basename "$dysk_path")" 61 | #strip first / in container name 62 | container="${container:1}" 63 | 64 | echo "Remounting device ${device_name} as ro device" 65 | sudo ${DYSKCTL} mount -a "${account}" \ 66 | -k "${key}" \ 67 | --device-name ${device_name} \ 68 | --lease-id ${lease_id} \ 69 | --container-name ${container} \ 70 | --pageblob-name ${page_blob} \ 71 | --read-only 72 | 73 | 74 | if [[ -z "$(lsblk | grep "$device_name" || echo -n "")" ]]; then 75 | echo "Test failed: Unable to find $device_name in blk devices" 76 | lsblk 77 | exit 1 78 | else 79 | echo "$device_name found in blk devices" 80 | fi 81 | 82 | echo "Mount /dev/${devicename} to ${mount_point} as readonly" 83 | sudo mount -o '_netdev,x-systemd.device-bound,ro' /dev/${device_name} /${mount_point} 84 | 85 | echo "testing file previously created" 86 | 87 | new_message="$(sudo cat ${mount_point}/hello.txt)" 88 | if [[ "${message}" != "${new_message}" ]];then 89 | echo "message is not the same, expected:${message} got:${new_message}" 90 | exit 1 91 | fi 92 | 93 | echo "unmounting the mount point ${mount_point}" 94 | sudo umount ${mount_point} 95 | 96 | echo "Removing deviceName:$device_name" 97 | sudo ${DYSKCTL} unmount -d "$device_name" 98 | 99 | if [[ ! -z "$(lsblk | grep "$device_name" || echo -n "")" ]]; then 100 | echo "Test failed: $device_name STILL in blk devices" 101 | lsblk 102 | exit 1 103 | fi 104 | 105 | 106 | -------------------------------------------------------------------------------- /dyskctl/vendor/github.com/spf13/pflag/ip.go: -------------------------------------------------------------------------------- 1 | package pflag 2 | 3 | import ( 4 | "fmt" 5 | "net" 6 | "strings" 7 | ) 8 | 9 | // -- net.IP value 10 | type ipValue net.IP 11 | 12 | func newIPValue(val net.IP, p *net.IP) *ipValue { 13 | *p = val 14 | return (*ipValue)(p) 15 | } 16 | 17 | func (i *ipValue) String() string { return net.IP(*i).String() } 18 | func (i *ipValue) Set(s string) error { 19 | ip := net.ParseIP(strings.TrimSpace(s)) 20 | if ip == nil { 21 | return fmt.Errorf("failed to parse IP: %q", s) 22 | } 23 | *i = ipValue(ip) 24 | return nil 25 | } 26 | 27 | func (i *ipValue) Type() string { 28 | return "ip" 29 | } 30 | 31 | func ipConv(sval string) (interface{}, error) { 32 | ip := net.ParseIP(sval) 33 | if ip != nil { 34 | return ip, nil 35 | } 36 | return nil, fmt.Errorf("invalid string being converted to IP address: %s", sval) 37 | } 38 | 39 | // GetIP return the net.IP value of a flag with the given name 40 | func (f *FlagSet) GetIP(name string) (net.IP, error) { 41 | val, err := f.getFlagType(name, "ip", ipConv) 42 | if err != nil { 43 | return nil, err 44 | } 45 | return val.(net.IP), nil 46 | } 47 | 48 | // IPVar defines an net.IP flag with specified name, default value, and usage string. 49 | // The argument p points to an net.IP variable in which to store the value of the flag. 50 | func (f *FlagSet) IPVar(p *net.IP, name string, value net.IP, usage string) { 51 | f.VarP(newIPValue(value, p), name, "", usage) 52 | } 53 | 54 | // IPVarP is like IPVar, but accepts a shorthand letter that can be used after a single dash. 55 | func (f *FlagSet) IPVarP(p *net.IP, name, shorthand string, value net.IP, usage string) { 56 | f.VarP(newIPValue(value, p), name, shorthand, usage) 57 | } 58 | 59 | // IPVar defines an net.IP flag with specified name, default value, and usage string. 60 | // The argument p points to an net.IP variable in which to store the value of the flag. 61 | func IPVar(p *net.IP, name string, value net.IP, usage string) { 62 | CommandLine.VarP(newIPValue(value, p), name, "", usage) 63 | } 64 | 65 | // IPVarP is like IPVar, but accepts a shorthand letter that can be used after a single dash. 66 | func IPVarP(p *net.IP, name, shorthand string, value net.IP, usage string) { 67 | CommandLine.VarP(newIPValue(value, p), name, shorthand, usage) 68 | } 69 | 70 | // IP defines an net.IP flag with specified name, default value, and usage string. 71 | // The return value is the address of an net.IP variable that stores the value of the flag. 72 | func (f *FlagSet) IP(name string, value net.IP, usage string) *net.IP { 73 | p := new(net.IP) 74 | f.IPVarP(p, name, "", value, usage) 75 | return p 76 | } 77 | 78 | // IPP is like IP, but accepts a shorthand letter that can be used after a single dash. 79 | func (f *FlagSet) IPP(name, shorthand string, value net.IP, usage string) *net.IP { 80 | p := new(net.IP) 81 | f.IPVarP(p, name, shorthand, value, usage) 82 | return p 83 | } 84 | 85 | // IP defines an net.IP flag with specified name, default value, and usage string. 86 | // The return value is the address of an net.IP variable that stores the value of the flag. 87 | func IP(name string, value net.IP, usage string) *net.IP { 88 | return CommandLine.IPP(name, "", value, usage) 89 | } 90 | 91 | // IPP is like IP, but accepts a shorthand letter that can be used after a single dash. 92 | func IPP(name, shorthand string, value net.IP, usage string) *net.IP { 93 | return CommandLine.IPP(name, shorthand, value, usage) 94 | } 95 | -------------------------------------------------------------------------------- /dyskctl/vendor/github.com/spf13/cobra/zsh_completions.go: -------------------------------------------------------------------------------- 1 | package cobra 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "io" 7 | "os" 8 | "strings" 9 | ) 10 | 11 | // GenZshCompletionFile generates zsh completion file. 12 | func (c *Command) GenZshCompletionFile(filename string) error { 13 | outFile, err := os.Create(filename) 14 | if err != nil { 15 | return err 16 | } 17 | defer outFile.Close() 18 | 19 | return c.GenZshCompletion(outFile) 20 | } 21 | 22 | // GenZshCompletion generates a zsh completion file and writes to the passed writer. 23 | func (c *Command) GenZshCompletion(w io.Writer) error { 24 | buf := new(bytes.Buffer) 25 | 26 | writeHeader(buf, c) 27 | maxDepth := maxDepth(c) 28 | writeLevelMapping(buf, maxDepth) 29 | writeLevelCases(buf, maxDepth, c) 30 | 31 | _, err := buf.WriteTo(w) 32 | return err 33 | } 34 | 35 | func writeHeader(w io.Writer, cmd *Command) { 36 | fmt.Fprintf(w, "#compdef %s\n\n", cmd.Name()) 37 | } 38 | 39 | func maxDepth(c *Command) int { 40 | if len(c.Commands()) == 0 { 41 | return 0 42 | } 43 | maxDepthSub := 0 44 | for _, s := range c.Commands() { 45 | subDepth := maxDepth(s) 46 | if subDepth > maxDepthSub { 47 | maxDepthSub = subDepth 48 | } 49 | } 50 | return 1 + maxDepthSub 51 | } 52 | 53 | func writeLevelMapping(w io.Writer, numLevels int) { 54 | fmt.Fprintln(w, `_arguments \`) 55 | for i := 1; i <= numLevels; i++ { 56 | fmt.Fprintf(w, ` '%d: :->level%d' \`, i, i) 57 | fmt.Fprintln(w) 58 | } 59 | fmt.Fprintf(w, ` '%d: :%s'`, numLevels+1, "_files") 60 | fmt.Fprintln(w) 61 | } 62 | 63 | func writeLevelCases(w io.Writer, maxDepth int, root *Command) { 64 | fmt.Fprintln(w, "case $state in") 65 | defer fmt.Fprintln(w, "esac") 66 | 67 | for i := 1; i <= maxDepth; i++ { 68 | fmt.Fprintf(w, " level%d)\n", i) 69 | writeLevel(w, root, i) 70 | fmt.Fprintln(w, " ;;") 71 | } 72 | fmt.Fprintln(w, " *)") 73 | fmt.Fprintln(w, " _arguments '*: :_files'") 74 | fmt.Fprintln(w, " ;;") 75 | } 76 | 77 | func writeLevel(w io.Writer, root *Command, i int) { 78 | fmt.Fprintf(w, " case $words[%d] in\n", i) 79 | defer fmt.Fprintln(w, " esac") 80 | 81 | commands := filterByLevel(root, i) 82 | byParent := groupByParent(commands) 83 | 84 | for p, c := range byParent { 85 | names := names(c) 86 | fmt.Fprintf(w, " %s)\n", p) 87 | fmt.Fprintf(w, " _arguments '%d: :(%s)'\n", i, strings.Join(names, " ")) 88 | fmt.Fprintln(w, " ;;") 89 | } 90 | fmt.Fprintln(w, " *)") 91 | fmt.Fprintln(w, " _arguments '*: :_files'") 92 | fmt.Fprintln(w, " ;;") 93 | 94 | } 95 | 96 | func filterByLevel(c *Command, l int) []*Command { 97 | cs := make([]*Command, 0) 98 | if l == 0 { 99 | cs = append(cs, c) 100 | return cs 101 | } 102 | for _, s := range c.Commands() { 103 | cs = append(cs, filterByLevel(s, l-1)...) 104 | } 105 | return cs 106 | } 107 | 108 | func groupByParent(commands []*Command) map[string][]*Command { 109 | m := make(map[string][]*Command) 110 | for _, c := range commands { 111 | parent := c.Parent() 112 | if parent == nil { 113 | continue 114 | } 115 | m[parent.Name()] = append(m[parent.Name()], c) 116 | } 117 | return m 118 | } 119 | 120 | func names(commands []*Command) []string { 121 | ns := make([]string, len(commands)) 122 | for i, c := range commands { 123 | ns[i] = c.Name() 124 | } 125 | return ns 126 | } 127 | --------------------------------------------------------------------------------