Skip to content

Commit

Permalink
Add OnHostMaintenance and ConfidentialCompute to GCPMachineSpec
Browse files Browse the repository at this point in the history
Add manual conversion for ConfidentialCompute and OnHostMaintenance
Add webhook to validate that OnHostMaintenance is set to TERMINATE if ConfidentialCompute is Enabled
Add webhook to validate that the instanceType belongs to a machine series that support confidentail computing

Update machine.go to set instance.ConfidentialCompute and instance.OnHostMaintenance according to GCPMachine.Spec
  • Loading branch information
eranco74 committed Jan 26, 2023
1 parent 517caab commit c37a092
Show file tree
Hide file tree
Showing 18 changed files with 516 additions and 7 deletions.
8 changes: 8 additions & 0 deletions api/v1alpha3/gcpmachine_conversion.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,14 @@ func (src *GCPMachine) ConvertTo(dstRaw conversion.Hub) error { // nolint
dst.Spec.ShieldedInstanceConfig = restored.Spec.ShieldedInstanceConfig
}

if restored.Spec.OnHostMaintenance != nil {
dst.Spec.OnHostMaintenance = restored.Spec.OnHostMaintenance
}

if restored.Spec.ConfidentialCompute != nil {
dst.Spec.ConfidentialCompute = restored.Spec.ConfidentialCompute
}

return nil
}

Expand Down
8 changes: 8 additions & 0 deletions api/v1alpha3/gcpmachinetemplate_conversion.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,14 @@ func (src *GCPMachineTemplate) ConvertTo(dstRaw conversion.Hub) error { // nolin
dst.Spec.Template.Spec.ShieldedInstanceConfig = restored.Spec.Template.Spec.ShieldedInstanceConfig
}

if restored.Spec.Template.Spec.OnHostMaintenance != nil {
dst.Spec.Template.Spec.OnHostMaintenance = restored.Spec.Template.Spec.OnHostMaintenance
}

if restored.Spec.Template.Spec.ConfidentialCompute != nil {
dst.Spec.Template.Spec.ConfidentialCompute = restored.Spec.Template.Spec.ConfidentialCompute
}

return nil
}

Expand Down
2 changes: 2 additions & 0 deletions api/v1alpha3/zz_generated.conversion.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions api/v1alpha4/gcpmachine_conversion.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,14 @@ func (src *GCPMachine) ConvertTo(dstRaw conversion.Hub) error { // nolint
dst.Spec.ShieldedInstanceConfig = restored.Spec.ShieldedInstanceConfig
}

if restored.Spec.OnHostMaintenance != nil {
dst.Spec.OnHostMaintenance = restored.Spec.OnHostMaintenance
}

if restored.Spec.ConfidentialCompute != nil {
dst.Spec.ConfidentialCompute = restored.Spec.ConfidentialCompute
}

return nil
}

Expand Down
7 changes: 7 additions & 0 deletions api/v1alpha4/gcpmachinetemplate_conversion.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,13 @@ func (src *GCPMachineTemplate) ConvertTo(dstRaw conversion.Hub) error { // nolin
if restored.Spec.Template.Spec.ShieldedInstanceConfig != nil {
dst.Spec.Template.Spec.ShieldedInstanceConfig = restored.Spec.Template.Spec.ShieldedInstanceConfig
}
if restored.Spec.Template.Spec.OnHostMaintenance != nil {
dst.Spec.Template.Spec.OnHostMaintenance = restored.Spec.Template.Spec.OnHostMaintenance
}

if restored.Spec.Template.Spec.ConfidentialCompute != nil {
dst.Spec.Template.Spec.ConfidentialCompute = restored.Spec.Template.Spec.ConfidentialCompute
}

return nil
}
Expand Down
2 changes: 2 additions & 0 deletions api/v1alpha4/zz_generated.conversion.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

37 changes: 37 additions & 0 deletions api/v1beta1/gcpmachine_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,30 @@ type GCPShieldedInstanceConfig struct {
IntegrityMonitoring IntegrityMonitoringPolicy `json:"integrityMonitoring,omitempty"`
}

// ConfidentialComputePolicy represents the confidential compute configuration for the GCP machine.
type ConfidentialComputePolicy string

const (
// ConfidentialComputePolicyEnabled enables confidential compute for the GCP machine.
ConfidentialComputePolicyEnabled ConfidentialComputePolicy = "Enabled"
// ConfidentialComputePolicyDisabled disables confidential compute for the GCP machine.
ConfidentialComputePolicyDisabled ConfidentialComputePolicy = "Disabled"
)

// Confidential VM supports Compute Engine machine types in the following series:
// reference: https://cloud.google.com/compute/confidential-vm/docs/os-and-machine-type#machine-type
var confidentialComputeSupportedMachineSeries = []string{"n2d", "c2d"}

// HostMaintenancePolicy represents the desired behavior ase of a host maintenance event.
type HostMaintenancePolicy string

const (
// HostMaintenancePolicyMigrate causes Compute Engine to live migrate an instance when there is a maintenance event.
HostMaintenancePolicyMigrate HostMaintenancePolicy = "Migrate"
// HostMaintenancePolicyTerminate - stops an instance instead of migrating it.
HostMaintenancePolicyTerminate HostMaintenancePolicy = "Terminate"
)

// GCPMachineSpec defines the desired state of GCPMachine.
type GCPMachineSpec struct {
// InstanceType is the type of instance to create. Example: n1.standard-2
Expand Down Expand Up @@ -209,6 +233,19 @@ type GCPMachineSpec struct {
// ShieldedInstanceConfig is the Shielded VM configuration for this machine
// +optional
ShieldedInstanceConfig *GCPShieldedInstanceConfig `json:"shieldedInstanceConfig,omitempty"`

// OnHostMaintenance determines the behavior when a maintenance event occurs that might cause the instance to reboot.
// If omitted, the platform chooses a default, which is subject to change over time, currently that default is "Migrate".
// +kubebuilder:validation:Enum=Migrate;Terminate;
// +optional
OnHostMaintenance *HostMaintenancePolicy `json:"onHostMaintenance,omitempty"`

// ConfidentialCompute Defines whether the instance should have confidential compute enabled.
// If enabled OnHostMaintenance is required to be set to "Terminate".
// If omitted, the platform chooses a default, which is subject to change over time, currently that default is false.
// +kubebuilder:validation:Enum=Enabled;Disabled
// +optional
ConfidentialCompute *ConfidentialComputePolicy `json:"confidentialCompute,omitempty"`
}

// MetadataItem defines a single piece of metadata associated with an instance.
Expand Down
21 changes: 19 additions & 2 deletions api/v1beta1/gcpmachine_webhook.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,11 @@ limitations under the License.
package v1beta1

import (
"fmt"
"reflect"
"strings"

"k8s.io/utils/strings/slices"

"github.com/pkg/errors"
apierrors "k8s.io/apimachinery/pkg/api/errors"
Expand Down Expand Up @@ -45,8 +49,7 @@ var _ webhook.Validator = &GCPMachine{}
// ValidateCreate implements webhook.Validator so a webhook will be registered for the type.
func (m *GCPMachine) ValidateCreate() error {
clusterlog.Info("validate create", "name", m.Name)

return nil
return validateConfidentialCompute(m.Spec)
}

// ValidateUpdate implements webhook.Validator so a webhook will be registered for the type.
Expand Down Expand Up @@ -99,3 +102,17 @@ func (m *GCPMachine) ValidateDelete() error {
func (m *GCPMachine) Default() {
clusterlog.Info("default", "name", m.Name)
}

func validateConfidentialCompute(spec GCPMachineSpec) error {
if spec.ConfidentialCompute != nil && *spec.ConfidentialCompute == ConfidentialComputePolicyEnabled {
if spec.OnHostMaintenance == nil || *spec.OnHostMaintenance == HostMaintenancePolicyMigrate {
return fmt.Errorf("ConfidentialCompute require OnHostMaintenance to be set to %s, the current value is: %s", HostMaintenancePolicyTerminate, HostMaintenancePolicyMigrate)
}

machineSeries := strings.Split(spec.InstanceType, "-")[0]
if !slices.Contains(confidentialComputeSupportedMachineSeries, machineSeries) {
return fmt.Errorf("ConfidentialCompute require instance type in the following series: %s", confidentialComputeSupportedMachineSeries)
}
}
return nil
}
101 changes: 101 additions & 0 deletions api/v1beta1/gcpmachine_webhook_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
/*
Copyright 2023 The Kubernetes 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 v1beta1

import (
"testing"

. "github.com/onsi/gomega"
)

func TestGCPMachine_ValidateCreate(t *testing.T) {
g := NewWithT(t)
confidentialComputeEnabled := ConfidentialComputePolicyEnabled
onHostMaintenanceTerminate := HostMaintenancePolicyTerminate
onHostMaintenanceMigrate := HostMaintenancePolicyMigrate
tests := []struct {
name string
*GCPMachine
wantErr bool
}{
{
name: "GCPMachined with OnHostMaintenance set to Terminate - valid",
GCPMachine: &GCPMachine{
Spec: GCPMachineSpec{
InstanceType: "n2d-standard-4",
OnHostMaintenance: &onHostMaintenanceTerminate,
},
},
wantErr: false,
},
{
name: "GCPMachined with ConfidentialCompute enabled and OnHostMaintenance set to Terminate - valid",
GCPMachine: &GCPMachine{
Spec: GCPMachineSpec{
InstanceType: "n2d-standard-4",
OnHostMaintenance: &onHostMaintenanceTerminate,
ConfidentialCompute: &confidentialComputeEnabled,
},
},
wantErr: false,
},
{
name: "GCPMachined with ConfidentialCompute enabled and OnHostMaintenance set to Migrate - invalid",
GCPMachine: &GCPMachine{
Spec: GCPMachineSpec{
InstanceType: "n2d-standard-4",
OnHostMaintenance: &onHostMaintenanceMigrate,
ConfidentialCompute: &confidentialComputeEnabled,
},
},
wantErr: true,
},
{
name: "GCPMachined with ConfidentialCompute enabled and default OnHostMaintenance (Migrate) - invalid",
GCPMachine: &GCPMachine{
Spec: GCPMachineSpec{
InstanceType: "n2d-standard-4",
ConfidentialCompute: &confidentialComputeEnabled,
},
},
wantErr: true,
},
{
name: "GCPMachined with ConfidentialCompute enabled and unsupported instance type - invalid",
GCPMachine: &GCPMachine{
Spec: GCPMachineSpec{
InstanceType: "e2-standard-4",
ConfidentialCompute: &confidentialComputeEnabled,
OnHostMaintenance: &onHostMaintenanceTerminate,
},
},
wantErr: true,
},
}
for _, test := range tests {
test := test
t.Run(test.name, func(t *testing.T) {
t.Parallel()
err := test.GCPMachine.ValidateCreate()
if test.wantErr {
g.Expect(err).To(HaveOccurred())
} else {
g.Expect(err).NotTo(HaveOccurred())
}
})
}
}
2 changes: 1 addition & 1 deletion api/v1beta1/gcpmachinetemplate_webhook.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ var _ webhook.Validator = &GCPMachineTemplate{}
func (r *GCPMachineTemplate) ValidateCreate() error {
clusterlog.Info("validate create", "name", r.Name)

return nil
return validateConfidentialCompute(r.Spec.Template.Spec)
}

// ValidateUpdate implements webhook.Validator so a webhook will be registered for the type.
Expand Down
116 changes: 116 additions & 0 deletions api/v1beta1/gcpmachinetemplate_webhook_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
/*
Copyright 2023 The Kubernetes 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 v1beta1

import (
"testing"

. "github.com/onsi/gomega"
)

func TestGCPMachineTemplate_ValidateCreate(t *testing.T) {
g := NewWithT(t)
confidentialComputeEnabled := ConfidentialComputePolicyEnabled
onHostMaintenanceTerminate := HostMaintenancePolicyTerminate
onHostMaintenanceMigrate := HostMaintenancePolicyMigrate
tests := []struct {
name string
template *GCPMachineTemplate
wantErr bool
}{
{
name: "GCPMachineTemplate with OnHostMaintenance set to Terminate - valid",
template: &GCPMachineTemplate{
Spec: GCPMachineTemplateSpec{
Template: GCPMachineTemplateResource{
Spec: GCPMachineSpec{
InstanceType: "n2d-standard-4",
OnHostMaintenance: &onHostMaintenanceTerminate,
}},
},
},
wantErr: false,
},
{
name: "GCPMachineTemplate with ConfidentialCompute enabled and OnHostMaintenance set to Terminate - valid",
template: &GCPMachineTemplate{
Spec: GCPMachineTemplateSpec{
Template: GCPMachineTemplateResource{
Spec: GCPMachineSpec{
InstanceType: "n2d-standard-4",
ConfidentialCompute: &confidentialComputeEnabled,
OnHostMaintenance: &onHostMaintenanceTerminate,
}},
},
},
wantErr: false,
},
{
name: "GCPMachineTemplate with ConfidentialCompute enabled and OnHostMaintenance set to Migrate - invalid",
template: &GCPMachineTemplate{
Spec: GCPMachineTemplateSpec{
Template: GCPMachineTemplateResource{
Spec: GCPMachineSpec{
InstanceType: "n2d-standard-4",
ConfidentialCompute: &confidentialComputeEnabled,
OnHostMaintenance: &onHostMaintenanceMigrate,
}},
},
},
wantErr: true,
},
{
name: "GCPMachineTemplate with ConfidentialCompute enabled and default OnHostMaintenance (Migrate) - invalid",
template: &GCPMachineTemplate{
Spec: GCPMachineTemplateSpec{
Template: GCPMachineTemplateResource{
Spec: GCPMachineSpec{
InstanceType: "n2d-standard-4",
ConfidentialCompute: &confidentialComputeEnabled,
}},
},
},
wantErr: true,
},
{
name: "GCPMachineTemplate with ConfidentialCompute enabled and unsupported instance type - invalid",
template: &GCPMachineTemplate{
Spec: GCPMachineTemplateSpec{
Template: GCPMachineTemplateResource{
Spec: GCPMachineSpec{
InstanceType: "e2-standard-4",
ConfidentialCompute: &confidentialComputeEnabled,
OnHostMaintenance: &onHostMaintenanceTerminate,
}},
},
},
wantErr: true,
},
}
for _, test := range tests {
test := test
t.Run(test.name, func(t *testing.T) {
t.Parallel()
err := test.template.ValidateCreate()
if test.wantErr {
g.Expect(err).To(HaveOccurred())
} else {
g.Expect(err).NotTo(HaveOccurred())
}
})
}
}
Loading

0 comments on commit c37a092

Please sign in to comment.