Skip to content

Commit 6dfd5c2

Browse files
author
Wei
authored
Merge pull request #152 from daimaxiaxie/support-multiple-authorizations
improve authorization
2 parents f8a3acc + 6fc1e6e commit 6dfd5c2

40 files changed

+235
-4847
lines changed

go.mod

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ require (
99
github.com/alibabacloud-go/tea v1.2.2
1010
github.com/alibabacloud-go/tea-utils/v2 v2.0.6
1111
github.com/alibabacloud-go/vpc-20160428/v6 v6.10.4
12-
github.com/aliyun/aliyun-cli v0.0.0-20240925084117-158a70e275f0
1312
github.com/awslabs/operatorpkg v0.0.0-20240805231134-67d0acfb6306
1413
github.com/cloudpilot-ai/priceserver v0.0.0-20241011010411-15ac0e19a857
1514
github.com/mitchellh/hashstructure/v2 v2.0.2
@@ -42,7 +41,7 @@ require (
4241
github.com/alibabacloud-go/openapi-util v0.1.0 // indirect
4342
github.com/alibabacloud-go/tea-utils v1.3.1 // indirect
4443
github.com/alibabacloud-go/tea-xml v1.1.3 // indirect
45-
github.com/aliyun/credentials-go v1.3.10 // indirect
44+
github.com/aliyun/credentials-go v1.3.10
4645
github.com/beorn7/perks v1.0.1 // indirect
4746
github.com/blang/semver/v4 v4.0.0 // indirect
4847
github.com/blendle/zapdriver v1.3.1 // indirect

go.sum

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -91,8 +91,6 @@ github.com/alibabacloud-go/tea-xml v1.1.3 h1:7LYnm+JbOq2B+T/B0fHC4Ies4/FofC4zHzY
9191
github.com/alibabacloud-go/tea-xml v1.1.3/go.mod h1:Rq08vgCcCAjHyRi/M7xlHKUykZCEtyBy9+DPF6GgEu8=
9292
github.com/alibabacloud-go/vpc-20160428/v6 v6.10.4 h1:6OXPOw1WcEjoSCOPFtKKgFFSlSSapns0uoOML+hzn8M=
9393
github.com/alibabacloud-go/vpc-20160428/v6 v6.10.4/go.mod h1:6516WWE4Y9lzscVSfaev84DM+TQSvBEGX1oeMvDL5xk=
94-
github.com/aliyun/aliyun-cli v0.0.0-20240925084117-158a70e275f0 h1:GyWC5h0inFp+vmJVbbRGh34KTj/HeG/tyqJwR+pQbko=
95-
github.com/aliyun/aliyun-cli v0.0.0-20240925084117-158a70e275f0/go.mod h1:LRvAoBmigy35079C5FYKseCCHG4oCCC0dEgyuSsAVeo=
9694
github.com/aliyun/credentials-go v1.1.2/go.mod h1:ozcZaMR5kLM7pwtCMEpVmQ242suV6qTJya2bDq4X1Tw=
9795
github.com/aliyun/credentials-go v1.3.1/go.mod h1:8jKYhQuDawt8x2+fusqa1Y6mPxemTsBEN04dgcAcYz0=
9896
github.com/aliyun/credentials-go v1.3.6/go.mod h1:1LxUuX7L5YrZUWzBrRyk0SwSdH4OmPrib8NVePL3fxM=

pkg/operator/operator.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ type Operator struct {
6161
}
6262

6363
func NewOperator(ctx context.Context, operator *operator.Operator) (context.Context, *Operator) {
64-
clientConfig, err := client.NewClientConfig()
64+
clientConfig, err := client.NewClientConfig(ctx, options.FromContext(ctx).RegionID, options.FromContext(ctx).AliNetwork)
6565
if err != nil {
6666
log.FromContext(ctx).Error(err, "Failed to create client config")
6767
os.Exit(1)

pkg/operator/options/options.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ type optionsKey struct{}
3535

3636
type Options struct {
3737
ClusterID string
38+
RegionID string
39+
AliNetwork string
3840
VMMemoryOverheadPercent float64
3941
Interruption bool
4042
TelemetryShare bool
@@ -43,6 +45,8 @@ type Options struct {
4345

4446
func (o *Options) AddFlags(fs *coreoptions.FlagSet) {
4547
fs.StringVar(&o.ClusterID, "cluster-id", env.WithDefaultString("CLUSTER_ID", ""), "The external kubernetes cluster id for new nodes to connect with.")
48+
fs.StringVar(&o.RegionID, "region-id", env.WithDefaultString("REGION_ID", ""), "Region of the kubernetes cluster. If not set, automatically obtain the host region.")
49+
fs.StringVar(&o.AliNetwork, "alibaba-cloud-network", env.WithDefaultString("ALIBABA_CLOUD_NETWORK", ""), "Network type for AlibabaCloud endpoint. If not set, use public.")
4650
// TODO: for different OS, the overhead is different, find a way to fix this.
4751
fs.Float64Var(&o.VMMemoryOverheadPercent, "vm-memory-overhead-percent", utils.WithDefaultFloat64("VM_MEMORY_OVERHEAD_PERCENT", 0.065), "The VM memory overhead as a percent that will be subtracted from the total memory for all instance types.")
4852
fs.BoolVar(&o.Interruption, "interruption", env.WithDefaultBool("INTERRUPTION", true), "Enable interruption handling.")

pkg/operator/options/options_validation.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ import (
1818
"fmt"
1919

2020
"go.uber.org/multierr"
21+
22+
"github.com/cloudpilot-ai/karpenter-provider-alibabacloud/pkg/utils/client/metadata"
2123
)
2224

2325
func (o *Options) Validate() error {
@@ -30,5 +32,14 @@ func (o *Options) validateRequiredFields() error {
3032
if o.ClusterID == "" {
3133
return fmt.Errorf("missing field, cluster-id")
3234
}
35+
if o.RegionID == "" {
36+
region, err := metadata.NewMetaData(nil).Region()
37+
if err != nil {
38+
return err
39+
} else if region == "" {
40+
return fmt.Errorf("missing field, region-id")
41+
}
42+
o.RegionID = region
43+
}
3344
return nil
3445
}

pkg/utils/client/client.go

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -17,30 +17,30 @@ limitations under the License.
1717
package client
1818

1919
import (
20-
"errors"
21-
20+
"context"
21+
"fmt"
2222
openapi "github.com/alibabacloud-go/darabonba-openapi/v2/client"
2323
"github.com/alibabacloud-go/tea/tea"
24-
aliyunconfig "github.com/aliyun/aliyun-cli/config"
24+
"github.com/aliyun/credentials-go/credentials"
25+
"sigs.k8s.io/controller-runtime/pkg/log"
2526
)
2627

27-
func NewClientConfig() (*openapi.Config, error) {
28-
profile, err := aliyunconfig.LoadCurrentProfile()
28+
func NewClientConfig(ctx context.Context, region string, network string) (*openapi.Config, error) {
29+
// Load in the following order: 1. AK/SK, 2. RRSA, 3. config.json, 4. RAMRole
30+
// https://www.alibabacloud.com/help/zh/sdk/developer-reference/v2-manage-go-access-credentials#3ca299f04bw3c
31+
credential, err := credentials.NewCredential(nil)
2932
if err != nil {
3033
return nil, err
3134
}
32-
33-
if profile.RegionId == "" {
34-
return nil, errors.New("regionId must be set in the config file")
35-
}
36-
37-
credentialClient, err := profile.GetCredential(nil, nil)
38-
if err != nil {
39-
return nil, err
35+
if cred, err := credential.GetCredential(); err == nil && cred != nil {
36+
log.FromContext(ctx).Info(fmt.Sprintf("using credential type: %s, AccessKeyID: %s", tea.StringValue(cred.Type), tea.StringValue(cred.AccessKeyId)))
37+
} else {
38+
return nil, fmt.Errorf("failed get credential, error: %w", err)
4039
}
4140

4241
return &openapi.Config{
43-
RegionId: tea.String(profile.RegionId),
44-
Credential: credentialClient,
42+
RegionId: tea.String(region),
43+
Credential: credential,
44+
Network: tea.String(network), // 1. public, 2. vpc, default is public
4545
}, nil
4646
}
Lines changed: 203 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,203 @@
1+
/*
2+
Copyright 2024 The CloudPilot AI Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package metadata
18+
19+
import (
20+
"encoding/json"
21+
"errors"
22+
"fmt"
23+
"io"
24+
"net/http"
25+
"os"
26+
"reflect"
27+
"strings"
28+
"time"
29+
)
30+
31+
const (
32+
Endpoint = "http://100.100.100.200"
33+
regionID = "region-id"
34+
)
35+
36+
// MetaData wrap http client
37+
type MetaData struct {
38+
// mock for unit test.
39+
mock requestMock
40+
client *http.Client
41+
}
42+
43+
// NewMetaData returns MetaData
44+
func NewMetaData(client *http.Client) *MetaData {
45+
if client == nil {
46+
client = &http.Client{}
47+
}
48+
return &MetaData{
49+
client: client,
50+
}
51+
}
52+
53+
// New returns MetaDataRequest
54+
func (m *MetaData) New() *MetaDataRequest {
55+
return &MetaDataRequest{
56+
client: m.client,
57+
sendRequest: m.mock,
58+
}
59+
}
60+
61+
// Region returns region
62+
func (m *MetaData) Region() (string, error) {
63+
var region ResultList
64+
err := m.New().Resource(regionID).Do(&region)
65+
if err != nil {
66+
return "", err
67+
}
68+
return region.result[0], nil
69+
}
70+
71+
type requestMock func(resource string) (string, error)
72+
73+
// ResultList struct
74+
type ResultList struct {
75+
result []string
76+
}
77+
78+
// nolint: stylecheck
79+
// RoleAuth struct
80+
type RoleAuth struct {
81+
AccessKeyId string
82+
AccessKeySecret string
83+
Expiration time.Time
84+
SecurityToken string
85+
LastUpdated time.Time
86+
Code string
87+
}
88+
89+
// MetaDataRequest struct
90+
type MetaDataRequest struct {
91+
version string
92+
resourceType string
93+
resource string
94+
subResource string
95+
client *http.Client
96+
97+
sendRequest requestMock
98+
}
99+
100+
// Version sets version
101+
func (r *MetaDataRequest) Version(version string) *MetaDataRequest {
102+
r.version = version
103+
return r
104+
}
105+
106+
// ResourceType sets resource type
107+
func (r *MetaDataRequest) ResourceType(rtype string) *MetaDataRequest {
108+
r.resourceType = rtype
109+
return r
110+
}
111+
112+
// Resource sets resource
113+
func (r *MetaDataRequest) Resource(resource string) *MetaDataRequest {
114+
r.resource = resource
115+
return r
116+
}
117+
118+
// SubResource set sub resource
119+
func (r *MetaDataRequest) SubResource(sub string) *MetaDataRequest {
120+
r.subResource = sub
121+
return r
122+
}
123+
124+
// URL returns url
125+
func (r *MetaDataRequest) URL() (string, error) {
126+
if r.version == "" {
127+
r.version = "latest"
128+
}
129+
if r.resourceType == "" {
130+
r.resourceType = "meta-data"
131+
}
132+
if r.resource == "" {
133+
return "", errors.New("the resource you want to visit must not be nil")
134+
}
135+
endpoint := os.Getenv("METADATA_ENDPOINT")
136+
if endpoint == "" {
137+
endpoint = Endpoint
138+
}
139+
url := fmt.Sprintf("%s/%s/%s/%s", endpoint, r.version, r.resourceType, r.resource)
140+
if r.subResource == "" {
141+
return url, nil
142+
}
143+
return fmt.Sprintf("%s/%s", url, r.subResource), nil
144+
}
145+
146+
// Do try to do MetaDataRequest
147+
func (r *MetaDataRequest) Do(api interface{}) (err error) {
148+
res := ""
149+
150+
if r.sendRequest != nil {
151+
res, err = r.sendRequest(r.resource)
152+
} else {
153+
res, err = r.send()
154+
}
155+
156+
if err != nil {
157+
return err
158+
}
159+
return r.Decode(res, api)
160+
}
161+
162+
// Decode returns decoded content
163+
func (r *MetaDataRequest) Decode(data string, api interface{}) error {
164+
if data == "" {
165+
url, _ := r.URL()
166+
return fmt.Errorf("metadata: alivpc decode data must not be nil. url=[%s]", url)
167+
}
168+
switch api := api.(type) {
169+
case *ResultList:
170+
api.result = strings.Split(data, "\n")
171+
return nil
172+
case *RoleAuth:
173+
return json.Unmarshal([]byte(data), api)
174+
default:
175+
return fmt.Errorf("metadata: unknow type to decode, type=%s", reflect.TypeOf(api))
176+
}
177+
}
178+
179+
func (r *MetaDataRequest) send() (string, error) {
180+
url, err := r.URL()
181+
if err != nil {
182+
return "", err
183+
}
184+
req, err := http.NewRequest(http.MethodGet, url, nil)
185+
186+
if err != nil {
187+
return "", err
188+
}
189+
resp, err := r.client.Do(req)
190+
if err != nil {
191+
return "", err
192+
}
193+
if resp.StatusCode != 200 {
194+
return "", fmt.Errorf("aliyun Metadata API Error: Status Code: %d", resp.StatusCode)
195+
}
196+
defer resp.Body.Close()
197+
198+
data, err := io.ReadAll(resp.Body)
199+
if err != nil {
200+
return "", err
201+
}
202+
return string(data), nil
203+
}

0 commit comments

Comments
 (0)