Repository: kubernetes/cloud-provider-aws
Pull request #129 (2020-09-23 20:27:02)

Create a new instance of aws cloud
<!--  Thanks for sending a pull request!  Here are some tips for you:

1. If this is your first time, please read our contributor guidelines: https://git.k8s.io/community/contributors/guide#your-first-contribution and developer guide https://git.k8s.io/community/contributors/devel/development.md#development-guide
2. Please label this pull request according to what type of issue you are addressing, especially if this is a release targeted pull request. For reference on required PR/issue labels, read here:
https://git.k8s.io/community/contributors/devel/sig-release/release.md#issue-kind-label
3. Ensure you have added or ran the appropriate tests for your PR: https://git.k8s.io/community/contributors/devel/sig-testing/testing.md
4. If you want *faster* PR reviews, read how: https://git.k8s.io/community/contributors/guide/pull-requests.md#best-practices-for-faster-reviews
5. Follow the instructions for writing a release note: https://git.k8s.io/community/contributors/guide/release-notes.md
6. If the PR is unfinished, see how to mark it: https://git.k8s.io/community/contributors/guide/pull-requests.md#marking-unfinished-pull-requests
-->

**What type of PR is this?**
/kind feature

**What this PR does / why we need it**:
This PR creates a new instance of aws cloud, which helps future PRs to commit in parallel with fewer conflicts

**Which issue(s) this PR fixes**:
<!-- 
*Automatically closes linked issue when PR is merged.
Usage: `Fixes #<issue number>`, or `Fixes (paste link of issue)`.
_If PR is about `failing-tests or flakes`, please post the related issues/tests in a comment and do not use `Fixes`_*
-->
Part of #125

**Special notes for your reviewer**:

**Does this PR introduce a user-facing change?**:
<!--  
If no, just write "NONE".
If yes, a release note is required:
Enter your extended release note in the block below. If the PR requires additional action from users switching to the new release, include the string "action required".
2. 
-->
```release-note
Create a new instance of aws cloud of v2 provider.
```

k8s-ci-robot: Hi @HaibaraAi96. Thanks for your PR.

I'm waiting for a [kubernetes](https://github.com/orgs/kubernetes/people) member to verify that this patch is reasonable to test. If it is, they should reply with `/ok-to-test` on its own line. Until that is done, I will not automatically test new commits in this PR, but the usual testing commands by org members will still work. Regular contributors should [join the org](https://git.k8s.io/community/community-membership.md#member) to skip this step.

Once the patch is verified, the new status will be reflected by the `ok-to-test` label.

I understand the commands that are listed [here](https://go.k8s.io/bot-commands?repo=kubernetes%2Fcloud-provider-aws).

<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes/test-infra](https://github.com/kubernetes/test-infra/issues/new?title=Prow%20issue:) repository.
</details>

k8s-ci-robot: [APPROVALNOTIFIER] This PR is **NOT APPROVED**

This pull-request has been approved by: *<a href="https://github.com/kubernetes/cloud-provider-aws/pull/129#" title="Author self-approved">HaibaraAi96</a>*
To complete the [pull request process](https://git.k8s.io/community/contributors/guide/owners.md#the-code-review-process), please assign **leakingtapan**
You can assign the PR to them by writing `/assign @leakingtapan` in a comment when ready.

The full list of commands accepted by this bot can be found [here](https://go.k8s.io/bot-commands?repo=kubernetes%2Fcloud-provider-aws).

<details open>
Needs approval from an approver in each of these files:

- **[OWNERS](https://github.com/kubernetes/cloud-provider-aws/blob/master/OWNERS)**

Approvers can indicate their approval by writing `/approve` in a comment
Approvers can cancel approval by writing `/approve cancel` in a comment
</details>
<!-- META={"approvers":["leakingtapan"]} -->
HaibaraAi96: /assign @andrewsykim 
k8s-ci-robot: [APPROVALNOTIFIER] This PR is **NOT APPROVED**

This pull-request has been approved by: *<a href="https://github.com/kubernetes/cloud-provider-aws/pull/129#" title="Author self-approved">HaibaraAi96</a>*
To complete the [pull request process](https://git.k8s.io/community/contributors/guide/owners.md#the-code-review-process), please assign **andrewsykim**
You can assign the PR to them by writing `/assign @andrewsykim` in a comment when ready.

The full list of commands accepted by this bot can be found [here](https://go.k8s.io/bot-commands?repo=kubernetes%2Fcloud-provider-aws).

<details open>
Needs approval from an approver in each of these files:

- **[OWNERS](https://github.com/kubernetes/cloud-provider-aws/blob/master/OWNERS)**

Approvers can indicate their approval by writing `/approve` in a comment
Approvers can cancel approval by writing `/approve cancel` in a comment
</details>
<!-- META={"approvers":["andrewsykim"]} -->
HaibaraAi96: /retest

Patch:
diff --git a/go.mod b/go.mod
index 5c4c519..f4c691c 100644
--- a/go.mod
+++ b/go.mod
@@ -27,8 +27,10 @@ replace (
 )
 
 require (
+	github.com/aws/aws-sdk-go v1.28.2
 	github.com/spf13/cobra v1.0.0
 	github.com/spf13/pflag v1.0.5
+	github.com/stretchr/testify v1.4.0
 	k8s.io/apimachinery v0.0.0
 	k8s.io/apiserver v0.0.0
 	k8s.io/cloud-provider v0.0.0
diff --git a/pkg/providers/v2/interface.go b/pkg/providers/v2/cloud.go
similarity index 60%
rename from pkg/providers/v2/interface.go
rename to pkg/providers/v2/cloud.go
index 7e64821..973190f 100644
--- a/pkg/providers/v2/interface.go
+++ b/pkg/providers/v2/cloud.go
@@ -19,14 +19,21 @@ limitations under the License.
 package v2
 
 import (
+	"fmt"
 	"io"
+	"regexp"
 
+	"github.com/aws/aws-sdk-go/aws"
+	"github.com/aws/aws-sdk-go/aws/credentials"
+	"github.com/aws/aws-sdk-go/aws/credentials/ec2rolecreds"
+	"github.com/aws/aws-sdk-go/aws/ec2metadata"
+	"github.com/aws/aws-sdk-go/aws/session"
 	cloudprovider "k8s.io/cloud-provider"
 )
 
 func init() {
 	cloudprovider.RegisterCloudProvider(ProviderName, func(config io.Reader) (cloudprovider.Interface, error) {
-		return &cloud{}, nil
+		return newCloud()
 	})
 }
 
@@ -39,6 +46,71 @@ var _ cloudprovider.Interface = (*cloud)(nil)
 
 // cloud is the AWS v2 implementation of the cloud provider interface
 type cloud struct {
+	creds  *credentials.Credentials
+	region string
+}
+
+// EC2Metadata is an abstraction over the AWS metadata service.
+type EC2Metadata interface {
+	// Query the EC2 metadata service (used to discover instance-id etc)
+	GetMetadata(path string) (string, error)
+}
+
+func getAvailabilityZone(metadata EC2Metadata) (string, error) {
+	return metadata.GetMetadata("placement/availability-zone")
+}
+
+// Derives the region from a valid az name.
+// Returns an error if the az is known invalid (empty)
+func azToRegion(az string) (string, error) {
+	if len(az) == 0 {
+		return "", fmt.Errorf("invalid (empty) AZ")
+	}
+
+	r := regexp.MustCompile(`^([a-zA-Z]+-)+\d+`)
+	region := r.FindString(az)
+	if region == "" {
+		return "", fmt.Errorf("invalid AZ: %s", az)
+	}
+
+	return region, nil
+}
+
+// newCloud creates a new instance of AWSCloud.
+func newCloud() (cloudprovider.Interface, error) {
+	sess, err := session.NewSession(&aws.Config{})
+	if err != nil {
+		return nil, fmt.Errorf("unable to initialize AWS session: %v", err)
+	}
+
+	creds := credentials.NewChainCredentials(
+		[]credentials.Provider{
+			&credentials.EnvProvider{},
+			&ec2rolecreds.EC2RoleProvider{
+				Client: ec2metadata.New(sess),
+			},
+			&credentials.SharedCredentialsProvider{},
+		})
+
+	metadataClient := ec2metadata.New(sess)
+	if err != nil {
+		return nil, fmt.Errorf("error creating AWS metadata client: %q", err)
+	}
+
+	az, err := getAvailabilityZone(metadataClient)
+	if err != nil {
+		return nil, err
+	}
+
+	region, err := azToRegion(az)
+	if err != nil {
+		return nil, err
+	}
+
+	return &cloud{
+		creds:  creds,
+		region: region,
+	}, nil
 }
 
 // Initialize passes a Kubernetes clientBuilder interface to the cloud provider


Test patch:
diff --git a/pkg/providers/v2/cloud_test.go b/pkg/providers/v2/cloud_test.go
new file mode 100644
index 0000000..4f94cf1
--- /dev/null
+++ b/pkg/providers/v2/cloud_test.go
@@ -0,0 +1,46 @@
+/*
+Copyright 2020 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 v2 is an out-of-tree only implementation of the AWS cloud provider.
+// It is not compatible with v1 and should only be used on new clusters.
+package v2
+
+import (
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+)
+
+func TestAzToRegion(t *testing.T) {
+	testCases := []struct {
+		az     string
+		region string
+	}{
+		{"us-east-1a", "us-east-1"},
+		{"us-west-2-lax-1a", "us-west-2"},
+		{"eu-central-1a", "eu-central-1"},
+		{"ap-northeast-2a", "ap-northeast-2"},
+		{"us-gov-east-1a", "us-gov-east-1"},
+		{"us-iso-east-1a", "us-iso-east-1"},
+		{"us-isob-east-1a", "us-isob-east-1"},
+	}
+
+	for _, testCase := range testCases {
+		ret, err := azToRegion(testCase.az)
+		assert.NoError(t, err)
+		assert.Equal(t, testCase.region, ret)
+	}
+}