From 0268e73569926c169a5f453089f0c53cb56952c3 Mon Sep 17 00:00:00 2001 From: mhf Date: Tue, 20 Sep 2022 16:03:08 +0800 Subject: [PATCH] add hcso aksk --- cmd/climc/shell/cloudid/cloudusers.go | 9 ++ pkg/apis/cloudid/clouduser.go | 11 ++ pkg/cloudid/models/clouduser.go | 45 ++++++++ pkg/cloudprovider/clouduser.go | 7 ++ pkg/cloudprovider/resources.go | 4 + pkg/hostman/hostdeployer/apis/deploy.pb.go | 1 - pkg/mcclient/options/cloudid/clouduser.go | 26 +++++ pkg/multicloud/aliyun/ram_user.go | 2 + pkg/multicloud/apsara/ram_user.go | 2 + pkg/multicloud/aws/iam_user.go | 2 + pkg/multicloud/azure/clouduser.go | 2 + pkg/multicloud/clouduser.go | 36 ++++++ pkg/multicloud/google/iampolicy.go | 3 + pkg/multicloud/hcso/clouduser.go | 68 +++++++++++ pkg/multicloud/hcso/hcso.go | 124 +++++++++++++++++++++ pkg/multicloud/hcso/huawei.go | 2 + pkg/multicloud/hcso/shell/clouduser.go | 33 ++++++ pkg/multicloud/huawei/clouduser.go | 64 +++++++++++ pkg/multicloud/huawei/huawei.go | 23 +++- pkg/multicloud/huawei/shell/clouduser.go | 33 ++++++ pkg/multicloud/qcloud/cam_user.go | 2 + 21 files changed, 495 insertions(+), 4 deletions(-) create mode 100644 pkg/multicloud/clouduser.go create mode 100644 pkg/multicloud/hcso/hcso.go diff --git a/cmd/climc/shell/cloudid/cloudusers.go b/cmd/climc/shell/cloudid/cloudusers.go index 03f4019873..44e0bffd8b 100644 --- a/cmd/climc/shell/cloudid/cloudusers.go +++ b/cmd/climc/shell/cloudid/cloudusers.go @@ -15,7 +15,10 @@ package cloudid import ( + "yunion.io/x/jsonutils" + "yunion.io/x/onecloud/cmd/climc/shell" + "yunion.io/x/onecloud/pkg/mcclient/modulebase" modules "yunion.io/x/onecloud/pkg/mcclient/modules/cloudid" "yunion.io/x/onecloud/pkg/mcclient/options/cloudid" ) @@ -35,4 +38,10 @@ func init() { cmd.Perform("reset-password", &cloudid.ClouduserResetPasswordOptions{}) cmd.Perform("cloud-user-join-group", &cloudid.ClouduserGroupOptions{}) cmd.Perform("cloud-user-leave-group", &cloudid.ClouduserGroupOptions{}) + cmd.GetWithCustomShow("access-keys", func(result jsonutils.JSONObject) { + ret := modulebase.JSON2ListResult(result) + shell.PrintList(ret, nil) + }, &cloudid.ClouduserListAccessKeyInput{}) + cmd.Perform("delete-access-key", &cloudid.ClouduserDeleteAccessKeyInput{}) + cmd.Perform("create-access-key", &cloudid.ClouduserCreateAccessKeyInput{}) } diff --git a/pkg/apis/cloudid/clouduser.go b/pkg/apis/cloudid/clouduser.go index 06d6be9b3d..7c5b4d3666 100644 --- a/pkg/apis/cloudid/clouduser.go +++ b/pkg/apis/cloudid/clouduser.go @@ -268,3 +268,14 @@ type ClouduserChangeOwnerInput struct { // 本地用户Id UserId string `json:"user_id"` } + +type ClouduserCreateAccessKeyInput struct { + Name string `json:"name"` +} + +type ClouduserDeleteAccessKeyInput struct { + AccessKey string `json:"access_key"` +} + +type ClouduserListAccessKeyInput struct { +} diff --git a/pkg/cloudid/models/clouduser.go b/pkg/cloudid/models/clouduser.go index 97f11dcfa6..a949e36798 100644 --- a/pkg/cloudid/models/clouduser.go +++ b/pkg/cloudid/models/clouduser.go @@ -1512,3 +1512,48 @@ func (self *SClouduser) SyncCustomCloudpoliciesForCloud(ctx context.Context, use return account.SyncCustomCloudpoliciesForCloud(ctx, userCred, self) } + +func (self *SClouduser) PerformCreateAccessKey(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.ClouduserCreateAccessKeyInput) (jsonutils.JSONObject, error) { + user, err := self.GetIClouduser() + if err != nil { + return nil, errors.Wrapf(err, "GetIClouduser error") + } + ak, err := user.CreateAccessKey(input.Name) + if err != nil { + return nil, errors.Wrapf(err, "GetDetailsAccessKeys error") + } + return jsonutils.Marshal(ak), nil +} + +func (self *SClouduser) GetDetailsAccessKeys(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) (jsonutils.JSONObject, error) { + user, err := self.GetIClouduser() + if err != nil { + return nil, errors.Wrapf(err, "GetIClouduser") + } + aks, err := user.GetAccessKeys() + if err != nil { + return nil, errors.Wrapf(err, "GetAccessKeys") + } + ret := struct { + Data []cloudprovider.SAccessKey + Total int + Limit int + }{ + Data: aks, + Total: len(aks), + Limit: 20, + } + return jsonutils.Marshal(ret), nil +} + +func (self *SClouduser) DeleteAccessKey(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.ClouduserDeleteAccessKeyInput) (jsonutils.JSONObject, error) { + user, err := self.GetIClouduser() + if err != nil { + return nil, errors.Wrapf(err, "GetIClouduser") + } + err = user.DeleteAccessKey(input.AccessKey) + if err != nil { + return nil, errors.Wrapf(err, "DeleteAccessKey") + } + return nil, nil +} diff --git a/pkg/cloudprovider/clouduser.go b/pkg/cloudprovider/clouduser.go index 568645bc58..f0480126d2 100644 --- a/pkg/cloudprovider/clouduser.go +++ b/pkg/cloudprovider/clouduser.go @@ -38,3 +38,10 @@ type SCloudpolicyCreateOptions struct { Desc string Document *jsonutils.JSONDict } + +type SAccessKey struct { + Name string + AccessKey string + Secret string + Status string +} diff --git a/pkg/cloudprovider/resources.go b/pkg/cloudprovider/resources.go index df138d7024..4dbb9ffab3 100644 --- a/pkg/cloudprovider/resources.go +++ b/pkg/cloudprovider/resources.go @@ -1193,6 +1193,10 @@ type IClouduser interface { ResetPassword(password string) error IsConsoleLogin() bool + + CreateAccessKey(name string) (*SAccessKey, error) + DeleteAccessKey(accessKey string) error + GetAccessKeys() ([]SAccessKey, error) } // 公有云子账号权限 diff --git a/pkg/hostman/hostdeployer/apis/deploy.pb.go b/pkg/hostman/hostdeployer/apis/deploy.pb.go index 3afd9ad113..cd50c91dca 100644 --- a/pkg/hostman/hostdeployer/apis/deploy.pb.go +++ b/pkg/hostman/hostdeployer/apis/deploy.pb.go @@ -28,7 +28,6 @@ import ( reflect "reflect" sync "sync" - protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" ) diff --git a/pkg/mcclient/options/cloudid/clouduser.go b/pkg/mcclient/options/cloudid/clouduser.go index ed47d3d3a9..b6989c77b6 100644 --- a/pkg/mcclient/options/cloudid/clouduser.go +++ b/pkg/mcclient/options/cloudid/clouduser.go @@ -119,3 +119,29 @@ type ClouduserResetPasswordOptions struct { func (opts *ClouduserResetPasswordOptions) Params() (jsonutils.JSONObject, error) { return jsonutils.Marshal(map[string]string{"password": opts.Password}), nil } + +type ClouduserCreateAccessKeyInput struct { + ClouduserIdOption + Name string `json:"Name"` +} + +func (opts *ClouduserCreateAccessKeyInput) Params() (jsonutils.JSONObject, error) { + return jsonutils.Marshal(map[string]string{"id": opts.ID, "name": opts.Name}), nil +} + +type ClouduserDeleteAccessKeyInput struct { + ClouduserIdOption + AccessKey string `json:"access_key"` +} + +func (opts *ClouduserDeleteAccessKeyInput) Params() (jsonutils.JSONObject, error) { + return jsonutils.Marshal(map[string]string{"access_key": opts.AccessKey}), nil +} + +type ClouduserListAccessKeyInput struct { + ClouduserIdOption +} + +func (opts *ClouduserListAccessKeyInput) Params() (jsonutils.JSONObject, error) { + return nil, nil +} diff --git a/pkg/multicloud/aliyun/ram_user.go b/pkg/multicloud/aliyun/ram_user.go index 2ebba89d8e..ea3f27a97d 100644 --- a/pkg/multicloud/aliyun/ram_user.go +++ b/pkg/multicloud/aliyun/ram_user.go @@ -22,6 +22,7 @@ import ( "yunion.io/x/pkg/errors" "yunion.io/x/onecloud/pkg/cloudprovider" + "yunion.io/x/onecloud/pkg/multicloud" ) type sUsers struct { @@ -36,6 +37,7 @@ type SUsers struct { type SUser struct { client *SAliyunClient + multicloud.SBaseClouduser Comments string CreateDate time.Time diff --git a/pkg/multicloud/apsara/ram_user.go b/pkg/multicloud/apsara/ram_user.go index df016b2015..c0c293afab 100644 --- a/pkg/multicloud/apsara/ram_user.go +++ b/pkg/multicloud/apsara/ram_user.go @@ -22,6 +22,7 @@ import ( "yunion.io/x/pkg/errors" "yunion.io/x/onecloud/pkg/cloudprovider" + "yunion.io/x/onecloud/pkg/multicloud" ) type sUsers struct { @@ -36,6 +37,7 @@ type SUsers struct { type SUser struct { client *SApsaraClient + multicloud.SBaseClouduser Comments string CreateDate time.Time diff --git a/pkg/multicloud/aws/iam_user.go b/pkg/multicloud/aws/iam_user.go index aecd2bf899..d43a5c72b2 100644 --- a/pkg/multicloud/aws/iam_user.go +++ b/pkg/multicloud/aws/iam_user.go @@ -22,6 +22,7 @@ import ( "yunion.io/x/pkg/errors" "yunion.io/x/onecloud/pkg/cloudprovider" + "yunion.io/x/onecloud/pkg/multicloud" ) type SUsers struct { @@ -32,6 +33,7 @@ type SUsers struct { type SUser struct { client *SAwsClient + multicloud.SBaseClouduser UserId string `xml:"UserId"` Path string `xml:"Path"` diff --git a/pkg/multicloud/azure/clouduser.go b/pkg/multicloud/azure/clouduser.go index f15daf09c4..96a41a47c0 100644 --- a/pkg/multicloud/azure/clouduser.go +++ b/pkg/multicloud/azure/clouduser.go @@ -23,6 +23,7 @@ import ( "yunion.io/x/pkg/errors" "yunion.io/x/onecloud/pkg/cloudprovider" + "yunion.io/x/onecloud/pkg/multicloud" ) type SClouduserPasswordProfile struct { @@ -33,6 +34,7 @@ type SClouduserPasswordProfile struct { type SClouduser struct { client *SAzureClient + multicloud.SBaseClouduser OdataType string `json:"odata.type"` ObjectType string diff --git a/pkg/multicloud/clouduser.go b/pkg/multicloud/clouduser.go new file mode 100644 index 0000000000..23e222d1a3 --- /dev/null +++ b/pkg/multicloud/clouduser.go @@ -0,0 +1,36 @@ +// Copyright 2019 Yunion +// +// 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 multicloud + +import ( + "yunion.io/x/pkg/errors" + + "yunion.io/x/onecloud/pkg/cloudprovider" +) + +type SBaseClouduser struct { +} + +func (self *SBaseClouduser) CreateAccessKey(name string) (*cloudprovider.SAccessKey, error) { + return nil, errors.Wrap(cloudprovider.ErrNotImplemented, "base CreateAccessKey") +} + +func (self *SBaseClouduser) GetAccessKeys() ([]cloudprovider.SAccessKey, error) { + return nil, errors.Wrap(cloudprovider.ErrNotImplemented, "base GetAccessKeys") +} + +func (self *SBaseClouduser) DeleteAccessKey(accesskey string) error { + return errors.Wrap(cloudprovider.ErrNotImplemented, "base DeleteAccessKey") +} diff --git a/pkg/multicloud/google/iampolicy.go b/pkg/multicloud/google/iampolicy.go index f8356160d6..15f8cc6b07 100644 --- a/pkg/multicloud/google/iampolicy.go +++ b/pkg/multicloud/google/iampolicy.go @@ -39,6 +39,7 @@ import ( "yunion.io/x/pkg/utils" "yunion.io/x/onecloud/pkg/cloudprovider" + "yunion.io/x/onecloud/pkg/multicloud" ) type SBinding struct { @@ -135,6 +136,8 @@ func (self *SGoogleClient) CreateRole(permissions []string, name, desc string) ( } type SClouduser struct { + multicloud.SBaseClouduser + policy *SIamPolicy Name string Roles []string diff --git a/pkg/multicloud/hcso/clouduser.go b/pkg/multicloud/hcso/clouduser.go index 8165ad659b..4965ba205e 100644 --- a/pkg/multicloud/hcso/clouduser.go +++ b/pkg/multicloud/hcso/clouduser.go @@ -219,3 +219,71 @@ func (self *SHuaweiClient) ResetClouduserPassword(id, password string) error { } return client.Users.ResetPassword(id, password) } + +type SAccessKey struct { + client *SHuaweiClient + + AccessKey string `json:"access"` + Secret string `json:"secret"` + Description string `json:"description"` + Status string `json:"status"` +} + +func (self *SHuaweiClient) GetAKSK(id string) ([]cloudprovider.SAccessKey, error) { + obj, err := self.getAKSKList(id) + if err != nil { + return nil, errors.Wrap(err, "SHuaweiClient.getAKSKList") + } + aks := make([]SAccessKey, 0) + obj.Unmarshal(&aks, "credentials") + res := make([]cloudprovider.SAccessKey, len(aks)) + for i := 0; i < len(aks); i++ { + res[i].Name = aks[i].Description + res[i].AccessKey = aks[i].AccessKey + res[i].Secret = aks[i].Secret + res[i].Status = aks[i].Status + } + return res, nil +} + +func (self *SHuaweiClient) CreateAKSK(id, name string) (*cloudprovider.SAccessKey, error) { + params := map[string]interface{}{ + "credential": map[string]interface{}{ + "user_id": id, + "description": name, + }, + } + obj, err := self.createAKSK(params) + if err != nil { + return nil, errors.Wrap(err, "SHuaweiClient.createAKSK") + } + ak := SAccessKey{} + obj.Unmarshal(&ak, "credential") + res := cloudprovider.SAccessKey{ + Name: ak.Description, + AccessKey: ak.AccessKey, + Secret: ak.Secret, + } + return &res, nil +} + +func (self *SHuaweiClient) DeleteAKSK(accessKey string) error { + _, err := self.deleteAKSK(accessKey) + return err +} + +func (user *SClouduser) DeleteAccessKey(accessKey string) error { + err := user.client.DeleteAKSK(accessKey) + if err != nil { + return errors.Wrap(err, "SHuaweiClient.deleteAKSK") + } + return nil +} + +func (user *SClouduser) CreateAccessKey(name string) (*cloudprovider.SAccessKey, error) { + return user.client.CreateAKSK(user.Id, name) +} + +func (user *SClouduser) GetAccessKeys() ([]cloudprovider.SAccessKey, error) { + return user.client.GetAKSK(user.Id) +} diff --git a/pkg/multicloud/hcso/hcso.go b/pkg/multicloud/hcso/hcso.go new file mode 100644 index 0000000000..a8cc217687 --- /dev/null +++ b/pkg/multicloud/hcso/hcso.go @@ -0,0 +1,124 @@ +// Copyright 2019 Yunion +// +// 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 hcso + +import ( + "context" + "fmt" + "net/http" + "net/url" + "strings" + + "github.com/huaweicloud/huaweicloud-sdk-go/auth/aksk" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + "yunion.io/x/onecloud/pkg/cloudprovider" + "yunion.io/x/onecloud/pkg/util/httputils" +) + +type akClient struct { + client *http.Client + aksk aksk.SignOptions +} + +func (self *akClient) Do(req *http.Request) (*http.Response, error) { + req.Header.Del("Accept") + if req.Method == string(httputils.GET) || req.Method == string(httputils.DELETE) || req.Method == string(httputils.PATCH) { + req.Header.Del("Content-Length") + } + aksk.Sign(req, self.aksk) + return self.client.Do(req) +} + +func (self *SHuaweiClient) getAkClient() *akClient { + return &akClient{ + client: self.getDefaultClient(), + aksk: aksk.SignOptions{ + AccessKey: self.accessKey, + SecretKey: self.accessSecret, + }, + } +} + +func (self *SHuaweiClient) getDefaultClient() *http.Client { + if self.httpClient != nil { + return self.httpClient + } + self.httpClient = self.cpcfg.AdaptiveTimeoutHttpClient() + ts, _ := self.httpClient.Transport.(*http.Transport) + self.httpClient.Transport = cloudprovider.GetCheckTransport(ts, func(req *http.Request) (func(resp *http.Response), error) { + service, method, path := strings.Split(req.URL.Host, ".")[0], req.Method, req.URL.Path + respCheck := func(resp *http.Response) { + if resp.StatusCode == 403 { + if self.cpcfg.UpdatePermission != nil { + self.cpcfg.UpdatePermission(service, fmt.Sprintf("%s %s", method, path)) + } + } + } + if self.cpcfg.ReadOnly { + if req.Method == "GET" { + return respCheck, nil + } + return nil, errors.Wrapf(cloudprovider.ErrAccountReadOnly, "%s %s", req.Method, req.URL.Path) + } + return respCheck, nil + }) + return self.httpClient +} + +func (self *SHuaweiClient) request(method httputils.THttpMethod, url string, query url.Values, params map[string]interface{}) (jsonutils.JSONObject, error) { + client := self.getAkClient() + if len(query) > 0 { + url = fmt.Sprintf("%s?%s", url, query.Encode()) + } + var body jsonutils.JSONObject = nil + if len(params) > 0 { + body = jsonutils.Marshal(params) + } + header := http.Header{} + if len(self.projectId) > 0 { + header.Set("X-Project-Id", self.projectId) + } + if strings.Contains(url, "/OS-CREDENTIAL/credentials") && len(self.ownerId) > 0 { + header.Set("X-Domain-Id", self.ownerId) + } + _, resp, err := httputils.JSONRequest(client, context.Background(), method, url, header, body, self.debug) + if err != nil { + if e, ok := err.(*httputils.JSONClientError); ok && e.Code == 404 { + return nil, errors.Wrapf(cloudprovider.ErrNotFound, err.Error()) + } + return nil, err + } + return resp, err +} + +func (self *SHuaweiClient) getAKSKList(userId string) (jsonutils.JSONObject, error) { + uri := fmt.Sprintf("https://%s/v3.0/OS-CREDENTIAL/credentials", self.endpoints.Iam) + query := url.Values{} + query.Set("user_id", userId) + return self.request(httputils.GET, uri, query, nil) +} + +func (self *SHuaweiClient) createAKSK(params map[string]interface{}) (jsonutils.JSONObject, error) { + uri := fmt.Sprintf("https://%s/v3.0/OS-CREDENTIAL/credentials", self.endpoints.Iam) + return self.request(httputils.POST, uri, nil, params) +} + +func (self *SHuaweiClient) deleteAKSK(accessKey string) (jsonutils.JSONObject, error) { + uri := fmt.Sprintf("https://%s/v3.0/OS-CREDENTIAL/credentials/%s", self.endpoints.Iam, accessKey) + return self.request(httputils.POST, uri, nil, nil) +} diff --git a/pkg/multicloud/hcso/huawei.go b/pkg/multicloud/hcso/huawei.go index c6d1d9b321..bebf6691f7 100644 --- a/pkg/multicloud/hcso/huawei.go +++ b/pkg/multicloud/hcso/huawei.go @@ -102,6 +102,8 @@ type SHuaweiClient struct { projects []SProject regions []SRegion + + httpClient *http.Client } // 进行资源操作时参数account 对应数据库cloudprovider表中的account字段,由accessKey和projectID两部分组成,通过"/"分割。 diff --git a/pkg/multicloud/hcso/shell/clouduser.go b/pkg/multicloud/hcso/shell/clouduser.go index f816cdb963..bd56a330e6 100644 --- a/pkg/multicloud/hcso/shell/clouduser.go +++ b/pkg/multicloud/hcso/shell/clouduser.go @@ -86,4 +86,37 @@ func init() { shellutils.R(&ClouduserResetPassword{}, "cloud-user-reset-password", "Reset clouduser password", func(cli *huawei.SRegion, args *ClouduserResetPassword) error { return cli.GetClient().ResetClouduserPassword(args.ID, args.PASSWORD) }) + + type ClouduserAKSKOptions struct { + Id string + } + shellutils.R(&ClouduserAKSKOptions{}, "aksk-list", "List AKSK", func(cli *huawei.SRegion, args *ClouduserAKSKOptions) error { + res, err := cli.GetClient().GetAKSK(args.Id) + if err != nil { + return err + } + printList(res, len(res), 0, 0, []string{}) + return nil + }) + type ClouduserAKSKDeleteOptions struct { + AccessKey string + } + shellutils.R(&ClouduserAKSKDeleteOptions{}, "aksk-delete", "Delete AKSK", func(cli *huawei.SRegion, args *ClouduserAKSKDeleteOptions) error { + err := cli.GetClient().DeleteAKSK(args.AccessKey) + return err + }) + + type AKSKCreateOption struct { + UserId string `help:"user id"` + Description string `help:"description"` + } + + shellutils.R(&AKSKCreateOption{}, "aksk-create", "Create aksk", func(cli *huawei.SRegion, args *AKSKCreateOption) error { + res, err := cli.GetClient().CreateAKSK(args.UserId, args.Description) + if err != nil { + return err + } + printObject(res) + return nil + }) } diff --git a/pkg/multicloud/huawei/clouduser.go b/pkg/multicloud/huawei/clouduser.go index 0221b87558..f36f0cfff8 100644 --- a/pkg/multicloud/huawei/clouduser.go +++ b/pkg/multicloud/huawei/clouduser.go @@ -219,3 +219,67 @@ func (self *SHuaweiClient) ResetClouduserPassword(id, password string) error { } return client.Users.ResetPassword(id, password) } + +type SAccessKey struct { + client *SHuaweiClient + + AccessKey string `json:"access"` + Secret string `json:"secret"` + Description string `json:"description"` + Status string `json:"status"` +} + +func (self *SHuaweiClient) GetAKSK(id string) ([]cloudprovider.SAccessKey, error) { + obj, err := self.getAKSKList(id) + if err != nil { + return nil, errors.Wrap(err, "SHuaweiClient.getAKSKList") + } + aks := make([]SAccessKey, 0) + obj.Unmarshal(&aks, "credentials") + res := make([]cloudprovider.SAccessKey, len(aks)) + for i := 0; i < len(aks); i++ { + res[i].Name = aks[i].Description + res[i].AccessKey = aks[i].AccessKey + res[i].Secret = aks[i].Secret + res[i].Status = aks[i].Status + } + return res, nil +} + +func (self *SHuaweiClient) CreateAKSK(id, name string) (*cloudprovider.SAccessKey, error) { + params := map[string]interface{}{ + "credential": map[string]interface{}{ + "user_id": id, + "description": name, + }, + } + obj, err := self.createAKSK(params) + if err != nil { + return nil, errors.Wrap(err, "SHuaweiClient.createAKSK") + } + ak := SAccessKey{} + obj.Unmarshal(&ak, "credential") + res := cloudprovider.SAccessKey{ + Name: ak.Description, + AccessKey: ak.AccessKey, + Secret: ak.Secret, + } + return &res, nil +} + +func (self *SHuaweiClient) DeleteAKSK(accessKey string) error { + _, err := self.deleteAKSK(accessKey) + return err +} + +func (user *SClouduser) DeleteAccessKey(accessKey string) error { + return user.client.DeleteAKSK(accessKey) +} + +func (user *SClouduser) CreateAccessKey(name string) (*cloudprovider.SAccessKey, error) { + return user.client.CreateAKSK(user.Id, name) +} + +func (user *SClouduser) GetAccessKeys() ([]cloudprovider.SAccessKey, error) { + return user.client.GetAKSK(user.Id) +} diff --git a/pkg/multicloud/huawei/huawei.go b/pkg/multicloud/huawei/huawei.go index 69b12878a1..cff6653c19 100644 --- a/pkg/multicloud/huawei/huawei.go +++ b/pkg/multicloud/huawei/huawei.go @@ -279,6 +279,23 @@ func (self *SHuaweiClient) modelartsResourceflavors(resource string, params map[ return self.request(httputils.GET, uri, url.Values{}, params) } +func (self *SHuaweiClient) getAKSKList(userId string) (jsonutils.JSONObject, error) { + params := url.Values{} + params.Set("user_id", userId) + uri := fmt.Sprintf("https://iam.cn-north-4.myhuaweicloud.com/v3.0/OS-CREDENTIAL/credentials") + return self.request(httputils.GET, uri, params, nil) +} + +func (self *SHuaweiClient) deleteAKSK(accesskey string) (jsonutils.JSONObject, error) { + uri := fmt.Sprintf("https://iam.cn-north-4.myhuaweicloud.com/v3.0/OS-CREDENTIAL/credentials/%s", accesskey) + return self.request(httputils.DELETE, uri, url.Values{}, nil) +} + +func (self *SHuaweiClient) createAKSK(params map[string]interface{}) (jsonutils.JSONObject, error) { + uri := fmt.Sprintf("https://iam.cn-north-4.myhuaweicloud.com/v3.0/OS-CREDENTIAL/credentials") + return self.request(httputils.POST, uri, url.Values{}, params) +} + func (self *SHuaweiClient) lbGet(regionId, resource string) (jsonutils.JSONObject, error) { uri := fmt.Sprintf("https://elb.%s.myhuaweicloud.com/v2/%s/%s", regionId, self.projectId, resource) return self.request(httputils.GET, uri, url.Values{}, nil) @@ -361,9 +378,9 @@ func (self *SHuaweiClient) request(method httputils.THttpMethod, url string, que if len(self.projectId) > 0 { header.Set("X-Project-Id", self.projectId) } - // if len(self.ownerId) > 0 { - // header.Set("X-Domain-Id", self.ownerId) - // } + if strings.Contains(url, "/OS-CREDENTIAL/credentials") && len(self.ownerId) > 0 { + header.Set("X-Domain-Id", self.ownerId) + } _, resp, err := httputils.JSONRequest(client, context.Background(), method, url, header, body, self.debug) if err != nil { if e, ok := err.(*httputils.JSONClientError); ok && e.Code == 404 { diff --git a/pkg/multicloud/huawei/shell/clouduser.go b/pkg/multicloud/huawei/shell/clouduser.go index b056c7b0ab..b6cc65a6b7 100644 --- a/pkg/multicloud/huawei/shell/clouduser.go +++ b/pkg/multicloud/huawei/shell/clouduser.go @@ -86,4 +86,37 @@ func init() { shellutils.R(&ClouduserResetPassword{}, "cloud-user-reset-password", "Reset clouduser password", func(cli *huawei.SRegion, args *ClouduserResetPassword) error { return cli.GetClient().ResetClouduserPassword(args.ID, args.PASSWORD) }) + + type ClouduserAKSKOptions struct { + Id string + } + shellutils.R(&ClouduserAKSKOptions{}, "aksk-list", "List AKSK", func(cli *huawei.SRegion, args *ClouduserAKSKOptions) error { + res, err := cli.GetClient().GetAKSK(args.Id) + if err != nil { + return err + } + printList(res, len(res), 0, 0, []string{}) + return nil + }) + type ClouduserAKSKDeleteOptions struct { + AccessKey string + } + shellutils.R(&ClouduserAKSKDeleteOptions{}, "aksk-delete", "Delete AKSK", func(cli *huawei.SRegion, args *ClouduserAKSKDeleteOptions) error { + err := cli.GetClient().DeleteAKSK(args.AccessKey) + return err + }) + + type AKSKCreateOption struct { + UserId string `help:"user id"` + Description string `help:"description"` + } + + shellutils.R(&AKSKCreateOption{}, "aksk-create", "Create aksk", func(cli *huawei.SRegion, args *AKSKCreateOption) error { + res, err := cli.GetClient().CreateAKSK(args.UserId, args.Description) + if err != nil { + return err + } + printObject(res) + return nil + }) } diff --git a/pkg/multicloud/qcloud/cam_user.go b/pkg/multicloud/qcloud/cam_user.go index 13275ea46b..3896411a75 100644 --- a/pkg/multicloud/qcloud/cam_user.go +++ b/pkg/multicloud/qcloud/cam_user.go @@ -21,9 +21,11 @@ import ( "yunion.io/x/pkg/errors" "yunion.io/x/onecloud/pkg/cloudprovider" + "yunion.io/x/onecloud/pkg/multicloud" ) type SUser struct { + multicloud.SBaseClouduser client *SQcloudClient Uin int64