Skip to content

Commit

Permalink
Merge pull request #7 from Xelon-AG/feat/expand-volume-capability
Browse files Browse the repository at this point in the history
feat: implement VolumeExpansion plugin capability
  • Loading branch information
pavel-github authored Jan 19, 2023
2 parents 059a616 + b566474 commit e5ef20c
Show file tree
Hide file tree
Showing 14 changed files with 1,432 additions and 84 deletions.
31 changes: 31 additions & 0 deletions .github/workflows/release-dev.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
name: Release Dev
on:
workflow_dispatch:

permissions:
contents: write

jobs:
release:
name: release
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
with:
fetch-depth: 0

- name: Set up Go
uses: actions/setup-go@v3
with:
go-version-file: "go.mod"
cache: true

- name: Login to Docker Hub
uses: docker/login-action@v1
with:
username: ${{ secrets.DOCKER_HUB_USERNAME }}
password: ${{ secrets.DOCKER_HUB_TOKEN }}

- name: Release development Docker image
run: make release-docker-dev
19 changes: 11 additions & 8 deletions .github/workflows/release.yml → .github/workflows/release.yaml
Original file line number Diff line number Diff line change
@@ -1,24 +1,27 @@
name: release
name: Release
on:
push:
tags:
- 'v*'

permissions:
contents: write

jobs:
release:
name: Release
name: release
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2

- name: Unshallow
run: git fetch --prune --unshallow
uses: actions/checkout@v3
with:
fetch-depth: 0

- name: Set up Go
uses: actions/setup-go@v2
uses: actions/setup-go@v3
with:
go-version: 1.15
go-version-file: "go.mod"
cache: true

- name: Login to Docker Hub
uses: docker/login-action@v1
Expand Down
43 changes: 43 additions & 0 deletions .github/workflows/tests.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
name: Tests
on:
pull_request:
paths-ignore:
- "CHANGELOG.md"
- "README.md"
push:
branches: [ master ]
paths-ignore:
- "CHANGELOG.md"
- "README.md"

permissions:
contents: read

jobs:
unit-tests:
name: unit tests
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3

- name: Set up Go
uses: actions/setup-go@v3
with:
go-version-file: "go.mod"

- name: Set up cache
uses: actions/cache@v3
with:
path: |
~/.cache/go-build
~/go/pkg/mod
key: ${{ runner.os }}-go-${{ hashFiles('go.sum', 'tools/go.sum') }}
restore-keys: |
${{ runner.os }}-go-
- name: Lint source code
run: make tools lint

- name: Run unit tests
run: make test
32 changes: 0 additions & 32 deletions .github/workflows/unit_tests.yml

This file was deleted.

8 changes: 5 additions & 3 deletions .golangci.yml → .golangci.yaml
Original file line number Diff line number Diff line change
@@ -1,19 +1,21 @@
linters:
disable-all: true
enable:
- deadcode
- errcheck
- gofmt
- goimports
- gosimple
- ineffassign
- misspell
- staticcheck
- structcheck
- unconvert
- unused
- varcheck
- vet

linters-settings:
goimports:
local-prefixes: github.com/Xelon-AG/xelon-csi

output:
format: tab

Expand Down
9 changes: 3 additions & 6 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,8 @@ LDFLAGS := $(LDFLAGS) -X github.com/Xelon-AG/xelon-csi/driver.buildDate=${BUILD_
## tools: Install required tooling.
.PHONY: tools
tools:
ifeq (,$(wildcard ./.bin/golangci-lint*))
@curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b .bin/ v1.24.0
else
@echo "==> Required tooling is already installed"
endif
@echo "==> Installing required tooling..."
@cd tools && go install github.com/golangci/golangci-lint/cmd/golangci-lint


## clean: Delete the build directory.
Expand All @@ -41,7 +38,7 @@ clean:
.PHONY: lint
lint:
@echo "==> Linting code with 'golangci-lint'..."
@.bin/golangci-lint run ./...
@golangci-lint run ./...


## test: Run all unit tests.
Expand Down
3 changes: 2 additions & 1 deletion cmd/xelon-csi/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,10 @@ import (
"os"
"time"

"github.com/sirupsen/logrus"

"github.com/Xelon-AG/xelon-csi/driver"
"github.com/Xelon-AG/xelon-csi/driver/helper"
"github.com/sirupsen/logrus"
)

func main() {
Expand Down
91 changes: 79 additions & 12 deletions driver/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,14 @@ import (
"strings"
"time"

"github.com/Xelon-AG/xelon-csi/driver/helper"
"github.com/Xelon-AG/xelon-sdk-go/xelon"
"github.com/container-storage-interface/spec/lib/go/csi"
"github.com/sirupsen/logrus"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
"k8s.io/klog"

"github.com/Xelon-AG/xelon-csi/driver/helper"
)

const (
Expand All @@ -38,6 +39,7 @@ var (
controllerCapabilities = []csi.ControllerServiceCapability_RPC_Type{
csi.ControllerServiceCapability_RPC_CREATE_DELETE_VOLUME,
csi.ControllerServiceCapability_RPC_PUBLISH_UNPUBLISH_VOLUME,
csi.ControllerServiceCapability_RPC_EXPAND_VOLUME,
}

xelonStorageUUID = DefaultDriverName + "/storage-uuid"
Expand All @@ -55,11 +57,11 @@ func (d *Driver) initializeControllerService(config *Config) error {

userAgent := fmt.Sprintf("%s/%s (%s)", DefaultDriverName, driverVersion, gitCommit)

client := xelon.NewClient(d.config.Token)
client.SetBaseURL(d.config.BaseURL)
client.SetUserAgent(userAgent)
opts := []xelon.ClientOption{xelon.WithUserAgent(userAgent)}
opts = append(opts, xelon.WithBaseURL(d.config.BaseURL))
client := xelon.NewClient(d.config.Token, opts...)

tenant, _, err := client.Tenant.Get(context.Background())
tenant, _, err := client.Tenants.GetCurrent(context.Background())
if err != nil {
return err
}
Expand Down Expand Up @@ -344,7 +346,7 @@ func (d *Driver) ControllerUnpublishVolume(ctx context.Context, req *csi.Control
return &csi.ControllerUnpublishVolumeResponse{}, nil
}

func (d *Driver) ValidateVolumeCapabilities(ctx context.Context, req *csi.ValidateVolumeCapabilitiesRequest) (*csi.ValidateVolumeCapabilitiesResponse, error) {
func (d *Driver) ValidateVolumeCapabilities(_ context.Context, _ *csi.ValidateVolumeCapabilitiesRequest) (*csi.ValidateVolumeCapabilitiesResponse, error) {
klog.V(4).Infof("ValidateVolumeCapabilities is not yet implemented")
return nil, status.Error(codes.Unimplemented, "ValidateVolumeCapabilities is not yet implemented")
}
Expand Down Expand Up @@ -379,32 +381,97 @@ func (d *Driver) ControllerGetCapabilities(_ context.Context, req *csi.Controlle

// CreateSnapshot will be called by the CO to create a new snapshot from a
// source volume on behalf of a user.
func (d *Driver) CreateSnapshot(ctx context.Context, req *csi.CreateSnapshotRequest) (*csi.CreateSnapshotResponse, error) {
func (d *Driver) CreateSnapshot(_ context.Context, _ *csi.CreateSnapshotRequest) (*csi.CreateSnapshotResponse, error) {
klog.V(4).Infof("CreateSnapshot is not yet implemented")
return nil, status.Error(codes.Unimplemented, "CreateSnapshot is not yet implemented")
}

// DeleteSnapshot will be called by the CO to delete a snapshot.
func (d *Driver) DeleteSnapshot(ctx context.Context, req *csi.DeleteSnapshotRequest) (*csi.DeleteSnapshotResponse, error) {
func (d *Driver) DeleteSnapshot(_ context.Context, _ *csi.DeleteSnapshotRequest) (*csi.DeleteSnapshotResponse, error) {
klog.V(4).Infof("DeleteSnapshot is not yet implemented")
return nil, status.Error(codes.Unimplemented, "DeleteSnapshot is not yet implemented")
}

// ListSnapshots returns the information about all snapshots on the storage
// system within the given parameters regardless of how they were created.
func (d *Driver) ListSnapshots(ctx context.Context, req *csi.ListSnapshotsRequest) (*csi.ListSnapshotsResponse, error) {
func (d *Driver) ListSnapshots(_ context.Context, _ *csi.ListSnapshotsRequest) (*csi.ListSnapshotsResponse, error) {
klog.V(4).Infof("ListSnapshots is not yet implemented")
return nil, status.Error(codes.Unimplemented, "ListSnapshots is not yet implemented")
}

// ControllerExpandVolume is called from the resizer to increase the volume size.
func (d *Driver) ControllerExpandVolume(ctx context.Context, req *csi.ControllerExpandVolumeRequest) (*csi.ControllerExpandVolumeResponse, error) {
klog.V(4).Infof("ControllerExpandVolume is not yet implemented")
return nil, status.Error(codes.Unimplemented, "ControllerExpandVolume is not yet implemented")
volumeID := req.GetVolumeId()

if volumeID == "" {
return nil, status.Error(codes.InvalidArgument, "ControllerExpandVolume volume ID missing in request")
}

storage, _, err := d.xelon.PersistentStorages.Get(ctx, d.tenantID, req.VolumeId)
if err != nil {
return nil, status.Errorf(codes.Internal, "ControllerExpandVolume could not retrieve existing volume: %v", err)
}

resizeBytes, err := extractStorage(req.GetCapacityRange())
if err != nil {
return nil, status.Errorf(codes.OutOfRange, "ControllerExpandVolume invalid capacity range: %v", err)
}

log := d.log.WithFields(logrus.Fields{
"method": "expand_volume",
"storage_size_gigabytes": resizeBytes / giB,
"volume_id": volumeID,
})
log.Info("expand volume called")

if resizeBytes <= int64(storage.Capacity*giB) {
log.WithFields(logrus.Fields{
"current_volume_size": int64(storage.Capacity * giB),
"requested_volume_size": resizeBytes,
}).Info("skipping volume resize because current volume size exceeds requested volume size")

return &csi.ControllerExpandVolumeResponse{
CapacityBytes: int64(storage.Capacity * giB),
NodeExpansionRequired: true,
}, nil
}

extendRequest := &xelon.PersistentStorageExtendRequest{
Size: int(resizeBytes / giB),
}
log.WithField("volume_extend_request", extendRequest).Info("extending volume")
apiResponse, _, err := d.xelon.PersistentStorages.Extend(ctx, volumeID, extendRequest)
if err != nil {
return nil, status.Errorf(codes.Internal, "could not extend volume: %v: %v", apiResponse, err)
}

volumeReady := false
for i := 0; i < volumeStatusCheckRetries; i++ {
time.Sleep(volumeStatusCheckInterval * time.Second)
storage, _, err := d.xelon.PersistentStorages.Get(ctx, d.tenantID, volumeID)
if err != nil {
return nil, status.Error(codes.Internal, err.Error())
}
if storage.UUID != "" && storage.Formatted == 1 {
volumeReady = true
break
}
}
if !volumeReady {
return nil, status.Errorf(codes.Internal, "volume is not ready %v seconds", volumeStatusCheckRetries*volumeStatusCheckInterval)
}

log.WithField("new_volume_size", resizeBytes)
log.Info("volume was resized")

return &csi.ControllerExpandVolumeResponse{
CapacityBytes: resizeBytes,
NodeExpansionRequired: true,
}, nil
}

// ControllerGetVolume gets a specific volume.
func (d *Driver) ControllerGetVolume(ctx context.Context, req *csi.ControllerGetVolumeRequest) (*csi.ControllerGetVolumeResponse, error) {
func (d *Driver) ControllerGetVolume(_ context.Context, _ *csi.ControllerGetVolumeRequest) (*csi.ControllerGetVolumeResponse, error) {
klog.V(4).Infof("ControllerGetVolume is not yet implemented")
return nil, status.Error(codes.Unimplemented, "ControllerGetVolume is not yet implemented")
}
Expand Down
Loading

0 comments on commit e5ef20c

Please sign in to comment.