Skip to content
This repository has been archived by the owner on Jan 28, 2022. It is now read-only.

feature: workspaceitem #57

Merged
merged 2 commits into from
Aug 8, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions PROJECT
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,6 @@ resources:
- group: databricks
version: v1
kind: DbfsBlock
- group: databricks
version: v1
kind: WorkspaceItem
115 changes: 115 additions & 0 deletions api/v1/workspaceitem_types.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
/*
Copyright 2019 microsoft.

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 v1

import (
"crypto/sha1"
"encoding/base64"
"fmt"

dbmodels "github.com/xinsnake/databricks-sdk-golang/azure/models"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

// WorkspaceItemSpec defines the desired state of WorkspaceItem
type WorkspaceItemSpec struct {
Content string `json:"content,omitempty"`
Path string `json:"path,omitempty"`
Language dbmodels.Language `json:"language,omitempty"`
Format dbmodels.ExportFormat `json:"format,omitempty"`
}

// WorkspaceItemStatus defines the observed state of WorkspaceItem
type WorkspaceItemStatus struct {
ObjectInfo *dbmodels.ObjectInfo `json:"object_info,omitempty"`
ObjectHash string `json:"object_hash,omitempty"`
}

// +kubebuilder:object:root=true

// WorkspaceItem is the Schema for the workspaceitems API
// +kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp",priority=0
// +kubebuilder:printcolumn:name="SHA1SUM",type="string",JSONPath=".status.object_hash",priority=0
// +kubebuilder:printcolumn:name="Language",type="string",JSONPath=".status.object_info.language",priority=0
// +kubebuilder:printcolumn:name="Type",type="string",JSONPath=".status.object_info.object_type",priority=1
// +kubebuilder:printcolumn:name="Path",type="string",JSONPath=".status.object_info.path",priority=1
type WorkspaceItem struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`

Spec *WorkspaceItemSpec `json:"spec,omitempty"`
Status *WorkspaceItemStatus `json:"status,omitempty"`
}

func (wi *WorkspaceItem) IsBeingDeleted() bool {
return !wi.ObjectMeta.DeletionTimestamp.IsZero()
}

func (wi *WorkspaceItem) IsSubmitted() bool {
if wi.Status == nil || wi.Status.ObjectInfo == nil || wi.Status.ObjectInfo.Path == "" {
return false
}
return true
}

// IsUpToDate tells you whether the data is up-to-date with the status
func (wi *WorkspaceItem) IsUpToDate() bool {
if wi.Status == nil {
return false
}
h := wi.GetHash()
return h == wi.Status.ObjectHash
}

// GetHash returns the sha1 hash of the decoded data attribute
func (wi *WorkspaceItem) GetHash() string {
data, err := base64.StdEncoding.DecodeString(wi.Spec.Content)
if err != nil {
return ""
}
h := sha1.New()
h.Write(data)
bs := h.Sum(nil)
return fmt.Sprintf("%x", bs)
}

const WorkspaceItemFinalizerName = "workspaceitem.finalizers.databricks.microsoft.com"

func (wi *WorkspaceItem) HasFinalizer(finalizerName string) bool {
return containsString(wi.ObjectMeta.Finalizers, finalizerName)
}

func (wi *WorkspaceItem) AddFinalizer(finalizerName string) {
wi.ObjectMeta.Finalizers = append(wi.ObjectMeta.Finalizers, finalizerName)
}

func (wi *WorkspaceItem) RemoveFinalizer(finalizerName string) {
wi.ObjectMeta.Finalizers = removeString(wi.ObjectMeta.Finalizers, finalizerName)
}

// +kubebuilder:object:root=true

// WorkspaceItemList contains a list of WorkspaceItem
type WorkspaceItemList struct {
metav1.TypeMeta `json:",inline"`
metav1.ListMeta `json:"metadata,omitempty"`
Items []WorkspaceItem `json:"items"`
}

func init() {
SchemeBuilder.Register(&WorkspaceItem{}, &WorkspaceItemList{})
}
149 changes: 149 additions & 0 deletions api/v1/workspaceitem_types_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
/*
Copyright 2019 microsoft.

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 v1

import (
"time"

. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
dbmodels "github.com/xinsnake/databricks-sdk-golang/azure/models"

"golang.org/x/net/context"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
)

// These tests are written in BDD-style using Ginkgo framework. Refer to
// http://onsi.github.io/ginkgo to learn more.

var _ = Describe("WorkspaceItem", func() {
var (
key types.NamespacedName
created, fetched *WorkspaceItem
)

BeforeEach(func() {
// Add any setup steps that needs to be executed before each test
})

AfterEach(func() {
// Add any teardown steps that needs to be executed after each test
})

// Add Tests for OpenAPI validation (or additonal CRD features) specified in
// your API definition.
// Avoid adding tests for vanilla CRUD operations because they would
// test Kubernetes API server, which isn't the goal here.
Context("Create API", func() {

It("should create an object successfully", func() {

key = types.NamespacedName{
Name: "foo",
Namespace: "default",
}
created = &WorkspaceItem{
ObjectMeta: metav1.ObjectMeta{
Name: "foo",
Namespace: "default",
}}

By("creating an API obj")
Expect(k8sClient.Create(context.TODO(), created)).To(Succeed())

fetched = &WorkspaceItem{}
Expect(k8sClient.Get(context.TODO(), key, fetched)).To(Succeed())
Expect(fetched).To(Equal(created))

By("deleting the created object")
Expect(k8sClient.Delete(context.TODO(), created)).To(Succeed())
Expect(k8sClient.Get(context.TODO(), key, created)).ToNot(Succeed())
})

It("should correctly handle isSubmitted", func() {
wiItem := &WorkspaceItem{
Status: &WorkspaceItemStatus{
ObjectInfo: &dbmodels.ObjectInfo{
Path: "",
},
},
}
Expect(wiItem.IsSubmitted()).To(BeFalse())

wiItem2 := &WorkspaceItem{
Status: &WorkspaceItemStatus{
ObjectInfo: &dbmodels.ObjectInfo{
Path: "/test-path",
},
},
}
Expect(wiItem2.IsSubmitted()).To(BeTrue())

wiItem3 := &WorkspaceItem{
Status: &WorkspaceItemStatus{
ObjectInfo: nil,
},
}
Expect(wiItem3.IsSubmitted()).To(BeFalse())
})

It("should correctly handle finalizers", func() {
wiItem := &WorkspaceItem{
ObjectMeta: metav1.ObjectMeta{
DeletionTimestamp: &metav1.Time{
Time: time.Now(),
},
},
}
Expect(wiItem.IsBeingDeleted()).To(BeTrue())

wiItem.AddFinalizer(WorkspaceItemFinalizerName)
Expect(len(wiItem.GetFinalizers())).To(Equal(1))
Expect(wiItem.HasFinalizer(WorkspaceItemFinalizerName)).To(BeTrue())

wiItem.RemoveFinalizer(WorkspaceItemFinalizerName)
Expect(len(wiItem.GetFinalizers())).To(Equal(0))
Expect(wiItem.HasFinalizer(WorkspaceItemFinalizerName)).To(BeFalse())
})

It("should correctly handle file hash", func() {
wiItem := &WorkspaceItem{
Spec: &WorkspaceItemSpec{
Content: "dGVzdA==",
},
}

Expect(wiItem.GetHash()).To(Equal("a94a8fe5ccb19ba61c4c0873d391e987982fbbd3"))
Expect(wiItem.IsUpToDate()).To(BeFalse())

wiItem.Status = &WorkspaceItemStatus{
ObjectHash: "a94a8fe5ccb19ba61c4c0873d391e987982fbbd3",
}
Expect(wiItem.IsUpToDate()).To(BeTrue())

wiItemError := &WorkspaceItem{
Spec: &WorkspaceItemSpec{
Content: "invalid_base64",
},
}
Expect(wiItemError.GetHash()).To(Equal(""))
})

})

})
102 changes: 102 additions & 0 deletions api/v1/zz_generated.deepcopy.go
Original file line number Diff line number Diff line change
Expand Up @@ -651,3 +651,105 @@ func (in *SecretScopeValueFrom) DeepCopy() *SecretScopeValueFrom {
in.DeepCopyInto(out)
return out
}

// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *WorkspaceItem) DeepCopyInto(out *WorkspaceItem) {
*out = *in
out.TypeMeta = in.TypeMeta
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
if in.Spec != nil {
in, out := &in.Spec, &out.Spec
*out = new(WorkspaceItemSpec)
**out = **in
}
if in.Status != nil {
in, out := &in.Status, &out.Status
*out = new(WorkspaceItemStatus)
(*in).DeepCopyInto(*out)
}
}

// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new WorkspaceItem.
func (in *WorkspaceItem) DeepCopy() *WorkspaceItem {
if in == nil {
return nil
}
out := new(WorkspaceItem)
in.DeepCopyInto(out)
return out
}

// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *WorkspaceItem) DeepCopyObject() runtime.Object {
if c := in.DeepCopy(); c != nil {
return c
}
return nil
}

// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *WorkspaceItemList) DeepCopyInto(out *WorkspaceItemList) {
*out = *in
out.TypeMeta = in.TypeMeta
out.ListMeta = in.ListMeta
if in.Items != nil {
in, out := &in.Items, &out.Items
*out = make([]WorkspaceItem, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
}

// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new WorkspaceItemList.
func (in *WorkspaceItemList) DeepCopy() *WorkspaceItemList {
if in == nil {
return nil
}
out := new(WorkspaceItemList)
in.DeepCopyInto(out)
return out
}

// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *WorkspaceItemList) DeepCopyObject() runtime.Object {
if c := in.DeepCopy(); c != nil {
return c
}
return nil
}

// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *WorkspaceItemSpec) DeepCopyInto(out *WorkspaceItemSpec) {
*out = *in
}

// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new WorkspaceItemSpec.
func (in *WorkspaceItemSpec) DeepCopy() *WorkspaceItemSpec {
if in == nil {
return nil
}
out := new(WorkspaceItemSpec)
in.DeepCopyInto(out)
return out
}

// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *WorkspaceItemStatus) DeepCopyInto(out *WorkspaceItemStatus) {
*out = *in
if in.ObjectInfo != nil {
in, out := &in.ObjectInfo, &out.ObjectInfo
*out = new(models.ObjectInfo)
(*in).DeepCopyInto(*out)
}
}

// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new WorkspaceItemStatus.
func (in *WorkspaceItemStatus) DeepCopy() *WorkspaceItemStatus {
if in == nil {
return nil
}
out := new(WorkspaceItemStatus)
in.DeepCopyInto(out)
return out
}
Loading