Skip to content

Commit

Permalink
Throw error when creationRoleProvider is used in MLC programs (#1121)
Browse files Browse the repository at this point in the history
### Proposed changes

The `creationRoleProvider` option in the nodejs version of this provider
allows passing a Pulumi AWS provider. However, for MLC programs, this
isn't supported since only the JSON serialized provider is passed, not a
fully initialized instance.

A user attempting to use this option will encounter a non-helpful error
message: `Detail="provider.getPackage is not a function")`

This PR updates the provider to determine if the provider is being
passed, and if so, returns a more helpful message on how to configure
the EKS cluster settings.

### Related issues (optional)

Closes: #1113
  • Loading branch information
rquitales committed Apr 12, 2024
1 parent f627afe commit 2c3cb5b
Show file tree
Hide file tree
Showing 7 changed files with 172 additions and 1 deletion.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
150 changes: 150 additions & 0 deletions examples/cluster-go/step2/main.go
@@ -0,0 +1,150 @@
package main

import (
"fmt"
"strings"

"github.com/pulumi/pulumi-aws/sdk/v6/go/aws"
"github.com/pulumi/pulumi-aws/sdk/v6/go/aws/ec2"
"github.com/pulumi/pulumi-eks/sdk/v2/go/eks"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
// Create cluster with default settings
cluster1, err := eks.NewCluster(ctx, "example-cluster-go-1", nil)
if err != nil {
return err
}

// Create cluster with non-default settings
cluster2, err := eks.NewCluster(ctx, "example-cluster-2", &eks.ClusterArgs{
DesiredCapacity: pulumi.IntPtr(2),
MinSize: pulumi.IntPtr(2),
MaxSize: pulumi.IntPtr(2),
EnabledClusterLogTypes: pulumi.StringArray{
pulumi.String("api"),
pulumi.String("audit"),
pulumi.String("authenticator"),
},
})
if err != nil {
return err
}

// Create a cluster that avoids conflicts between default settings and mutually exclusive arguments
// https://github.com/pulumi/pulumi-eks/pull/813
cluster3, err := eks.NewCluster(ctx, "example-cluster-3", &eks.ClusterArgs{
NodeGroupOptions: &eks.ClusterNodeGroupOptionsArgs{
DesiredCapacity: pulumi.IntPtr(2),
MinSize: pulumi.IntPtr(2),
MaxSize: pulumi.IntPtr(2),
},
})
if err != nil {
return err
}

//////////////////////////////////////////////////
/// Create an ipv6 enabled EKS cluster ///
//////////////////////////////////////////////////

// 1. Create a VPC with IPv6 CIDR block.
vpc, err := ec2.NewVpc(ctx, "ipv6-vpc", &ec2.VpcArgs{
AssignGeneratedIpv6CidrBlock: pulumi.Bool(true),
EnableDnsSupport: pulumi.Bool(true),
EnableDnsHostnames: pulumi.Bool(true),
CidrBlock: pulumi.String("10.100.0.0/16"),
})
if err != nil {
return err
}

// 2. Create two subnets with IPv6 CIDR block in two different availability zones.
// EKS requires at least two subnets in different availability zones.
var subnetIDs []pulumi.StringInput
for idx, az := range []string{"us-west-2a", "us-west-2b"} {
subnet, err := ec2.NewSubnet(ctx, fmt.Sprintf("ipv6-subnet-%d", idx), &ec2.SubnetArgs{
VpcId: vpc.ID().ToStringOutput(),
AssignIpv6AddressOnCreation: pulumi.Bool(true),
AvailabilityZone: pulumi.String(az),
CidrBlock: pulumi.String(fmt.Sprintf("10.100.%d.0/24", len(subnetIDs))),
Ipv6CidrBlock: calculateIPV6CidrBlock(vpc.Ipv6CidrBlock, idx),
})
if err != nil {
return err
}

subnetIDs = append(subnetIDs, subnet.ID().ToStringOutput())
}

// 3. Create an EKS cluster with IPv6 networking enabled.
cluster4, err := eks.NewCluster(ctx, "example-cluster-4", &eks.ClusterArgs{
IpFamily: pulumi.StringPtr("ipv6"),
VpcId: vpc.ID().ToStringOutput(),
SubnetIds: pulumi.StringArray(subnetIDs),
UseDefaultVpcCni: func() *bool { t := true; return &t }(),
NodeGroupOptions: &eks.ClusterNodeGroupOptionsArgs{
DesiredCapacity: pulumi.IntPtr(2),
MinSize: pulumi.IntPtr(2),
MaxSize: pulumi.IntPtr(2),
},
})
if err != nil {
return err
}

////////////////////////////////////////////////
/// CreationRoleProvider should fail ///
////////////////////////////////////////////////

// Create AWS provider
awsProv, err := aws.NewProvider(ctx, "aws", nil)
if err != nil {
return err
}

// Create cluster with CreationRoleProvider
cluster5, err := eks.NewCluster(ctx, "example-cluster-5", &eks.ClusterArgs{
DesiredCapacity: pulumi.IntPtr(2),
MinSize: pulumi.IntPtr(2),
MaxSize: pulumi.IntPtr(2),
CreationRoleProvider: &eks.CreationRoleProviderArgs{
Provider: awsProv,
},
EnabledClusterLogTypes: pulumi.StringArray{
pulumi.String("api"),
pulumi.String("audit"),
pulumi.String("authenticator"),
},
})
if err != nil {
return err
}

//////////////////////////////////////////
/// Export cluster kubeconfigs ///
//////////////////////////////////////////

ctx.Export("kubeconfig1", cluster1.Kubeconfig)
ctx.Export("kubeconfig2", cluster2.Kubeconfig)
ctx.Export("kubeconfig3", cluster3.Kubeconfig)
ctx.Export("kubeconfig4", cluster4.Kubeconfig)
ctx.Export("kubeconfig5", cluster5.Kubeconfig)
return nil
})
}

// calculateIPV6CidrBlock is a very simple function to calculate the ipv6 subnet cidr block for testing purpose.
// Usage for real workloads should implement a more robust function.
// Example: If the VPC ipv6 cidr block is 2600:1f13:e6:c000::/56, then the subnet ipv6 cidr block will be:
// 2600:1f13:e6:c005::/64, 2600:1f13:e6:c006::/64, 2600:1f13:e6:c007::/64, ...
func calculateIPV6CidrBlock(ipv6CidrBlock pulumi.StringOutput, subnetID int) pulumi.StringInput {
return ipv6CidrBlock.ApplyT(func(cidr string) (string, error) {
cidrStripped := strings.TrimSuffix(cidr, "::/56")
cidrStripped = cidrStripped[:len(cidrStripped)-1]
return fmt.Sprintf("%s%d::/64", cidrStripped, subnetID+5), nil

}).(pulumi.StringOutput)
}
17 changes: 16 additions & 1 deletion examples/examples_go_test.go
Expand Up @@ -17,18 +17,22 @@
package example

import (
"bytes"
"path/filepath"
"testing"

"github.com/pulumi/pulumi-eks/examples/utils"
"github.com/pulumi/pulumi/pkg/v3/testing/integration"
"github.com/stretchr/testify/assert"
)

func TestAccClusterGo(t *testing.T) {
var stdErr bytes.Buffer

test := getGoBaseOptions(t).
With(integration.ProgramTestOptions{
RunUpdateTest: false,
Dir: filepath.Join(getCwd(t), "cluster-go"),
Dir: filepath.Join(getCwd(t), "cluster-go", "step1"),
ExtraRuntimeValidation: func(t *testing.T, info integration.RuntimeValidationStackInfo) {
utils.RunEKSSmokeTest(t,
info.Deployment.Resources,
Expand All @@ -37,9 +41,20 @@ func TestAccClusterGo(t *testing.T) {
info.Outputs["kubeconfig3"],
)
},
EditDirs: []integration.EditDir{
{
// Step 2 should fail because the `creationRoleProvider` option is not supported in non nodejs Pulumi programs.
Dir: filepath.Join(getCwd(t), "cluster-go", "step2"),
ExpectFailure: true,
Additive: true,
Stderr: &stdErr,
},
},
})

integration.ProgramTest(t, &test)
// Ensure that the provider error message is as expected.
assert.Contains(t, stdErr.String(), "not supported")
}

// TestAccClusterGoWithOidc tests that we can set extra node security groups on new node groups.
Expand Down
6 changes: 6 additions & 0 deletions nodejs/eks/cluster.ts
Expand Up @@ -1907,6 +1907,12 @@ export class ClusterInternal extends pulumi.ComponentResource {

super(type, name, args, opts);

if (args?.creationRoleProvider?.provider) {
throw new Error(
"The `creationRoleProvider.provider` option is not supported in non-nodejs Pulumi programs. Please use the `providerCredentialOpts` option instead.",
);
}

const cluster = createCluster(name, this, args, opts);
this.kubeconfig = cluster.kubeconfig;
this.kubeconfigJson = cluster.kubeconfigJson;
Expand Down

0 comments on commit 2c3cb5b

Please sign in to comment.