Skip to content

Commit

Permalink
Add virtualmachinetemplateversions.harvesterhci.io mutator
Browse files Browse the repository at this point in the history
Signed-off-by: Kiefer Chang <kiefer.chang@suse.com>
  • Loading branch information
bk201 authored and guangbochen committed Jun 11, 2021
1 parent 4851964 commit fde9a7c
Show file tree
Hide file tree
Showing 4 changed files with 170 additions and 97 deletions.
11 changes: 0 additions & 11 deletions pkg/api/vmtemplate/schema.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import (
"github.com/rancher/apiserver/pkg/types"
"github.com/rancher/steve/pkg/schema"
"github.com/rancher/steve/pkg/server"
"github.com/rancher/steve/pkg/stores/proxy"

"github.com/harvester/harvester/pkg/config"
)
Expand All @@ -15,32 +14,22 @@ const (
)

func RegisterSchema(scaled *config.Scaled, server *server.Server, options config.Options) error {
templates := scaled.HarvesterFactory.Harvesterhci().V1beta1().VirtualMachineTemplate()
templateVersionCache := scaled.HarvesterFactory.Harvesterhci().V1beta1().VirtualMachineTemplateVersion().Cache()
th := &templateLinkHandler{
templateVersionCache: templateVersionCache,
}

templateVersionStore := &templateVersionStore{
Store: proxy.NewProxyStore(server.ClientFactory, nil, server.AccessSetLookup),
templateCache: templates.Cache(),
templateVersionCache: templateVersionCache,
keyPairCache: scaled.HarvesterFactory.Harvesterhci().V1beta1().KeyPair().Cache(),
}

t := []schema.Template{
{
ID: templateSchemaID,
Formatter: formatter,
Customize: func(apiSchema *types.APISchema) {
apiSchema.ByIDHandler = th.byIDHandler
},
Store: proxy.NewProxyStore(server.ClientFactory, nil, server.AccessSetLookup),
},
{
ID: templateVersionSchemaID,
Formatter: versionFormatter,
Store: templateVersionStore,
},
}

Expand Down
86 changes: 0 additions & 86 deletions pkg/api/vmtemplate/template_version_store.go

This file was deleted.

59 changes: 59 additions & 0 deletions pkg/webhook/resources/templateversion/mutator.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package templateversion

import (
"fmt"

admissionregv1 "k8s.io/api/admissionregistration/v1"
"k8s.io/apimachinery/pkg/runtime"

"github.com/harvester/harvester/pkg/apis/harvesterhci.io/v1beta1"
"github.com/harvester/harvester/pkg/ref"
werror "github.com/harvester/harvester/pkg/webhook/error"
"github.com/harvester/harvester/pkg/webhook/types"
)

func NewMutator() types.Mutator {
return &templateVersionMutator{}
}

type templateVersionMutator struct {
types.DefaultMutator
}

func newResource(ops []admissionregv1.OperationType) types.Resource {
return types.Resource{
Name: v1beta1.VirtualMachineTemplateVersionResourceName,
Scope: admissionregv1.NamespacedScope,
APIGroup: v1beta1.SchemeGroupVersion.Group,
APIVersion: v1beta1.SchemeGroupVersion.Version,
ObjectType: &v1beta1.VirtualMachineTemplateVersion{},
OperationTypes: ops,
}
}

func (m *templateVersionMutator) Resource() types.Resource {
return newResource([]admissionregv1.OperationType{
admissionregv1.Create,
})
}

func (m *templateVersionMutator) Create(request *types.Request, newObj runtime.Object) (types.PatchOps, error) {
vmTemplVersion := newObj.(*v1beta1.VirtualMachineTemplateVersion)

templateID := vmTemplVersion.Spec.TemplateID
if templateID == "" {
return nil, werror.NewInvalidError("TemplateId is empty", fieldTemplateID)
}

_, templateName := ref.Parse(templateID)

// Do not generate a name if there is a name.
if vmTemplVersion.Name != "" {
return nil, nil
}

// patch "metadata.generateName" with "{templateName}-"
var patchOps types.PatchOps
patchOps = append(patchOps, fmt.Sprintf(`{"op": "replace", "path": "/metadata/generateName", "value": "%s"}`, templateName+"-"))
return patchOps, nil
}
111 changes: 111 additions & 0 deletions pkg/webhook/resources/templateversion/validator.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
package templateversion

import (
"fmt"

"github.com/sirupsen/logrus"
admissionregv1 "k8s.io/api/admissionregistration/v1"
"k8s.io/apimachinery/pkg/runtime"

"github.com/harvester/harvester/pkg/apis/harvesterhci.io/v1beta1"
ctlharvesterv1 "github.com/harvester/harvester/pkg/generated/controllers/harvesterhci.io/v1beta1"
"github.com/harvester/harvester/pkg/ref"
werror "github.com/harvester/harvester/pkg/webhook/error"
"github.com/harvester/harvester/pkg/webhook/types"
)

const (
fieldTemplateID = "spec.templateId"
fieldKeyPairIds = "spec.keyPairIds"
)

func NewValidator(templateCache ctlharvesterv1.VirtualMachineTemplateCache, templateVersionCache ctlharvesterv1.VirtualMachineTemplateVersionCache, keypairs ctlharvesterv1.KeyPairCache) types.Validator {
return &templateVersionValidator{
templateCache: templateCache,
templateVersionCache: templateVersionCache,
keypairs: keypairs,
}
}

type templateVersionValidator struct {
types.DefaultValidator

templateCache ctlharvesterv1.VirtualMachineTemplateCache
templateVersionCache ctlharvesterv1.VirtualMachineTemplateVersionCache
keypairs ctlharvesterv1.KeyPairCache
}

func (v *templateVersionValidator) Resource() types.Resource {
return newResource([]admissionregv1.OperationType{
admissionregv1.Create,
admissionregv1.Update,
admissionregv1.Delete,
})
}

func (v *templateVersionValidator) Create(request *types.Request, newObj runtime.Object) error {
vmTemplVersion := newObj.(*v1beta1.VirtualMachineTemplateVersion)

templateID := vmTemplVersion.Spec.TemplateID
if templateID == "" {
return werror.NewInvalidError("TemplateId is empty", fieldTemplateID)
}

templateNs, templateName := ref.Parse(templateID)
if vmTemplVersion.Namespace != templateNs {
return werror.NewInvalidError("Template version and template should reside in the same namespace", "metadata.namespace")
}

if _, err := v.templateCache.Get(templateNs, templateName); err != nil {
return werror.NewInvalidError(err.Error(), fieldTemplateID)
}

keyPairIDs := vmTemplVersion.Spec.KeyPairIDs
if len(keyPairIDs) > 0 {
for i, kp := range keyPairIDs {
keyPairNs, keyPairName := ref.Parse(kp)
_, err := v.keypairs.Get(keyPairNs, keyPairName)
if err != nil {
message := fmt.Sprintf("KeyPairID %s is invalid, %v", v, err)
field := fmt.Sprintf("%s[%d]", fieldKeyPairIds, i)
return werror.NewInvalidError(message, field)
}
}
}

return nil
}

func (v *templateVersionValidator) Update(request *types.Request, oldObj runtime.Object, newObj runtime.Object) error {
if request.IsFromController() {
return nil
}
logrus.Infof("not allow for user %s", request.UserInfo.Username)
return werror.NewMethodNotAllowed("Update templateVersion is not supported")
}

func (v *templateVersionValidator) Delete(request *types.Request, oldObj runtime.Object) error {
// If a template is deleted, its versions are garbage collected.
// No need to check for template existence or if a version is the default version or not.
if request.IsGarbageCollection() {
return nil
}
vmTemplVersion := oldObj.(*v1beta1.VirtualMachineTemplateVersion)
version, err := v.templateVersionCache.Get(vmTemplVersion.Namespace, vmTemplVersion.Name)
if err != nil {
return err
}

templNs, templName := ref.Parse(version.Spec.TemplateID)
vt, err := v.templateCache.Get(templNs, templName)
if err != nil {
return err
}

vresionID := ref.Construct(vmTemplVersion.Namespace, vmTemplVersion.Name)
if vt.Spec.DefaultVersionID == vresionID {
return werror.NewBadRequest("Cannot delete the default templateVersion")
}

return nil
}

0 comments on commit fde9a7c

Please sign in to comment.