From 43f639dbc5363e9df92f44a9dafe14f47d8b979d Mon Sep 17 00:00:00 2001 From: Lukas Frank Date: Tue, 28 Mar 2023 16:02:36 +0200 Subject: [PATCH] `ori-volume` mock server --- ori/testing/volume/fake.go | 157 +++++++++++++++++++++++++++++++++++++ 1 file changed, 157 insertions(+) create mode 100644 ori/testing/volume/fake.go diff --git a/ori/testing/volume/fake.go b/ori/testing/volume/fake.go new file mode 100644 index 000000000..4d739310d --- /dev/null +++ b/ori/testing/volume/fake.go @@ -0,0 +1,157 @@ +// Copyright 2022 OnMetal authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package volume + +import ( + "context" + "crypto/rand" + "encoding/hex" + "strconv" + "sync" + "time" + + ori "github.com/onmetal/onmetal-api/ori/apis/volume/v1alpha1" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + "k8s.io/apimachinery/pkg/labels" +) + +func filterInLabels(labelSelector, lbls map[string]string) bool { + return labels.SelectorFromSet(labelSelector).Matches(labels.Set(lbls)) +} + +const defaultIDLength = 63 + +func generateID(length int) string { + data := make([]byte, (length/2)+1) + for { + _, _ = rand.Read(data) + id := hex.EncodeToString(data) + + // Truncated versions of the id should not be numerical. + if _, err := strconv.ParseInt(id[:12], 10, 64); err != nil { + continue + } + + return id[:length] + } +} + +type FakeVolume struct { + ori.Volume +} + +type FakeVolumeClass struct { + ori.VolumeClass +} + +type FakeRuntimeService struct { + sync.Mutex + + Volumes map[string]*FakeVolume + VolumeClasses map[string]*FakeVolumeClass +} + +func NewFakeRuntimeService() *FakeRuntimeService { + return &FakeRuntimeService{ + Volumes: make(map[string]*FakeVolume), + VolumeClasses: make(map[string]*FakeVolumeClass), + } +} + +func (r *FakeRuntimeService) SetVolumes(volumes []*FakeVolume) { + r.Lock() + defer r.Unlock() + + r.Volumes = make(map[string]*FakeVolume) + for _, volume := range volumes { + r.Volumes[volume.Metadata.Id] = volume + } +} + +func (r *FakeRuntimeService) SetVolumeClasses(volumeClasses []*FakeVolumeClass) { + r.Lock() + defer r.Unlock() + + r.VolumeClasses = make(map[string]*FakeVolumeClass) + for _, volumeClass := range volumeClasses { + r.VolumeClasses[volumeClass.Name] = volumeClass + } +} + +func (r *FakeRuntimeService) ListVolumes(ctx context.Context, req *ori.ListVolumesRequest) (*ori.ListVolumesResponse, error) { + r.Lock() + defer r.Unlock() + + filter := req.Filter + + var res []*ori.Volume + for _, v := range r.Volumes { + if filter != nil { + if filter.Id != "" && filter.Id != v.Metadata.Id { + continue + } + if filter.LabelSelector != nil && !filterInLabels(filter.LabelSelector, v.Metadata.Labels) { + continue + } + } + + volume := v.Volume + res = append(res, &volume) + } + return &ori.ListVolumesResponse{Volumes: res}, nil +} + +func (r *FakeRuntimeService) CreateVolume(ctx context.Context, req *ori.CreateVolumeRequest) (*ori.CreateVolumeResponse, error) { + r.Lock() + defer r.Unlock() + + volume := *req.Volume + volume.Metadata.Id = generateID(defaultIDLength) + volume.Metadata.CreatedAt = time.Now().UnixNano() + + r.Volumes[volume.Metadata.Id] = &FakeVolume{ + Volume: volume, + } + + return &ori.CreateVolumeResponse{ + Volume: &volume, + }, nil +} + +func (r *FakeRuntimeService) DeleteVolume(ctx context.Context, req *ori.DeleteVolumeRequest) (*ori.DeleteVolumeResponse, error) { + r.Lock() + defer r.Unlock() + + volumeID := req.VolumeId + if _, ok := r.Volumes[volumeID]; !ok { + return nil, status.Errorf(codes.NotFound, "volume %q not found", volumeID) + } + + delete(r.Volumes, volumeID) + return &ori.DeleteVolumeResponse{}, nil +} + +func (r *FakeRuntimeService) ListVolumeClasses(ctx context.Context, req *ori.ListVolumeClassesRequest) (*ori.ListVolumeClassesResponse, error) { + r.Lock() + defer r.Unlock() + + var res []*ori.VolumeClass + for _, m := range r.VolumeClasses { + volumeClass := m.VolumeClass + res = append(res, &volumeClass) + } + return &ori.ListVolumeClassesResponse{VolumeClasses: res}, nil +}