Skip to content
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
9 changes: 9 additions & 0 deletions cmd/log/log.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package log

import "github.com/openshift/hypershift/cmd/util"

var log = util.Log

func Error(err error, msg string, keysAndValues ...interface{}) {
log.Error(err, msg, keysAndValues)
}
111 changes: 111 additions & 0 deletions cmd/nodepool/aws/create.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
package aws
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please update the docs getting starting guide to reflect this changes

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated the docs (added aws option)


import (
"context"
"fmt"
"os"
"os/signal"
"syscall"

hyperv1 "github.com/openshift/hypershift/api/v1alpha1"
"github.com/openshift/hypershift/cmd/log"
"github.com/openshift/hypershift/cmd/nodepool/core"
"github.com/spf13/cobra"
"k8s.io/apimachinery/pkg/types"
crclient "sigs.k8s.io/controller-runtime/pkg/client"
)

type AWSPlatformCreateOptions struct {
InstanceProfile string
SubnetID string
SecurityGroupID string
InstanceType string
RootVolumeType string
RootVolumeIOPS int64
RootVolumeSize int64
}

func NewCreateCommand(coreOpts core.CreateNodePoolOptions) *cobra.Command {
platformOpts := AWSPlatformCreateOptions{
InstanceType: "m5.large",
RootVolumeType: "gp3",
RootVolumeSize: 120,
RootVolumeIOPS: 0,
}
cmd := &cobra.Command{
Use: "aws",
Short: "Creates basic functional NodePool resources for AWS platform",
SilenceUsage: true,
}

cmd.Flags().StringVar(&platformOpts.InstanceType, "instance-type", platformOpts.InstanceType, "The AWS instance type of the NodePool")
cmd.Flags().StringVar(&platformOpts.SubnetID, "subnet-id", platformOpts.SubnetID, "The AWS subnet ID in which to create the NodePool")
cmd.Flags().StringVar(&platformOpts.SecurityGroupID, "securitygroup-id", platformOpts.SecurityGroupID, "The AWS security group in which to create the NodePool")
cmd.Flags().StringVar(&platformOpts.InstanceProfile, "instance-profile", platformOpts.InstanceProfile, "The AWS instance profile for the NodePool")
cmd.Flags().StringVar(&platformOpts.RootVolumeType, "root-volume-type", platformOpts.RootVolumeType, "The type of the root volume (e.g. gp3, io2) for machines in the NodePool")
cmd.Flags().Int64Var(&platformOpts.RootVolumeIOPS, "root-volume-iops", platformOpts.RootVolumeIOPS, "The iops of the root volume for machines in the NodePool")
cmd.Flags().Int64Var(&platformOpts.RootVolumeSize, "root-volume-size", platformOpts.RootVolumeSize, "The size of the root volume (min: 8) for machines in the NodePool")

cmd.Run = func(cmd *cobra.Command, args []string) {
ctx, cancel := context.WithCancel(context.Background())
sigs := make(chan os.Signal, 1)
signal.Notify(sigs, syscall.SIGINT)
go func() {
<-sigs
cancel()
}()

if err := coreOpts.CreateNodePool(ctx, platformOpts); err != nil {
log.Error(err, "Failed to create nodepool")
os.Exit(1)
}
}

return cmd
}

func (o AWSPlatformCreateOptions) UpdateNodePool(ctx context.Context, nodePool *hyperv1.NodePool, hcluster *hyperv1.HostedCluster, client crclient.Client) error {
if len(o.InstanceProfile) == 0 {
o.InstanceProfile = fmt.Sprintf("%s-worker", hcluster.Spec.InfraID)
}
if len(o.SubnetID) == 0 {
if hcluster.Spec.Platform.AWS.CloudProviderConfig.Subnet.ID != nil {
o.SubnetID = *hcluster.Spec.Platform.AWS.CloudProviderConfig.Subnet.ID
} else {
return fmt.Errorf("subnet ID was not specified and cannot be determined from HostedCluster")
}
}
if len(o.SecurityGroupID) == 0 {
defaultNodePool := &hyperv1.NodePool{}
if err := client.Get(ctx, types.NamespacedName{Namespace: hcluster.Namespace, Name: hcluster.Name}, defaultNodePool); err != nil {
return fmt.Errorf("security group ID was not specified and cannot be determined from default nodepool: %v", err)
}
if defaultNodePool.Spec.Platform.AWS == nil || len(defaultNodePool.Spec.Platform.AWS.SecurityGroups) == 0 ||
defaultNodePool.Spec.Platform.AWS.SecurityGroups[0].ID == nil {
return fmt.Errorf("security group ID was not specified and cannot be determined from default nodepool")
}
o.SecurityGroupID = *defaultNodePool.Spec.Platform.AWS.SecurityGroups[0].ID
}
nodePool.Spec.Platform.AWS = &hyperv1.AWSNodePoolPlatform{
InstanceType: o.InstanceType,
InstanceProfile: o.InstanceProfile,
Subnet: &hyperv1.AWSResourceReference{
ID: &o.SubnetID,
},
SecurityGroups: []hyperv1.AWSResourceReference{
{
ID: &o.SecurityGroupID,
},
},
RootVolume: &hyperv1.Volume{
Type: o.RootVolumeType,
Size: o.RootVolumeSize,
IOPS: o.RootVolumeIOPS,
},
}
return nil
}

func (o AWSPlatformCreateOptions) Type() hyperv1.PlatformType {
return hyperv1.AWSPlatform
}
102 changes: 102 additions & 0 deletions cmd/nodepool/core/create.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
package core

import (
"context"
"fmt"
"os"

hyperv1 "github.com/openshift/hypershift/api/v1alpha1"
"github.com/openshift/hypershift/cmd/util"
hyperapi "github.com/openshift/hypershift/support/api"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
crclient "sigs.k8s.io/controller-runtime/pkg/client"
)

type CreateNodePoolOptions struct {
Name string
Namespace string
ClusterName string
NodeCount int32
ReleaseImage string
Render bool
}

type PlatformOptions interface {
// UpdateNodePool is used to update the platform specific values in the NodePool
UpdateNodePool(ctx context.Context, nodePool *hyperv1.NodePool, hcluster *hyperv1.HostedCluster, client crclient.Client) error
// Type returns the platform type
Type() hyperv1.PlatformType
}

func (o *CreateNodePoolOptions) CreateNodePool(ctx context.Context, platformOpts PlatformOptions) error {
client := util.GetClientOrDie()

hcluster := &hyperv1.HostedCluster{}
err := client.Get(ctx, types.NamespacedName{Namespace: o.Namespace, Name: o.ClusterName}, hcluster)
if err != nil {
return fmt.Errorf("failed to get HostedCluster %s/%s: %w", o.Namespace, o.Name, err)
}

if platformOpts.Type() != hcluster.Spec.Platform.Type {
return fmt.Errorf("NodePool platform type %s must be HostedCluster type %s", platformOpts.Type(), hcluster.Spec.Platform.Type)
}

nodePool := &hyperv1.NodePool{}
err = client.Get(ctx, types.NamespacedName{Namespace: o.Namespace, Name: o.Name}, nodePool)
if err == nil && !o.Render {
return fmt.Errorf("NodePool %s/%s already exists", o.Namespace, o.Name)
}

var releaseImage string
if len(o.ReleaseImage) > 0 {
releaseImage = o.ReleaseImage
} else {
releaseImage = hcluster.Spec.Release.Image
}

nodePool = &hyperv1.NodePool{
TypeMeta: metav1.TypeMeta{
Kind: "NodePool",
APIVersion: hyperv1.GroupVersion.String(),
},
ObjectMeta: metav1.ObjectMeta{
Namespace: o.Namespace,
Name: o.Name,
},
Spec: hyperv1.NodePoolSpec{
Management: hyperv1.NodePoolManagement{
UpgradeType: hyperv1.UpgradeTypeReplace,
},
ClusterName: o.ClusterName,
NodeCount: &o.NodeCount,
Release: hyperv1.Release{
Image: releaseImage,
},
Platform: hyperv1.NodePoolPlatform{
Type: hcluster.Spec.Platform.Type,
},
},
}

if err := platformOpts.UpdateNodePool(ctx, nodePool, hcluster, client); err != nil {
return err
}

if o.Render {
err := hyperapi.YamlSerializer.Encode(nodePool, os.Stdout)
if err != nil {
panic(err)
}
fmt.Printf("NodePool %s was rendered to yaml output file\n", o.Name)
return nil
}

err = client.Create(ctx, nodePool)
if err != nil {
return err
}

fmt.Printf("NodePool %s created\n", o.Name)
return nil
}
Loading