mirror of
https://github.com/edgelesssys/constellation.git
synced 2024-12-24 15:09:39 -05:00
add coordinator count to cli
This commit is contained in:
parent
dbfbdfe3cd
commit
8b7bafb482
@ -15,7 +15,7 @@ func (c *Client) CreateInstances(ctx context.Context, input CreateInstancesInput
|
||||
createNodesInput := CreateScaleSetInput{
|
||||
Name: "constellation-scale-set-nodes-" + c.uid,
|
||||
NamePrefix: c.name + "-worker-" + c.uid + "-",
|
||||
Count: input.Count - 1,
|
||||
Count: input.CountNodes,
|
||||
InstanceType: input.InstanceType,
|
||||
StateDiskSizeGB: int32(input.StateDiskSizeGB),
|
||||
Image: input.Image,
|
||||
@ -32,7 +32,7 @@ func (c *Client) CreateInstances(ctx context.Context, input CreateInstancesInput
|
||||
createCoordinatorsInput := CreateScaleSetInput{
|
||||
Name: "constellation-scale-set-coordinators-" + c.uid,
|
||||
NamePrefix: c.name + "-control-plane-" + c.uid + "-",
|
||||
Count: 1,
|
||||
Count: input.CountCoordinators,
|
||||
InstanceType: input.InstanceType,
|
||||
StateDiskSizeGB: int32(input.StateDiskSizeGB),
|
||||
Image: input.Image,
|
||||
@ -63,7 +63,8 @@ func (c *Client) CreateInstances(ctx context.Context, input CreateInstancesInput
|
||||
|
||||
// CreateInstancesInput is the input for a CreateInstances operation.
|
||||
type CreateInstancesInput struct {
|
||||
Count int
|
||||
CountNodes int
|
||||
CountCoordinators int
|
||||
InstanceType string
|
||||
StateDiskSizeGB int
|
||||
Image string
|
||||
@ -78,23 +79,25 @@ func (c *Client) CreateInstancesVMs(ctx context.Context, input CreateInstancesIn
|
||||
return err
|
||||
}
|
||||
|
||||
vm := azure.VMInstance{
|
||||
Name: c.name + "-control-plane-" + c.uid,
|
||||
Username: "constell",
|
||||
Password: pw,
|
||||
Location: c.location,
|
||||
InstanceType: input.InstanceType,
|
||||
Image: input.Image,
|
||||
}
|
||||
instance, err := c.createInstanceVM(ctx, vm)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
c.coordinators = azure.Instances{"0": instance}
|
||||
|
||||
for i := 0; i < input.Count-1; i++ {
|
||||
for i := 0; i < input.CountCoordinators; i++ {
|
||||
vm := azure.VMInstance{
|
||||
Name: c.name + "-node-" + strconv.Itoa(i) + c.uid,
|
||||
Name: c.name + "-control-plane-" + c.uid + "-" + strconv.Itoa(i),
|
||||
Username: "constell",
|
||||
Password: pw,
|
||||
Location: c.location,
|
||||
InstanceType: input.InstanceType,
|
||||
Image: input.Image,
|
||||
}
|
||||
instance, err := c.createInstanceVM(ctx, vm)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
c.coordinators[strconv.Itoa(i)] = instance
|
||||
}
|
||||
|
||||
for i := 0; i < input.CountNodes; i++ {
|
||||
vm := azure.VMInstance{
|
||||
Name: c.name + "-node-" + c.uid + "-" + strconv.Itoa(i),
|
||||
Username: "constell",
|
||||
Password: pw,
|
||||
Location: c.location,
|
||||
|
@ -146,7 +146,8 @@ func TestCreateInstances(t *testing.T) {
|
||||
resourceGroupAPI: newSuccessfulResourceGroupStub(),
|
||||
roleAssignmentsAPI: &stubRoleAssignmentsAPI{},
|
||||
createInstancesInput: CreateInstancesInput{
|
||||
Count: 3,
|
||||
CountCoordinators: 3,
|
||||
CountNodes: 3,
|
||||
InstanceType: "type",
|
||||
Image: "image",
|
||||
UserAssingedIdentity: "identity",
|
||||
@ -159,7 +160,8 @@ func TestCreateInstances(t *testing.T) {
|
||||
resourceGroupAPI: newSuccessfulResourceGroupStub(),
|
||||
roleAssignmentsAPI: &stubRoleAssignmentsAPI{},
|
||||
createInstancesInput: CreateInstancesInput{
|
||||
Count: 3,
|
||||
CountCoordinators: 3,
|
||||
CountNodes: 3,
|
||||
InstanceType: "type",
|
||||
Image: "image",
|
||||
UserAssingedIdentity: "identity",
|
||||
@ -173,7 +175,8 @@ func TestCreateInstances(t *testing.T) {
|
||||
resourceGroupAPI: newSuccessfulResourceGroupStub(),
|
||||
roleAssignmentsAPI: &stubRoleAssignmentsAPI{},
|
||||
createInstancesInput: CreateInstancesInput{
|
||||
Count: 3,
|
||||
CountCoordinators: 3,
|
||||
CountNodes: 3,
|
||||
InstanceType: "type",
|
||||
Image: "image",
|
||||
UserAssingedIdentity: "identity",
|
||||
@ -187,7 +190,7 @@ func TestCreateInstances(t *testing.T) {
|
||||
resourceGroupAPI: newSuccessfulResourceGroupStub(),
|
||||
roleAssignmentsAPI: &stubRoleAssignmentsAPI{},
|
||||
createInstancesInput: CreateInstancesInput{
|
||||
Count: 3,
|
||||
CountNodes: 3,
|
||||
InstanceType: "type",
|
||||
Image: "image",
|
||||
UserAssingedIdentity: "identity",
|
||||
@ -219,8 +222,8 @@ func TestCreateInstances(t *testing.T) {
|
||||
assert.Error(client.CreateInstances(ctx, tc.createInstancesInput))
|
||||
} else {
|
||||
assert.NoError(client.CreateInstances(ctx, tc.createInstancesInput))
|
||||
assert.Equal(1, len(client.coordinators))
|
||||
assert.Equal(tc.createInstancesInput.Count-1, len(client.nodes))
|
||||
assert.Equal(tc.createInstancesInput.CountCoordinators, len(client.coordinators))
|
||||
assert.Equal(tc.createInstancesInput.CountNodes, len(client.nodes))
|
||||
assert.NotEmpty(client.nodes["0"].PrivateIP)
|
||||
assert.NotEmpty(client.nodes["0"].PublicIP)
|
||||
assert.NotEmpty(client.coordinators["0"].PrivateIP)
|
||||
@ -257,9 +260,10 @@ func TestCreateInstancesVMs(t *testing.T) {
|
||||
resourceGroupAPI: newSuccessfulResourceGroupStub(),
|
||||
roleAssignmentsAPI: &stubRoleAssignmentsAPI{},
|
||||
createInstancesInput: CreateInstancesInput{
|
||||
Count: 3,
|
||||
InstanceType: "type",
|
||||
Image: "image",
|
||||
CountCoordinators: 3,
|
||||
CountNodes: 3,
|
||||
InstanceType: "type",
|
||||
Image: "image",
|
||||
},
|
||||
},
|
||||
"error when creating scale set": {
|
||||
@ -269,9 +273,10 @@ func TestCreateInstancesVMs(t *testing.T) {
|
||||
resourceGroupAPI: newSuccessfulResourceGroupStub(),
|
||||
roleAssignmentsAPI: &stubRoleAssignmentsAPI{},
|
||||
createInstancesInput: CreateInstancesInput{
|
||||
Count: 3,
|
||||
InstanceType: "type",
|
||||
Image: "image",
|
||||
CountCoordinators: 3,
|
||||
CountNodes: 3,
|
||||
InstanceType: "type",
|
||||
Image: "image",
|
||||
},
|
||||
errExpected: true,
|
||||
},
|
||||
@ -282,9 +287,10 @@ func TestCreateInstancesVMs(t *testing.T) {
|
||||
resourceGroupAPI: newSuccessfulResourceGroupStub(),
|
||||
roleAssignmentsAPI: &stubRoleAssignmentsAPI{},
|
||||
createInstancesInput: CreateInstancesInput{
|
||||
Count: 3,
|
||||
InstanceType: "type",
|
||||
Image: "image",
|
||||
CountCoordinators: 3,
|
||||
CountNodes: 3,
|
||||
InstanceType: "type",
|
||||
Image: "image",
|
||||
},
|
||||
errExpected: true,
|
||||
},
|
||||
@ -295,9 +301,10 @@ func TestCreateInstancesVMs(t *testing.T) {
|
||||
resourceGroupAPI: newSuccessfulResourceGroupStub(),
|
||||
roleAssignmentsAPI: &stubRoleAssignmentsAPI{},
|
||||
createInstancesInput: CreateInstancesInput{
|
||||
Count: 3,
|
||||
InstanceType: "type",
|
||||
Image: "image",
|
||||
CountCoordinators: 3,
|
||||
CountNodes: 3,
|
||||
InstanceType: "type",
|
||||
Image: "image",
|
||||
},
|
||||
errExpected: true,
|
||||
},
|
||||
@ -308,9 +315,10 @@ func TestCreateInstancesVMs(t *testing.T) {
|
||||
resourceGroupAPI: newSuccessfulResourceGroupStub(),
|
||||
roleAssignmentsAPI: &stubRoleAssignmentsAPI{},
|
||||
createInstancesInput: CreateInstancesInput{
|
||||
Count: 3,
|
||||
InstanceType: "type",
|
||||
Image: "image",
|
||||
CountCoordinators: 3,
|
||||
CountNodes: 3,
|
||||
InstanceType: "type",
|
||||
Image: "image",
|
||||
},
|
||||
errExpected: true,
|
||||
},
|
||||
@ -321,9 +329,10 @@ func TestCreateInstancesVMs(t *testing.T) {
|
||||
resourceGroupAPI: newSuccessfulResourceGroupStub(),
|
||||
roleAssignmentsAPI: &stubRoleAssignmentsAPI{},
|
||||
createInstancesInput: CreateInstancesInput{
|
||||
Count: 3,
|
||||
InstanceType: "type",
|
||||
Image: "image",
|
||||
CountCoordinators: 3,
|
||||
CountNodes: 3,
|
||||
InstanceType: "type",
|
||||
Image: "image",
|
||||
},
|
||||
errExpected: true,
|
||||
},
|
||||
@ -355,8 +364,8 @@ func TestCreateInstancesVMs(t *testing.T) {
|
||||
}
|
||||
|
||||
require.NoError(client.CreateInstancesVMs(ctx, tc.createInstancesInput))
|
||||
assert.Equal(1, len(client.coordinators))
|
||||
assert.Equal(tc.createInstancesInput.Count-1, len(client.nodes))
|
||||
assert.Equal(tc.createInstancesInput.CountCoordinators, len(client.coordinators))
|
||||
assert.Equal(tc.createInstancesInput.CountNodes, len(client.nodes))
|
||||
assert.NotEmpty(client.nodes["0"].PrivateIP)
|
||||
assert.NotEmpty(client.nodes["0"].PublicIP)
|
||||
assert.NotEmpty(client.coordinators["0"].PrivateIP)
|
||||
|
@ -83,24 +83,30 @@ func (c *fakeAzureClient) CreateInstances(ctx context.Context, input client.Crea
|
||||
c.coordinatorsScaleSet = "coordinators-scale-set"
|
||||
c.nodesScaleSet = "nodes-scale-set"
|
||||
c.nodes = make(azure.Instances)
|
||||
for i := 0; i < input.Count-1; i++ {
|
||||
for i := 0; i < input.CountNodes; i++ {
|
||||
id := strconv.Itoa(i)
|
||||
c.nodes[id] = azure.Instance{PublicIP: "192.0.2.1", PrivateIP: "192.0.2.1"}
|
||||
}
|
||||
c.coordinators = make(azure.Instances)
|
||||
c.coordinators["0"] = azure.Instance{PublicIP: "192.0.2.1", PrivateIP: "192.0.2.1"}
|
||||
for i := 0; i < input.CountCoordinators; i++ {
|
||||
id := strconv.Itoa(i)
|
||||
c.coordinators[id] = azure.Instance{PublicIP: "192.0.2.1", PrivateIP: "192.0.2.1"}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// TODO: deprecate as soon as scale sets are available.
|
||||
func (c *fakeAzureClient) CreateInstancesVMs(ctx context.Context, input client.CreateInstancesInput) error {
|
||||
c.nodes = make(azure.Instances)
|
||||
for i := 0; i < input.Count-1; i++ {
|
||||
for i := 0; i < input.CountNodes; i++ {
|
||||
id := strconv.Itoa(i)
|
||||
c.nodes[id] = azure.Instance{PublicIP: "192.0.2.1", PrivateIP: "192.0.2.1"}
|
||||
}
|
||||
c.coordinators = make(azure.Instances)
|
||||
c.coordinators["0"] = azure.Instance{PublicIP: "192.0.2.1", PrivateIP: "192.0.2.1"}
|
||||
for i := 0; i < input.CountCoordinators; i++ {
|
||||
id := strconv.Itoa(i)
|
||||
c.coordinators[id] = azure.Instance{PublicIP: "192.0.2.1", PrivateIP: "192.0.2.1"}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -17,14 +17,15 @@ import (
|
||||
|
||||
func newCreateAWSCmd() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "aws NUMBER SIZE",
|
||||
Short: "Create a Constellation of NUMBER nodes of SIZE on AWS.",
|
||||
Long: "Create a Constellation of NUMBER nodes of SIZE on AWS.",
|
||||
Example: "aws 4 2xlarge",
|
||||
Use: "aws C_COUNT N_COUNT TYPE",
|
||||
Short: "Create a Constellation of C_COUNT coordinators and N_COUNT nodes of TYPE on AWS.",
|
||||
Long: "Create a Constellation of C_COUNT coordinators and N_COUNT nodes of TYPE on AWS.",
|
||||
Example: "aws 1 4 2xlarge",
|
||||
Args: cobra.MatchAll(
|
||||
cobra.ExactArgs(2),
|
||||
isIntGreaterArg(0, 1),
|
||||
isEC2InstanceType(1),
|
||||
cobra.ExactArgs(3),
|
||||
isValidAWSCoordinatorCount(0),
|
||||
isIntGreaterArg(1, 1),
|
||||
isEC2InstanceType(2),
|
||||
),
|
||||
ValidArgsFunction: createAWSCompletion,
|
||||
RunE: runCreateAWS,
|
||||
@ -35,7 +36,7 @@ func newCreateAWSCmd() *cobra.Command {
|
||||
// runCreateAWS runs the create command.
|
||||
func runCreateAWS(cmd *cobra.Command, args []string) error {
|
||||
count, _ := strconv.Atoi(args[0]) // err already checked in args validation
|
||||
size := strings.ToLower(args[1])
|
||||
size := strings.ToLower(args[2])
|
||||
|
||||
name, err := cmd.Flags().GetString("name")
|
||||
if err != nil {
|
||||
@ -125,6 +126,8 @@ func createAWSCompletion(cmd *cobra.Command, args []string, toComplete string) (
|
||||
case 0:
|
||||
return []string{}, cobra.ShellCompDirectiveNoFileComp
|
||||
case 1:
|
||||
return []string{}, cobra.ShellCompDirectiveNoFileComp
|
||||
case 2:
|
||||
return []string{
|
||||
"4xlarge",
|
||||
"8xlarge",
|
||||
|
@ -21,21 +21,23 @@ func TestCreateAWSCmdArgumentValidation(t *testing.T) {
|
||||
args []string
|
||||
expectErr bool
|
||||
}{
|
||||
"valid size 4XL": {[]string{"5", "4xlarge"}, false},
|
||||
"valid size 8XL": {[]string{"4", "8xlarge"}, false},
|
||||
"valid size 12XL": {[]string{"3", "12xlarge"}, false},
|
||||
"valid size 16XL": {[]string{"2", "16xlarge"}, false},
|
||||
"valid size 24XL": {[]string{"2", "24xlarge"}, false},
|
||||
"valid short 12XL": {[]string{"4", "12xl"}, false},
|
||||
"valid short 24XL": {[]string{"2", "24xl"}, false},
|
||||
"valid capitalized": {[]string{"3", "24XlARge"}, false},
|
||||
"valid short capitalized": {[]string{"4", "16XL"}, false},
|
||||
"invalid to many arguments": {[]string{"2", "4xl", "2xl"}, true},
|
||||
"invalid to many arguments 2": {[]string{"2", "4xl", "2"}, true},
|
||||
"invalidOnlyOneInstance": {[]string{"1", "4xl"}, true},
|
||||
"invalid first is no int": {[]string{"xl", "4xl"}, true},
|
||||
"invalid second is no size": {[]string{"2", "2"}, true},
|
||||
"invalid wrong order": {[]string{"4xl", "2"}, true},
|
||||
"valid size 4XL": {[]string{"1", "5", "4xlarge"}, false},
|
||||
"valid size 8XL": {[]string{"1", "4", "8xlarge"}, false},
|
||||
"valid size 12XL": {[]string{"1", "3", "12xlarge"}, false},
|
||||
"valid size 16XL": {[]string{"1", "2", "16xlarge"}, false},
|
||||
"valid size 24XL": {[]string{"1", "2", "24xlarge"}, false},
|
||||
"valid short 12XL": {[]string{"1", "4", "12xl"}, false},
|
||||
"valid short 24XL": {[]string{"1", "2", "24xl"}, false},
|
||||
"valid capitalized": {[]string{"1", "3", "24XlARge"}, false},
|
||||
"valid short capitalized": {[]string{"1", "4", "16XL"}, false},
|
||||
"invalid to many arguments": {[]string{"1", "2", "4xl", "2xl"}, true},
|
||||
"invalid to many arguments 2": {[]string{"1", "2", "4xl", "2"}, true},
|
||||
"invalidOnlyOneInstance": {[]string{"1", "1", "4xl"}, true},
|
||||
"invalid first is no int": {[]string{"xl", "2", "4xl"}, true},
|
||||
"invalid first is not 1": {[]string{"2", "2", "4xl"}, true},
|
||||
"invalid second is no int": {[]string{"1", "xl", "4xl"}, true},
|
||||
"invalid third is no size": {[]string{"2", "1", "2"}, true},
|
||||
"invalid wrong order": {[]string{"4xl", "1", "2"}, true},
|
||||
}
|
||||
|
||||
cmd := newCreateAWSCmd()
|
||||
@ -173,7 +175,13 @@ func TestCreateAWSCompletion(t *testing.T) {
|
||||
shellCDExpected: cobra.ShellCompDirectiveNoFileComp,
|
||||
},
|
||||
"second arg": {
|
||||
args: []string{"23"},
|
||||
args: []string{"23"},
|
||||
toComplete: "21",
|
||||
resultExpected: []string{},
|
||||
shellCDExpected: cobra.ShellCompDirectiveNoFileComp,
|
||||
},
|
||||
"third arg": {
|
||||
args: []string{"23", "24"},
|
||||
toComplete: "4xl",
|
||||
resultExpected: []string{
|
||||
"4xlarge",
|
||||
@ -184,8 +192,8 @@ func TestCreateAWSCompletion(t *testing.T) {
|
||||
},
|
||||
shellCDExpected: cobra.ShellCompDirectiveDefault,
|
||||
},
|
||||
"third arg": {
|
||||
args: []string{"23", "4xlarge"},
|
||||
"fourth arg": {
|
||||
args: []string{"23", "24", "4xlarge"},
|
||||
toComplete: "xl",
|
||||
resultExpected: []string{},
|
||||
shellCDExpected: cobra.ShellCompDirectiveError,
|
||||
|
@ -16,13 +16,14 @@ import (
|
||||
|
||||
func newCreateAzureCmd() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "azure",
|
||||
Short: "Create a Constellation of NUMBER nodes of SIZE on Azure.",
|
||||
Long: "Create a Constellation of NUMBER nodes of SIZE on Azure.",
|
||||
Use: "azure C_COUNT N_COUNT TYPE",
|
||||
Short: "Create a Constellation of C_COUNT coordinators and N_COUNT nodes of TYPE on Azure.",
|
||||
Long: "Create a Constellation of C_COUNT coordinators and N_COUNT nodes of TYPE on Azure.",
|
||||
Args: cobra.MatchAll(
|
||||
cobra.ExactArgs(2),
|
||||
isIntGreaterArg(0, 1),
|
||||
isAzureInstanceType(1),
|
||||
cobra.ExactArgs(3),
|
||||
isIntGreaterZeroArg(0),
|
||||
isIntGreaterZeroArg(1),
|
||||
isAzureInstanceType(2),
|
||||
),
|
||||
ValidArgsFunction: createAzureCompletion,
|
||||
RunE: runCreateAzure,
|
||||
@ -32,8 +33,9 @@ func newCreateAzureCmd() *cobra.Command {
|
||||
|
||||
// runCreateAzure runs the create command.
|
||||
func runCreateAzure(cmd *cobra.Command, args []string) error {
|
||||
count, _ := strconv.Atoi(args[0]) // err already checked in args validation
|
||||
size := strings.ToLower(args[1])
|
||||
countNodes, _ := strconv.Atoi(args[0]) // err already checked in args validation
|
||||
countCoordinators, _ := strconv.Atoi(args[1]) // err already checked in args validation
|
||||
size := strings.ToLower(args[2])
|
||||
subscriptionID := "0d202bbb-4fa7-4af8-8125-58c269a05435" // TODO: This will be user input
|
||||
tenantID := "adb650a8-5da3-4b15-b4b0-3daf65ff7626" // TODO: This will be user input
|
||||
location := "North Europe" // TODO: This will be user input
|
||||
@ -65,10 +67,10 @@ func runCreateAzure(cmd *cobra.Command, args []string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
return createAzure(cmd, client, fileHandler, config, size, count)
|
||||
return createAzure(cmd, client, fileHandler, config, size, countCoordinators, countNodes)
|
||||
}
|
||||
|
||||
func createAzure(cmd *cobra.Command, cl azureclient, fileHandler file.Handler, config *config.Config, size string, count int) (retErr error) {
|
||||
func createAzure(cmd *cobra.Command, cl azureclient, fileHandler file.Handler, config *config.Config, size string, countCoordinators, countNodes int) (retErr error) {
|
||||
if err := checkDirClean(fileHandler, config); err != nil {
|
||||
return err
|
||||
}
|
||||
@ -80,7 +82,8 @@ func createAzure(cmd *cobra.Command, cl azureclient, fileHandler file.Handler, c
|
||||
if !ok {
|
||||
// Ask user to confirm action.
|
||||
cmd.Printf("The following Constellation will be created:\n")
|
||||
cmd.Printf("%d nodes of size %s will be created.\n", count, size)
|
||||
cmd.Printf("%d coordinators of size %s will be created.\n", countCoordinators, size)
|
||||
cmd.Printf("%d nodes of size %s will be created.\n", countNodes, size)
|
||||
ok, err := askToConfirm(cmd, "Do you want to create this Constellation?")
|
||||
if err != nil {
|
||||
return err
|
||||
@ -103,7 +106,8 @@ func createAzure(cmd *cobra.Command, cl azureclient, fileHandler file.Handler, c
|
||||
return err
|
||||
}
|
||||
if err := cl.CreateInstances(cmd.Context(), client.CreateInstancesInput{
|
||||
Count: count,
|
||||
CountCoordinators: countCoordinators,
|
||||
CountNodes: countNodes,
|
||||
InstanceType: size,
|
||||
StateDiskSizeGB: *config.StateDiskSizeGB,
|
||||
Image: *config.Provider.Azure.Image,
|
||||
@ -131,6 +135,8 @@ func createAzureCompletion(cmd *cobra.Command, args []string, toComplete string)
|
||||
case 0:
|
||||
return []string{}, cobra.ShellCompDirectiveNoFileComp
|
||||
case 1:
|
||||
return []string{}, cobra.ShellCompDirectiveNoFileComp
|
||||
case 2:
|
||||
return azure.InstanceTypes, cobra.ShellCompDirectiveDefault
|
||||
default:
|
||||
return []string{}, cobra.ShellCompDirectiveError
|
||||
|
@ -21,15 +21,17 @@ func TestCreateAzureCmdArgumentValidation(t *testing.T) {
|
||||
args []string
|
||||
expectErr bool
|
||||
}{
|
||||
"valid create 1": {[]string{"3", "Standard_DC2as_v5"}, false},
|
||||
"valid create 2": {[]string{"7", "Standard_DC4as_v5"}, false},
|
||||
"valid create 3": {[]string{"2", "Standard_DC8as_v5"}, false},
|
||||
"invalid to many arguments": {[]string{"2", "Standard_DC2as_v5", "Standard_DC2as_v5"}, true},
|
||||
"invalid to many arguments 2": {[]string{"2", "Standard_DC2as_v5", "2"}, true},
|
||||
"invalidOnlyOneInstance": {[]string{"1", "Standard_DC2as_v5"}, true},
|
||||
"invalid first is no int": {[]string{"Standard_DC2as_v5", "Standard_DC2as_v5"}, true},
|
||||
"invalid second is no size": {[]string{"2", "2"}, true},
|
||||
"invalid wrong order": {[]string{"Standard_DC2as_v5", "2"}, true},
|
||||
"valid create 1": {[]string{"3", "3", "Standard_DC2as_v5"}, false},
|
||||
"valid create 2": {[]string{"3", "7", "Standard_DC4as_v5"}, false},
|
||||
"valid create 3": {[]string{"1", "2", "Standard_DC8as_v5"}, false},
|
||||
"invalid to many arguments": {[]string{"3", "2", "Standard_DC2as_v5", "Standard_DC2as_v5"}, true},
|
||||
"invalid to many arguments 2": {[]string{"3", "2", "Standard_DC2as_v5", "2"}, true},
|
||||
"invalid no coordinators": {[]string{"0", "1", "Standard_DC2as_v5"}, true},
|
||||
"invalid no nodes": {[]string{"1", "0", "Standard_DC2as_v5"}, true},
|
||||
"invalid first is no int": {[]string{"Standard_DC2as_v5", "1", "Standard_DC2as_v5"}, true},
|
||||
"invalid second is no int": {[]string{"1", "Standard_DC2as_v5", "Standard_DC2as_v5"}, true},
|
||||
"invalid third is no size": {[]string{"2", "2", "2"}, true},
|
||||
"invalid wrong order": {[]string{"Standard_DC2as_v5", "2", "2"}, true},
|
||||
}
|
||||
|
||||
cmd := newCreateAzureCmd()
|
||||
@ -65,6 +67,14 @@ func TestCreateAzure(t *testing.T) {
|
||||
PrivateIP: "192.0.2.1",
|
||||
PublicIP: "192.0.2.1",
|
||||
},
|
||||
"1": {
|
||||
PrivateIP: "192.0.2.1",
|
||||
PublicIP: "192.0.2.1",
|
||||
},
|
||||
"2": {
|
||||
PrivateIP: "192.0.2.1",
|
||||
PublicIP: "192.0.2.1",
|
||||
},
|
||||
},
|
||||
AzureResourceGroup: "resource-group",
|
||||
AzureSubnet: "subnet",
|
||||
@ -148,7 +158,7 @@ func TestCreateAzure(t *testing.T) {
|
||||
require.NoError(fileHandler.WriteJSON(*config.StatePath, *tc.existingState, false))
|
||||
}
|
||||
|
||||
err := createAzure(cmd, tc.client, fileHandler, config, "Standard_D2s_v3", 3)
|
||||
err := createAzure(cmd, tc.client, fileHandler, config, "Standard_D2s_v3", 3, 2)
|
||||
if tc.errExpected {
|
||||
assert.Error(err)
|
||||
if stubClient, ok := tc.client.(*stubAzureClient); ok {
|
||||
@ -181,12 +191,18 @@ func TestCreateAzureCompletion(t *testing.T) {
|
||||
},
|
||||
"second arg": {
|
||||
args: []string{"23"},
|
||||
toComplete: "21",
|
||||
resultExpected: []string{},
|
||||
shellCDExpected: cobra.ShellCompDirectiveNoFileComp,
|
||||
},
|
||||
"third arg": {
|
||||
args: []string{"23", "24"},
|
||||
toComplete: "Standard_D",
|
||||
resultExpected: azure.InstanceTypes,
|
||||
shellCDExpected: cobra.ShellCompDirectiveDefault,
|
||||
},
|
||||
"third arg": {
|
||||
args: []string{"23", "Standard_D2s_v3"},
|
||||
"fourth arg": {
|
||||
args: []string{"23", "24", "Standard_D2s_v3"},
|
||||
toComplete: "Standard_D",
|
||||
resultExpected: []string{},
|
||||
shellCDExpected: cobra.ShellCompDirectiveError,
|
||||
|
@ -16,13 +16,14 @@ import (
|
||||
|
||||
func newCreateGCPCmd() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "gcp",
|
||||
Short: "Create a Constellation of NUMBER nodes of SIZE on Google Cloud Platform.",
|
||||
Long: "Create a Constellation of NUMBER nodes of SIZE on Google Cloud Platform.",
|
||||
Use: "gcp C_COUNT N_COUNT TYPE",
|
||||
Short: "Create a Constellation of C_COUNT coordinators and N_COUNT nodes of TYPE on Google Cloud Platform.",
|
||||
Long: "Create a Constellation of C_COUNT coordinators and N_COUNT nodes of TYPE on Google Cloud Platform.",
|
||||
Args: cobra.MatchAll(
|
||||
cobra.ExactArgs(2),
|
||||
isIntGreaterArg(0, 1),
|
||||
isGCPInstanceType(1),
|
||||
cobra.ExactArgs(3),
|
||||
isIntGreaterZeroArg(0),
|
||||
isIntGreaterZeroArg(1),
|
||||
isGCPInstanceType(2),
|
||||
),
|
||||
ValidArgsFunction: createGCPCompletion,
|
||||
RunE: runCreateGCP,
|
||||
@ -32,8 +33,9 @@ func newCreateGCPCmd() *cobra.Command {
|
||||
|
||||
// runCreateGCP runs the create command.
|
||||
func runCreateGCP(cmd *cobra.Command, args []string) error {
|
||||
count, _ := strconv.Atoi(args[0]) // err already checked in args validation
|
||||
size := strings.ToLower(args[1])
|
||||
countNodes, _ := strconv.Atoi(args[0]) // err already checked in args validation
|
||||
countCoordinators, _ := strconv.Atoi(args[1]) // err already checked in args validation
|
||||
size := strings.ToLower(args[2])
|
||||
project := "constellation-331613" // TODO: This will be user input
|
||||
zone := "europe-west3-b" // TODO: This will be user input
|
||||
region := "europe-west3" // TODO: This will be user input
|
||||
@ -59,21 +61,22 @@ func runCreateGCP(cmd *cobra.Command, args []string) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return createGCP(cmd, client, fileHandler, config, size, count)
|
||||
return createGCP(cmd, client, fileHandler, config, size, countCoordinators, countNodes)
|
||||
}
|
||||
|
||||
func createGCP(cmd *cobra.Command, cl gcpclient, fileHandler file.Handler, config *config.Config, size string, count int) (retErr error) {
|
||||
func createGCP(cmd *cobra.Command, cl gcpclient, fileHandler file.Handler, config *config.Config, size string, countCoordinators, countNodes int) (retErr error) {
|
||||
if err := checkDirClean(fileHandler, config); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
createInput := client.CreateInstancesInput{
|
||||
Count: count,
|
||||
ImageId: *config.Provider.GCP.Image,
|
||||
InstanceType: size,
|
||||
StateDiskSizeGB: *config.StateDiskSizeGB,
|
||||
KubeEnv: gcp.KubeEnv,
|
||||
DisableCVM: *config.Provider.GCP.DisableCVM,
|
||||
CountNodes: countNodes,
|
||||
CountCoordinators: countCoordinators,
|
||||
ImageId: *config.Provider.GCP.Image,
|
||||
InstanceType: size,
|
||||
StateDiskSizeGB: *config.StateDiskSizeGB,
|
||||
KubeEnv: gcp.KubeEnv,
|
||||
DisableCVM: *config.Provider.GCP.DisableCVM,
|
||||
}
|
||||
|
||||
ok, err := cmd.Flags().GetBool("yes")
|
||||
@ -83,7 +86,7 @@ func createGCP(cmd *cobra.Command, cl gcpclient, fileHandler file.Handler, confi
|
||||
if !ok {
|
||||
// Ask user to confirm action.
|
||||
cmd.Printf("The following Constellation will be created:\n")
|
||||
cmd.Printf("%d nodes of size %s will be created.\n", count, size)
|
||||
cmd.Printf("%d coordinators and %d nodes of size %s will be created.\n", countCoordinators, countNodes, size)
|
||||
ok, err := askToConfirm(cmd, "Do you want to create this Constellation?")
|
||||
if err != nil {
|
||||
return err
|
||||
@ -126,6 +129,8 @@ func createGCPCompletion(cmd *cobra.Command, args []string, toComplete string) (
|
||||
case 0:
|
||||
return []string{}, cobra.ShellCompDirectiveNoFileComp
|
||||
case 1:
|
||||
return []string{}, cobra.ShellCompDirectiveNoFileComp
|
||||
case 2:
|
||||
return gcp.InstanceTypes, cobra.ShellCompDirectiveDefault
|
||||
default:
|
||||
return []string{}, cobra.ShellCompDirectiveError
|
||||
|
@ -21,15 +21,17 @@ func TestCreateGCPCmdArgumentValidation(t *testing.T) {
|
||||
args []string
|
||||
expectErr bool
|
||||
}{
|
||||
"valid create 1": {[]string{"3", "n2d-standard-2"}, false},
|
||||
"valid create 2": {[]string{"7", "n2d-standard-16"}, false},
|
||||
"valid create 3": {[]string{"2", "n2d-standard-96"}, false},
|
||||
"invalid to many arguments": {[]string{"2", "n2d-standard-2", "n2d-standard-2"}, true},
|
||||
"invalid to many arguments 2": {[]string{"2", "n2d-standard-2", "2"}, true},
|
||||
"invalidOnlyOneInstance": {[]string{"1", "n2d-standard-2"}, true},
|
||||
"invalid first is no int": {[]string{"n2d-standard-2", "n2d-standard-2"}, true},
|
||||
"invalid second is no size": {[]string{"2", "2"}, true},
|
||||
"invalid wrong order": {[]string{"n2d-standard-2", "2"}, true},
|
||||
"valid create 1": {[]string{"3", "3", "n2d-standard-2"}, false},
|
||||
"valid create 2": {[]string{"3", "7", "n2d-standard-16"}, false},
|
||||
"valid create 3": {[]string{"1", "2", "n2d-standard-96"}, false},
|
||||
"invalid too many arguments": {[]string{"3", "2", "n2d-standard-2", "n2d-standard-2"}, true},
|
||||
"invalid too many arguments 2": {[]string{"3", "2", "n2d-standard-2", "2"}, true},
|
||||
"invalid no coordinators": {[]string{"0", "1", "n2d-standard-2"}, true},
|
||||
"invalid no nodes": {[]string{"1", "0", "n2d-standard-2"}, true},
|
||||
"invalid first is no int": {[]string{"n2d-standard-2", "1", "n2d-standard-2"}, true},
|
||||
"invalid second is no int": {[]string{"3", "n2d-standard-2", "n2d-standard-2"}, true},
|
||||
"invalid third is no size": {[]string{"2", "2", "2"}, true},
|
||||
"invalid wrong order": {[]string{"n2d-standard-2", "2", "2"}, true},
|
||||
}
|
||||
|
||||
cmd := newCreateGCPCmd()
|
||||
@ -61,7 +63,15 @@ func TestCreateGCP(t *testing.T) {
|
||||
},
|
||||
},
|
||||
GCPCoordinators: gcp.Instances{
|
||||
"id-c": {
|
||||
"id-0": {
|
||||
PrivateIP: "192.0.2.1",
|
||||
PublicIP: "192.0.2.1",
|
||||
},
|
||||
"id-1": {
|
||||
PrivateIP: "192.0.2.1",
|
||||
PublicIP: "192.0.2.1",
|
||||
},
|
||||
"id-2": {
|
||||
PrivateIP: "192.0.2.1",
|
||||
PublicIP: "192.0.2.1",
|
||||
},
|
||||
@ -146,7 +156,7 @@ func TestCreateGCP(t *testing.T) {
|
||||
require.NoError(fileHandler.WriteJSON(*config.StatePath, *tc.existingState, false))
|
||||
}
|
||||
|
||||
err := createGCP(cmd, tc.client, fileHandler, config, "n2d-standard-2", 3)
|
||||
err := createGCP(cmd, tc.client, fileHandler, config, "n2d-standard-2", 3, 2)
|
||||
if tc.errExpected {
|
||||
assert.Error(err)
|
||||
if stubClient, ok := tc.client.(*stubGcpClient); ok {
|
||||
@ -181,12 +191,18 @@ func TestCreateGCPCompletion(t *testing.T) {
|
||||
},
|
||||
"second arg": {
|
||||
args: []string{"23"},
|
||||
toComplete: "21",
|
||||
resultExpected: []string{},
|
||||
shellCDExpected: cobra.ShellCompDirectiveNoFileComp,
|
||||
},
|
||||
"third arg": {
|
||||
args: []string{"23", "24"},
|
||||
toComplete: "n2d-stan",
|
||||
resultExpected: gcp.InstanceTypes,
|
||||
shellCDExpected: cobra.ShellCompDirectiveDefault,
|
||||
},
|
||||
"third arg": {
|
||||
args: []string{"23", "n2d-standard-2"},
|
||||
"fourth arg": {
|
||||
args: []string{"23", "24", "n2d-standard-2"},
|
||||
toComplete: "n2d-stan",
|
||||
resultExpected: []string{},
|
||||
shellCDExpected: cobra.ShellCompDirectiveError,
|
||||
|
@ -92,12 +92,15 @@ func (c *fakeGcpClient) CreateInstances(ctx context.Context, input client.Create
|
||||
c.nodeTemplate = "node-template"
|
||||
c.coordinatorTemplate = "coordinator-template"
|
||||
c.nodes = make(gcp.Instances)
|
||||
for i := 0; i < input.Count-1; i++ {
|
||||
id := "id-" + strconv.Itoa(len(c.nodes))
|
||||
for i := 0; i < input.CountNodes; i++ {
|
||||
id := "id-" + strconv.Itoa(i)
|
||||
c.nodes[id] = gcp.Instance{PublicIP: "192.0.2.1", PrivateIP: "192.0.2.1"}
|
||||
}
|
||||
c.coordinators = make(gcp.Instances)
|
||||
c.coordinators["id-c"] = gcp.Instance{PublicIP: "192.0.2.1", PrivateIP: "192.0.2.1"}
|
||||
for i := 0; i < input.CountCoordinators; i++ {
|
||||
id := "id-" + strconv.Itoa(i)
|
||||
c.coordinators[id] = gcp.Instance{PublicIP: "192.0.2.1", PrivateIP: "192.0.2.1"}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -21,7 +21,7 @@ func isIntArg(arg int) cobra.PositionalArgs {
|
||||
}
|
||||
}
|
||||
|
||||
// isIntGreaterArg checks if argument at position arg is and integer and greater i.
|
||||
// isIntGreaterArg checks if argument at position arg is an integer and greater i.
|
||||
func isIntGreaterArg(arg int, i int) cobra.PositionalArgs {
|
||||
return cobra.MatchAll(isIntArg(arg), func(cmd *cobra.Command, args []string) error {
|
||||
if v, _ := strconv.Atoi(args[arg]); v <= i {
|
||||
@ -31,6 +31,16 @@ func isIntGreaterArg(arg int, i int) cobra.PositionalArgs {
|
||||
})
|
||||
}
|
||||
|
||||
// isValidAWSCoordinatorCount checks if argument at position arg is an integer exactly 1.
|
||||
func isValidAWSCoordinatorCount(arg int) cobra.PositionalArgs {
|
||||
return cobra.MatchAll(isIntArg(arg), func(cmd *cobra.Command, args []string) error {
|
||||
if v, _ := strconv.Atoi(args[arg]); v != 1 {
|
||||
return fmt.Errorf("argument %d is %d, that is not a valid coordinator count for AWS, currently the only supported coordinator count is 1", arg, v)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
// isIntGreaterZeroArg checks if argument at position arg is a positive non zero integer.
|
||||
func isIntGreaterZeroArg(arg int) cobra.PositionalArgs {
|
||||
return cobra.MatchAll(isIntGreaterArg(arg, 0))
|
||||
|
@ -72,7 +72,7 @@ func (c *Client) CreateInstances(ctx context.Context, input CreateInstancesInput
|
||||
ops = []Operation{}
|
||||
|
||||
nodeGroupInput := instanceGroupManagerInput{
|
||||
Count: input.Count - 1,
|
||||
Count: input.CountNodes,
|
||||
Name: strings.Join([]string{c.name, "worker", c.uid}, "-"),
|
||||
Template: c.nodeTemplate,
|
||||
UID: c.uid,
|
||||
@ -87,7 +87,7 @@ func (c *Client) CreateInstances(ctx context.Context, input CreateInstancesInput
|
||||
c.nodesInstanceGroup = nodeGroupInput.Name
|
||||
|
||||
coordinatorGroupInput := instanceGroupManagerInput{
|
||||
Count: 1,
|
||||
Count: input.CountCoordinators,
|
||||
Name: strings.Join([]string{c.name, "control-plane", c.uid}, "-"),
|
||||
Template: c.coordinatorTemplate,
|
||||
UID: c.uid,
|
||||
@ -287,12 +287,13 @@ func (i *instanceGroupManagerInput) InsertInstanceGroupManagerRequest() computep
|
||||
|
||||
// CreateInstancesInput is the input for a CreatInstances operation.
|
||||
type CreateInstancesInput struct {
|
||||
Count int
|
||||
ImageId string
|
||||
InstanceType string
|
||||
StateDiskSizeGB int
|
||||
KubeEnv string
|
||||
DisableCVM bool
|
||||
CountNodes int
|
||||
CountCoordinators int
|
||||
ImageId string
|
||||
InstanceType string
|
||||
StateDiskSizeGB int
|
||||
KubeEnv string
|
||||
DisableCVM bool
|
||||
}
|
||||
|
||||
type insertInstanceTemplateInput struct {
|
||||
|
@ -41,10 +41,11 @@ func TestCreateInstances(t *testing.T) {
|
||||
{CurrentAction: proto.String(computepb.ManagedInstance_NONE.String())},
|
||||
}
|
||||
testInput := CreateInstancesInput{
|
||||
Count: 3,
|
||||
ImageId: "img",
|
||||
InstanceType: "n2d-standard-2",
|
||||
KubeEnv: "kube-env",
|
||||
CountCoordinators: 3,
|
||||
CountNodes: 4,
|
||||
ImageId: "img",
|
||||
InstanceType: "n2d-standard-2",
|
||||
KubeEnv: "kube-env",
|
||||
}
|
||||
someErr := errors.New("failed")
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user