fix(cloudid): vendor update form volcengine iam (#19856)

This commit is contained in:
屈轩
2024-04-02 14:39:18 +08:00
committed by GitHub
parent f57e69e6b3
commit 4f43e6d121
27 changed files with 1586 additions and 112 deletions
+1 -1
View File
@@ -88,7 +88,7 @@ require (
k8s.io/client-go v0.19.3
k8s.io/cluster-bootstrap v0.19.3
moul.io/http2curl/v2 v2.3.0
yunion.io/x/cloudmux v0.3.10-0-alpha.1.0.20240401032225-9a152ed52202
yunion.io/x/cloudmux v0.3.10-0-alpha.1.0.20240402061507-4922cc681244
yunion.io/x/executor v0.0.0-20230705125604-c5ac3141db32
yunion.io/x/jsonutils v1.0.1-0.20240203102553-4096f103b401
yunion.io/x/log v1.0.1-0.20240305175729-7cf2d6cd5a91
+2 -2
View File
@@ -1204,8 +1204,8 @@ sigs.k8s.io/structured-merge-diff/v4 v4.0.1/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK
sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q=
sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc=
yunion.io/x/cloudmux v0.3.10-0-alpha.1.0.20240401032225-9a152ed52202 h1:nufuDeVPNxkYT8IbVbkwSb4SbGYxWV1w1DhrhR7++tE=
yunion.io/x/cloudmux v0.3.10-0-alpha.1.0.20240401032225-9a152ed52202/go.mod h1:dsUESXIbXJ+/ywbNClhldOrbPOiBi2udrgOnB/ffoWk=
yunion.io/x/cloudmux v0.3.10-0-alpha.1.0.20240402061507-4922cc681244 h1:b63UITGOFheDihKXXzF1fPX/Cgb/zDa3a93cs9pmmkA=
yunion.io/x/cloudmux v0.3.10-0-alpha.1.0.20240402061507-4922cc681244/go.mod h1:dsUESXIbXJ+/ywbNClhldOrbPOiBi2udrgOnB/ffoWk=
yunion.io/x/executor v0.0.0-20230705125604-c5ac3141db32 h1:v7POYkQwo1XzOxBoIoRVr/k0V9Y5JyjpshlIFa9raug=
yunion.io/x/executor v0.0.0-20230705125604-c5ac3141db32/go.mod h1:Uxuou9WQIeJXNpy7t2fPLL0BYLvLiMvGQwY7Qc6aSws=
yunion.io/x/jsonutils v0.0.0-20190625054549-a964e1e8a051/go.mod h1:4N0/RVzsYL3kH3WE/H1BjUQdFiWu50JGCFQuuy+Z634=
+44 -4
View File
@@ -22,6 +22,7 @@ import (
"yunion.io/x/cloudmux/pkg/cloudprovider"
"yunion.io/x/log"
"yunion.io/x/pkg/errors"
"yunion.io/x/pkg/utils"
"yunion.io/x/onecloud/pkg/apis"
api "yunion.io/x/onecloud/pkg/apis/cloudid"
@@ -436,7 +437,7 @@ func (base SProviderBaseProviderDriver) RequestCreateClouduser(ctx context.Conte
iUser, err := provider.CreateIClouduser(opts)
if err != nil {
return errors.Wrapf(err, "CreateICloudgroup")
return errors.Wrapf(err, "CreateIClouduser")
}
_, err = db.Update(user, func() error {
user.ExternalId = iUser.GetGlobalId()
@@ -537,8 +538,11 @@ func (base SProviderBaseProviderDriver) RequestCreateSAMLProvider(ctx context.Co
opts := &cloudprovider.SAMLProviderCreateOptions{
Metadata: models.SamlIdpInstance().GetMetadata(providers[i].Id),
Name: strings.TrimPrefix(options.Options.ApiServer, "https://"),
Desc: "create by cloudpods",
}
log.Debugf("create saml provider for manager %s(%s) %s", providers[i].Name, providers[i].Id, opts.Metadata.String())
opts.Name = strings.TrimPrefix(opts.Name, "http://")
iSaml, err := iProvider.CreateICloudSAMLProvider(opts)
@@ -577,17 +581,44 @@ func (base SProviderBaseProviderDriver) RequestCreateRoleForSamlUser(ctx context
if err != nil {
return errors.Wrapf(err, "GetSamlProvider")
}
policies, err := group.GetCloudpolicies()
if err != nil {
return errors.Wrapf(err, "GetCloudpolicies")
}
roles, err := account.GetCloudroles(provider.Id)
if err != nil {
return errors.Wrapf(err, "GetCloudroles")
}
for i := range roles {
if roles[i].Status == apis.STATUS_AVAILABLE && len(roles[i].ExternalId) > 0 && roles[i].SAMLProviderId == samlProvider.Id {
if roles[i].Status == apis.STATUS_AVAILABLE && len(roles[i].ExternalId) > 0 && roles[i].SAMLProviderId == samlProvider.Id && roles[i].CloudgroupId == group.Id {
_, err := db.Update(user, func() error {
user.CloudroleId = roles[i].Id
return nil
})
return err
if err != nil {
return err
}
existPolicies := []string{}
iRole, err := roles[i].GetICloudrole()
if err != nil {
return err
}
iPolicies, err := iRole.GetICloudpolicies()
if err != nil {
return errors.Wrapf(err, "GetICloudpolicies")
}
for _, policy := range iPolicies {
existPolicies = append(existPolicies, policy.GetGlobalId())
}
for _, policy := range policies {
if !utils.IsInStringArray(policy.ExternalId, existPolicies) {
err = iRole.AttachPolicy(policy.ExternalId, policy.PolicyType)
if err != nil {
return errors.Wrapf(err, "attach %s policy %s", policy.PolicyType, policy.ExternalId)
}
}
}
return nil
}
}
iProvider, err := group.GetProvider()
@@ -622,5 +653,14 @@ func (base SProviderBaseProviderDriver) RequestCreateRoleForSamlUser(ctx context
user.CloudroleId = role.Id
return nil
})
return err
if err != nil {
return err
}
for _, policy := range policies {
err := iRole.AttachPolicy(policy.ExternalId, policy.PolicyType)
if err != nil {
return errors.Wrapf(err, "attach %s policy %s", policy.PolicyType, policy.ExternalId)
}
}
return nil
}
+32
View File
@@ -0,0 +1,32 @@
// 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 drivers
import (
api "yunion.io/x/onecloud/pkg/apis/compute"
"yunion.io/x/onecloud/pkg/cloudid/models"
)
type SVolcEngineDriver struct {
SProviderBaseProviderDriver
}
func (driver SVolcEngineDriver) GetProvider() string {
return api.CLOUD_PROVIDER_VOLCENGINE
}
func init() {
models.RegisterProviderDriver(&SVolcEngineDriver{})
}
-26
View File
@@ -18,7 +18,6 @@ import (
"context"
"database/sql"
"fmt"
"net/url"
"strings"
"yunion.io/x/cloudmux/pkg/cloudprovider"
@@ -29,7 +28,6 @@ import (
"yunion.io/x/onecloud/pkg/apis"
api "yunion.io/x/onecloud/pkg/apis/cloudid"
computeapi "yunion.io/x/onecloud/pkg/apis/compute"
"yunion.io/x/onecloud/pkg/cloudcommon/db"
"yunion.io/x/onecloud/pkg/cloudcommon/db/taskman"
"yunion.io/x/onecloud/pkg/cloudid/options"
@@ -77,30 +75,6 @@ func (manager *SCloudaccountManager) GetResourceCount() ([]db.SScopeResourceCoun
return []db.SScopeResourceCount{}, nil
}
func (self *SCloudaccount) GetClouduserAccountName(name string) (string, string) {
account := ""
switch self.Provider {
case computeapi.CLOUD_PROVIDER_ALIYUN:
suffix := strings.TrimPrefix(self.IamLoginUrl, "https://signin.aliyun.com/")
suffix = strings.TrimSuffix(suffix, "/login.htm")
if len(suffix) > 0 {
name = fmt.Sprintf("%s@%s", name, suffix)
account = suffix
}
case computeapi.CLOUD_PROVIDER_QCLOUD, computeapi.CLOUD_PROVIDER_HUAWEI:
u, _ := url.Parse(self.IamLoginUrl)
if u != nil {
account = u.Query().Get("account")
}
case computeapi.CLOUD_PROVIDER_AWS:
account := strings.TrimPrefix(self.IamLoginUrl, "https://")
if info := strings.Split(account, "."); len(info) > 0 {
account = info[0]
}
}
return account, name
}
func (manager *SCloudaccountManager) GetCloudaccounts() ([]SCloudaccount, error) {
accounts := []SCloudaccount{}
q := manager.Query()
+1
View File
@@ -85,6 +85,7 @@ func GetMetadata(driver ICloudSAMLLoginDriver) ([]byte, error) {
if err != nil {
return nil, errors.Wrapf(err, "read body %s fail", metaUrl)
}
os.WriteFile(filePath, metaBytes, 0644)
} else {
return nil, errors.Wrapf(err, "read file %s fail", filePath)
}
+1
View File
@@ -22,4 +22,5 @@ import (
_ "yunion.io/x/onecloud/pkg/cloudid/saml/providers/google"
_ "yunion.io/x/onecloud/pkg/cloudid/saml/providers/huawei"
_ "yunion.io/x/onecloud/pkg/cloudid/saml/providers/qcloud"
_ "yunion.io/x/onecloud/pkg/cloudid/saml/providers/volcengine"
)
@@ -0,0 +1 @@
package volcengine // import "yunion.io/x/onecloud/pkg/cloudid/saml/providers/volcengine"
@@ -0,0 +1,95 @@
// 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 volcengine
import (
"context"
"fmt"
"yunion.io/x/pkg/errors"
"yunion.io/x/pkg/util/samlutils"
"yunion.io/x/onecloud/pkg/cloudid/models"
"yunion.io/x/onecloud/pkg/mcclient"
"yunion.io/x/onecloud/pkg/util/samlutils/idp"
)
func (d *SVolcEngineSAMLDriver) GetIdpInitiatedLoginData(ctx context.Context, userCred mcclient.TokenCredential, managerId string, sp *idp.SSAMLServiceProvider, redirectUrl string) (samlutils.SSAMLIdpInitiatedLoginData, error) {
data := samlutils.SSAMLIdpInitiatedLoginData{}
provider, err := models.CloudproviderManager.FetchProvier(managerId)
if err != nil {
return data, err
}
account, err := provider.GetCloudaccount()
if err != nil {
return data, errors.Wrapf(err, "GetCloudaccount")
}
role, err := provider.GetRole(ctx, userCred.GetUserId())
if err != nil {
return data, err
}
samlProvider, err := provider.GetSamlProvider()
if err != nil {
return data, err
}
// trn:iam::${AccountID}:role/${RoleName},trn:iam::${AccountID}:saml-provider/${SAMLProviderName}
roleStr := fmt.Sprintf("trn:iam::%s:role/%s,trn:iam::%s:saml-provider/%s", account.AccountId, role.ExternalId, account.AccountId, samlProvider.ExternalId)
data.NameId = role.Name
data.NameIdFormat = samlutils.NAME_ID_FORMAT_TRANSIENT
data.AudienceRestriction = "https://console.volcengine.com"
for _, v := range []struct {
name string
friendlyName string
value string
}{
{
name: "https://www.volcengine.com/SAML/Attributes/Identity",
friendlyName: "RoleEntitlement",
value: roleStr,
},
{
name: "https://www.volcengine.com/SAML/Attributes/SessionName",
friendlyName: "SessionName",
value: role.Name,
},
{
name: "https://www.volcengine.com/SAML/Attributes/SessionDuration",
friendlyName: "SessionDuration",
value: "7200",
},
} {
data.Attributes = append(data.Attributes, samlutils.SSAMLResponseAttribute{
Name: v.name,
FriendlyName: v.friendlyName,
Values: []string{v.value},
})
}
if len(redirectUrl) == 0 {
redirectUrl = "https://console.volcengine.com"
}
data.RelayState = redirectUrl
return data, nil
}
func (d *SVolcEngineSAMLDriver) GetSpInitiatedLoginData(ctx context.Context, userCred mcclient.TokenCredential, managerId string, sp *idp.SSAMLServiceProvider) (samlutils.SSAMLSpInitiatedLoginData, error) {
return samlutils.SSAMLSpInitiatedLoginData{}, errors.ErrNotSupported
}
@@ -0,0 +1,39 @@
// 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 volcengine
import (
"yunion.io/x/cloudmux/pkg/cloudprovider"
"yunion.io/x/onecloud/pkg/cloudid/models"
)
type SVolcEngineSAMLDriver struct{}
func (d *SVolcEngineSAMLDriver) GetEntityID() string {
return cloudprovider.SAML_ENTITY_ID_VOLC_ENGINE
}
func (d *SVolcEngineSAMLDriver) GetMetadataFilename() string {
return "volcengine.xml"
}
func (d *SVolcEngineSAMLDriver) GetMetadataUrl() string {
return "https://signin.volcengine.com/saml_role/SpMetadata.xml"
}
func init() {
models.Register(&SVolcEngineSAMLDriver{})
}
+2 -2
View File
@@ -85,8 +85,8 @@ func StartService() {
if !opts.IsSlaveNode {
cron := cronman.InitCronJobManager(true, options.Options.CronJobWorkerCount)
cron.AddJobAtIntervalsWithStartRun("SyncCloudaccountResources", time.Duration(opts.CloudIdResourceSyncIntervalHours)*time.Hour, models.CloudaccountManager.SyncCloudaccountResources, false)
cron.AddJobAtIntervalsWithStartRun("SyncCloudproviderResources", time.Duration(opts.CloudIdResourceSyncIntervalHours)*time.Hour, models.CloudproviderManager.SyncCloudproviderResources, false)
cron.AddJobAtIntervalsWithStartRun("SyncCloudaccountResources", time.Duration(opts.CloudIdResourceSyncIntervalHours)*time.Hour, models.CloudaccountManager.SyncCloudaccountResources, true)
cron.AddJobAtIntervalsWithStartRun("SyncCloudproviderResources", time.Duration(opts.CloudIdResourceSyncIntervalHours)*time.Hour, models.CloudproviderManager.SyncCloudproviderResources, true)
cron.AddJobEveryFewHour("AutoPurgeSplitable", 4, 30, 0, db.AutoPurgeSplitable, false)
@@ -80,7 +80,7 @@ func (self *CloudgroupSetPoliciesTask) OnInit(ctx context.Context, obj db.IStand
for _, policy := range input.Add {
for id, role := range iRoleMap {
err := role.AttachPolicy(policy.ExternalId)
err := role.AttachPolicy(policy.ExternalId, policy.PolicyType)
if err != nil {
logclient.AddSimpleActionLog(roleMap[id], logclient.ACT_ATTACH_POLICY, err, self.GetUserCred(), false)
}
@@ -99,7 +99,7 @@ func (self *CloudgroupSetPoliciesTask) OnInit(ctx context.Context, obj db.IStand
for _, policy := range input.Del {
for id, role := range iRoleMap {
err := role.DetachPolicy(policy.ExternalId)
err := role.DetachPolicy(policy.ExternalId, policy.PolicyType)
if err != nil {
logclient.AddSimpleActionLog(roleMap[id], logclient.ACT_DETACH_POLICY, err, self.GetUserCred(), false)
}
+1 -1
View File
@@ -82,9 +82,9 @@ func (self *ClouduserCreateTask) OnInit(ctx context.Context, obj db.IStandaloneM
}{
Id: self.Id,
IamLoginUrl: account.IamLoginUrl,
Account: account.AccountId,
}
msg.Password, _ = user.GetPassword()
msg.Account, msg.Name = account.GetClouduserAccountName(user.Name)
notifyclient.NotifyWithContact(ctx, []string{user.Email}, npk.NotifyByEmail, npk.NotifyPriorityNormal, "CLOUD_USER_CREATED", jsonutils.Marshal(msg))
}
+1 -1
View File
@@ -1472,7 +1472,7 @@ sigs.k8s.io/structured-merge-diff/v4/value
# sigs.k8s.io/yaml v1.2.0
## explicit; go 1.12
sigs.k8s.io/yaml
# yunion.io/x/cloudmux v0.3.10-0-alpha.1.0.20240401032225-9a152ed52202
# yunion.io/x/cloudmux v0.3.10-0-alpha.1.0.20240402061507-4922cc681244
## explicit; go 1.18
yunion.io/x/cloudmux/pkg/apis
yunion.io/x/cloudmux/pkg/apis/billing
+2 -2
View File
@@ -1369,8 +1369,8 @@ type ICloudrole interface {
GetSAMLProvider() string
GetICloudpolicies() ([]ICloudpolicy, error)
AttachPolicy(id string) error
DetachPolicy(id string) error
AttachPolicy(policyName string, policyType string) error
DetachPolicy(policyName string, policyType string) error
Delete() error
}
+2
View File
@@ -24,9 +24,11 @@ const (
SAML_ENTITY_ID_HUAWEI_CLOUD = "https://auth.huaweicloud.com/"
SAML_ENTITY_ID_GOOGLE = "google.com"
SAML_ENTITY_ID_AZURE = "urn:federation:MicrosoftOnline"
SAML_ENTITY_ID_VOLC_ENGINE = "https://www.volcengine.com/"
)
type SAMLProviderCreateOptions struct {
Name string
Metadata samlutils.EntityDescriptor
Desc string
}
+5 -4
View File
@@ -20,6 +20,7 @@ import (
"yunion.io/x/jsonutils"
"yunion.io/x/pkg/errors"
"yunion.io/x/pkg/utils"
"yunion.io/x/cloudmux/pkg/cloudprovider"
)
@@ -67,12 +68,12 @@ func (self *SRole) GetICloudpolicies() ([]cloudprovider.ICloudpolicy, error) {
return ret, nil
}
func (self *SRole) AttachPolicy(policyName string) error {
return self.client.AttachPolicy2Role("System", policyName, self.RoleName)
func (self *SRole) AttachPolicy(policyName string, policyType string) error {
return self.client.AttachPolicy2Role(utils.Capitalize(policyType), policyName, self.RoleName)
}
func (self *SRole) DetachPolicy(policyName string) error {
return self.client.DetachPolicyFromRole("System", policyName, self.RoleName)
func (self *SRole) DetachPolicy(policyName string, policyType string) error {
return self.client.DetachPolicyFromRole(utils.Capitalize(policyType), policyName, self.RoleName)
}
func (self *SRole) Delete() error {
+2 -2
View File
@@ -88,11 +88,11 @@ func (self *SRole) GetSAMLProvider() string {
return ""
}
func (self *SRole) AttachPolicy(id string) error {
func (self *SRole) AttachPolicy(id string, policyType string) error {
return self.client.AttachRolePolicy(self.RoleName, self.client.getIamArn(id))
}
func (self *SRole) DetachPolicy(id string) error {
func (self *SRole) DetachPolicy(id string, polityType string) error {
return self.client.DetachRolePolicy(self.RoleName, self.client.getIamArn(id))
}
+2 -2
View File
@@ -128,11 +128,11 @@ func (self *SRole) GetICloudpolicies() ([]cloudprovider.ICloudpolicy, error) {
return ret, nil
}
func (self *SRole) AttachPolicy(id string) error {
func (self *SRole) AttachPolicy(id string, policyType string) error {
return self.client.AttachRolePolicy(self.RoleName, id)
}
func (self *SRole) DetachPolicy(id string) error {
func (self *SRole) DetachPolicy(id string, policyType string) error {
return self.client.DetachRolePolicy(self.RoleName, id)
}
+298
View File
@@ -0,0 +1,298 @@
// 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 volcengine
import (
"fmt"
"yunion.io/x/cloudmux/pkg/cloudprovider"
)
type SGroup struct {
client *SVolcEngineClient
Description string
CreatedDate string
UserGroupName string
UpdateDate string
AccountId string
UserGroupId string
}
func (self *SGroup) GetName() string {
return self.UserGroupName
}
func (self *SGroup) GetGlobalId() string {
return self.UserGroupName
}
func (self *SGroup) GetDescription() string {
return self.Description
}
func (self *SGroup) GetICloudusers() ([]cloudprovider.IClouduser, error) {
users, err := self.client.ListUsersForGroup(self.UserGroupName)
if err != nil {
return nil, err
}
ret := []cloudprovider.IClouduser{}
for i := range users {
users[i].client = self.client
ret = append(ret, &users[i])
}
return ret, nil
}
func (self *SGroup) GetISystemCloudpolicies() ([]cloudprovider.ICloudpolicy, error) {
policies, err := self.client.ListAttachedUserGroupPolicies(self.UserGroupName)
if err != nil {
return nil, err
}
ret := []cloudprovider.ICloudpolicy{}
for i := range policies {
policies[i].client = self.client
if policies[i].PolicyType == "System" {
ret = append(ret, &policies[i])
}
}
return ret, nil
}
func (self *SGroup) GetICustomCloudpolicies() ([]cloudprovider.ICloudpolicy, error) {
policies, err := self.client.ListAttachedUserGroupPolicies(self.UserGroupName)
if err != nil {
return nil, err
}
ret := []cloudprovider.ICloudpolicy{}
for i := range policies {
policies[i].client = self.client
if policies[i].PolicyType == "Custom" {
ret = append(ret, &policies[i])
}
}
return ret, nil
}
func (self *SGroup) AddUser(name string) error {
return self.client.AddUserToGroup(name, self.UserGroupName)
}
func (self *SGroup) RemoveUser(name string) error {
return self.client.RemoveUserFromGroup(name, self.UserGroupName)
}
func (self *SGroup) AttachSystemPolicy(policyName string) error {
return self.client.AttachUserGroupPolicy(self.UserGroupName, policyName, "System")
}
func (self *SGroup) AttachCustomPolicy(policyName string) error {
return self.client.AttachUserGroupPolicy(self.UserGroupName, policyName, "Custom")
}
func (self *SGroup) DetachSystemPolicy(policyName string) error {
return self.client.DetachUserGroupPolicy(self.UserGroupName, policyName, "System")
}
func (self *SGroup) DetachCustomPolicy(policyName string) error {
return self.client.DetachUserGroupPolicy(self.UserGroupName, policyName, "Custom")
}
func (self *SGroup) Delete() error {
return self.client.DeleteGroup(self.UserGroupName)
}
func (self *SVolcEngineClient) CreateICloudgroup(name string, desc string) (cloudprovider.ICloudgroup, error) {
group, err := self.CreateGroup(name, desc)
if err != nil {
return nil, err
}
return group, nil
}
func (self *SVolcEngineClient) GetICloudgroups() ([]cloudprovider.ICloudgroup, error) {
groups, err := self.ListGroups()
if err != nil {
return nil, err
}
ret := []cloudprovider.ICloudgroup{}
for i := range groups {
groups[i].client = self
ret = append(ret, &groups[i])
}
return ret, nil
}
func (client *SVolcEngineClient) ListGroups() ([]SGroup, error) {
params := map[string]string{
"Limit": "50",
}
offset := 0
ret := []SGroup{}
for {
params["Offset"] = fmt.Sprintf("%d", offset)
resp, err := client.iamRequest("", "ListGroups", params)
if err != nil {
return nil, err
}
part := struct {
UserGroups []SGroup
Total int
}{}
err = resp.Unmarshal(&part)
if err != nil {
return nil, err
}
ret = append(ret, part.UserGroups...)
if len(part.UserGroups) == 0 || len(ret) >= part.Total {
break
}
offset = len(ret)
}
return ret, nil
}
func (client *SVolcEngineClient) ListUsersForGroup(name string) ([]SUser, error) {
params := map[string]string{
"Limit": "50",
"UserGroupName": name,
}
offset := 0
ret := []SUser{}
for {
params["Offset"] = fmt.Sprintf("%d", offset)
resp, err := client.iamRequest("", "ListUsersForGroup", params)
if err != nil {
return nil, err
}
part := struct {
Users []SUser
Total int
}{}
err = resp.Unmarshal(&part)
if err != nil {
return nil, err
}
ret = append(ret, part.Users...)
if len(part.Users) == 0 || len(ret) >= part.Total {
break
}
offset = len(ret)
}
return ret, nil
}
func (client *SVolcEngineClient) ListAttachedUserGroupPolicies(name string) ([]SPolicy, error) {
params := map[string]string{
"UserGroupName": name,
}
resp, err := client.iamRequest("", "ListAttachedUserGroupPolicies", params)
if err != nil {
return nil, err
}
ret := []SPolicy{}
err = resp.Unmarshal(&ret, "AttachedPolicyMetadata")
if err != nil {
return nil, err
}
return ret, nil
}
func (client *SVolcEngineClient) AttachUserGroupPolicy(name, policy, policyType string) error {
params := map[string]string{
"UserGroupName": name,
"PolicyName": policy,
"PolicyType": policyType,
}
_, err := client.iamRequest("", "AttachUserGroupPolicy", params)
return err
}
func (client *SVolcEngineClient) DetachUserGroupPolicy(name, policy, policyType string) error {
params := map[string]string{
"UserGroupName": name,
"PolicyName": policy,
"PolicyType": policyType,
}
_, err := client.iamRequest("", "DetachUserGroupPolicy", params)
return err
}
func (client *SVolcEngineClient) DeleteGroup(name string) error {
params := map[string]string{
"UserGroupName": name,
}
_, err := client.iamRequest("", "DeleteGroup", params)
return err
}
func (client *SVolcEngineClient) AddUserToGroup(user, group string) error {
params := map[string]string{
"UserGroupName": group,
"UserName": user,
}
_, err := client.iamRequest("", "AddUserToGroup", params)
return err
}
func (client *SVolcEngineClient) RemoveUserFromGroup(user, group string) error {
params := map[string]string{
"UserGroupName": group,
"UserName": user,
}
_, err := client.iamRequest("", "RemoveUserFromGroup", params)
return err
}
func (client *SVolcEngineClient) CreateGroup(name, desc string) (*SGroup, error) {
params := map[string]string{
"UserGroupName": name,
"Description": desc,
}
resp, err := client.iamRequest("", "CreateGroup", params)
if err != nil {
return nil, err
}
ret := &SGroup{client: client}
err = resp.Unmarshal(ret, "UserGroup")
if err != nil {
return nil, err
}
return ret, nil
}
func (client *SVolcEngineClient) GetICloudgroupByName(name string) (cloudprovider.ICloudgroup, error) {
group, err := client.GetGroup(name)
if err != nil {
return nil, err
}
return group, nil
}
func (client *SVolcEngineClient) GetGroup(name string) (*SGroup, error) {
params := map[string]string{
"UserGroupName": name,
}
resp, err := client.iamRequest("", "GetGroup", params)
if err != nil {
return nil, err
}
ret := &SGroup{client: client}
err = resp.Unmarshal(ret, "UserGroup")
if err != nil {
return nil, err
}
return ret, nil
}
+143
View File
@@ -0,0 +1,143 @@
// 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 volcengine
import (
"fmt"
"yunion.io/x/jsonutils"
"yunion.io/x/pkg/errors"
"yunion.io/x/cloudmux/pkg/cloudprovider"
)
const (
POLICY_TYPE_SYSTEM = "System"
POLICY_TYPE_CUSTOM = "Custom"
)
type SPolicy struct {
client *SVolcEngineClient
CreateDate string
UpdateDate string
PolicyDocument string
Status string
PolicyName string
PolicyType string
Description string
Category string
IsServiceRolePolicy int
AttachmentCount int
}
func (policy *SPolicy) GetName() string {
return policy.PolicyName
}
func (policy *SPolicy) GetDescription() string {
return policy.Description
}
func (policy *SPolicy) GetGlobalId() string {
return policy.PolicyName
}
func (policy *SPolicy) UpdateDocument(document *jsonutils.JSONDict) error {
return cloudprovider.ErrNotImplemented
}
func (policy *SPolicy) Delete() error {
return policy.client.DeletePolicy(policy.PolicyName)
}
func (policy *SPolicy) GetDocument() (*jsonutils.JSONDict, error) {
doc, err := jsonutils.Parse([]byte(policy.PolicyDocument))
if err != nil {
return nil, err
}
ret, ok := doc.(*jsonutils.JSONDict)
if !ok {
return nil, errors.Wrapf(cloudprovider.ErrNotSupported, policy.PolicyDocument)
}
return ret, nil
}
func (self *SVolcEngineClient) GetISystemCloudpolicies() ([]cloudprovider.ICloudpolicy, error) {
policies, err := self.ListPolicies("System")
if err != nil {
return nil, err
}
ret := []cloudprovider.ICloudpolicy{}
for i := range policies {
policies[i].client = self
ret = append(ret, &policies[i])
}
return ret, nil
}
func (self *SVolcEngineClient) GetICustomCloudpolicies() ([]cloudprovider.ICloudpolicy, error) {
policies, err := self.ListPolicies("Custom")
if err != nil {
return nil, err
}
ret := []cloudprovider.ICloudpolicy{}
for i := range policies {
policies[i].client = self
ret = append(ret, &policies[i])
}
return ret, nil
}
func (client *SVolcEngineClient) ListPolicies(scope string) ([]SPolicy, error) {
params := map[string]string{
"Limit": "50",
}
if len(scope) > 0 {
params["Scope"] = scope
}
offset := 0
ret := []SPolicy{}
for {
params["Offset"] = fmt.Sprintf("%d", offset)
resp, err := client.iamRequest("", "ListPolicies", params)
if err != nil {
return nil, err
}
part := struct {
PolicyMetadata []SPolicy
Total int
}{}
err = resp.Unmarshal(&part)
if err != nil {
return nil, err
}
ret = append(ret, part.PolicyMetadata...)
if len(part.PolicyMetadata) == 0 || len(ret) >= part.Total {
break
}
offset = len(ret)
}
return ret, nil
}
func (client *SVolcEngineClient) DeletePolicy(name string) error {
params := map[string]string{
"PolicyName": name,
}
_, err := client.iamRequest("", "DeletePolicy", params)
return err
}
+5 -5
View File
@@ -36,8 +36,8 @@ type SProject struct {
Path string
DisplayName string
Description string
CreateDate time.Time
UpdateDate time.Time
CreateDate string
UpdateDate string
Status string
}
@@ -77,7 +77,7 @@ func (client *SVolcEngineClient) GetProject(name string) (*SProject, error) {
params := map[string]string{
"ProjectName": name,
}
body, err := client.iamRequest("", "GetProject", params)
body, err := client.iam20210801Request("", "GetProject", params)
if err != nil {
return nil, err
}
@@ -97,7 +97,7 @@ func (client *SVolcEngineClient) ListProjects(limit int, offset int) ([]SProject
"Limit": fmt.Sprintf("%d", limit),
"Offset": fmt.Sprintf("%d", offset),
}
resp, err := client.iamRequest("", "ListProjects", params)
resp, err := client.iam20210801Request("", "ListProjects", params)
if err != nil {
return nil, 0, errors.Wrap(err, "iamRequest.ListProjects")
}
@@ -123,7 +123,7 @@ func (client *SVolcEngineClient) CreateProject(name string) (*SProject, error) {
"DisplayName": name,
"ProjectName": name,
}
resp, err := client.iamRequest("", "CreateProject", params)
resp, err := client.iam20210801Request("", "CreateProject", params)
if err != nil {
return nil, errors.Wrap(err, "CreateProject")
}
@@ -16,6 +16,7 @@ package volcengine
import (
"context"
"fmt"
"strings"
"yunion.io/x/pkg/errors"
@@ -66,6 +67,10 @@ func (f *SVolcEngineProviderFactory) ValidateUpdateCloudaccountCredential(ctx co
return output, nil
}
func (factory *SVolcEngineProviderFactory) IsSupportSAMLAuth() bool {
return true
}
func validateClientCloudenv(client *volcengine.SVolcEngineClient) error {
regions := client.GetIRegions()
if len(regions) == 0 {
@@ -210,3 +215,76 @@ func (self *SVolcEngineProvider) GetVersion() string {
func (self *SVolcEngineProvider) GetMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) {
return self.client.GetMetrics(opts)
}
func (self *SVolcEngineProvider) CreateICloudSAMLProvider(opts *cloudprovider.SAMLProviderCreateOptions) (cloudprovider.ICloudSAMLProvider, error) {
sp, err := self.client.CreateSAMLProvider(opts.Name, opts.Metadata.String(), opts.Desc)
if err != nil {
return nil, errors.Wrapf(err, "CreateSAMLProvider")
}
return sp, nil
}
func (self *SVolcEngineProvider) GetICloudSAMLProviders() ([]cloudprovider.ICloudSAMLProvider, error) {
return self.client.GetICloudSAMLProviders()
}
func (self *SVolcEngineProvider) GetICloudroles() ([]cloudprovider.ICloudrole, error) {
return self.client.GetICloudroles()
}
func (self *SVolcEngineProvider) GetICloudroleById(id string) (cloudprovider.ICloudrole, error) {
role, err := self.client.GetRole(id)
if err != nil {
return nil, errors.Wrapf(err, "GetRole(%s)", id)
}
return role, nil
}
func (self *SVolcEngineProvider) CreateICloudrole(opts *cloudprovider.SRoleCreateOptions) (cloudprovider.ICloudrole, error) {
stetement := fmt.Sprintf(`{"Statement":[{"Effect":"Allow","Action":["sts:AssumeRoleWithSAML"],"Principal":{"Federated":["trn:iam::%s:saml-provider/%s"]}}]}`, self.client.GetAccountId(), opts.SAMLProvider)
role, err := self.client.CreateRole(opts.Name, stetement, opts.Desc)
if err != nil {
return nil, errors.Wrapf(err, "CreateRole")
}
return role, nil
}
func (self *SVolcEngineProvider) CreateIClouduser(conf *cloudprovider.SClouduserCreateConfig) (cloudprovider.IClouduser, error) {
return self.client.CreateIClouduser(conf)
}
func (self *SVolcEngineProvider) GetICloudusers() ([]cloudprovider.IClouduser, error) {
return self.client.GetICloudusers()
}
func (self *SVolcEngineProvider) GetIClouduserByName(name string) (cloudprovider.IClouduser, error) {
return self.client.GetIClouduserByName(name)
}
func (self *SVolcEngineProvider) GetICloudgroups() ([]cloudprovider.ICloudgroup, error) {
return self.client.GetICloudgroups()
}
func (self *SVolcEngineProvider) CreateICloudgroup(name, desc string) (cloudprovider.ICloudgroup, error) {
return self.client.CreateICloudgroup(name, desc)
}
func (self *SVolcEngineProvider) GetICloudgroupByName(name string) (cloudprovider.ICloudgroup, error) {
return self.client.GetICloudgroupByName(name)
}
func (self *SVolcEngineProvider) GetISystemCloudpolicies() ([]cloudprovider.ICloudpolicy, error) {
return self.client.GetISystemCloudpolicies()
}
func (self *SVolcEngineProvider) GetICustomCloudpolicies() ([]cloudprovider.ICloudpolicy, error) {
return self.client.GetICustomCloudpolicies()
}
func (self *SVolcEngineProvider) CreateICloudpolicy(opts *cloudprovider.SCloudpolicyCreateOptions) (cloudprovider.ICloudpolicy, error) {
return nil, cloudprovider.ErrNotImplemented
}
func (self *SVolcEngineProvider) GetSamlEntityId() string {
return cloudprovider.SAML_ENTITY_ID_VOLC_ENGINE
}
+224
View File
@@ -0,0 +1,224 @@
// 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 volcengine
import (
"fmt"
"strings"
"yunion.io/x/jsonutils"
"yunion.io/x/pkg/utils"
"yunion.io/x/cloudmux/pkg/cloudprovider"
)
type PolicyDocument struct {
Statement []struct {
Effect string
Action []string
Principal struct {
Federated []string
}
}
}
type SRole struct {
client *SVolcEngineClient
RoleName string
DisplayName string
TrustPolicyDocument string
Description string
}
func (self *SRole) GetGlobalId() string {
return self.RoleName
}
func (self *SRole) GetName() string {
return self.RoleName
}
func (self *SRole) GetICloudpolicies() ([]cloudprovider.ICloudpolicy, error) {
policies, err := self.client.ListAttachedRolePolicies(self.RoleName)
if err != nil {
return nil, err
}
ret := []cloudprovider.ICloudpolicy{}
for i := range policies {
policies[i].client = self.client
ret = append(ret, &policies[i])
}
return ret, nil
}
func (self *SRole) AttachPolicy(policyName string, policyType string) error {
return self.client.AttachRolePolicy(self.RoleName, policyName, utils.Capitalize(policyType))
}
func (self *SRole) DetachPolicy(policyName string, policyType string) error {
return self.client.DetachRolePolicy(self.RoleName, policyName, utils.Capitalize(policyType))
}
func (self *SRole) Delete() error {
return self.client.DeleteRole(self.RoleName)
}
func (self *SRole) GetDocument() *jsonutils.JSONDict {
doc, err := jsonutils.ParseString(self.TrustPolicyDocument)
if err != nil {
return nil
}
return doc.(*jsonutils.JSONDict)
}
func (self *SRole) GetSAMLProvider() string {
document := self.GetDocument()
if document == nil {
return ""
}
info := &PolicyDocument{}
document.Unmarshal(info)
for _, statement := range info.Statement {
for _, sp := range statement.Principal.Federated {
info := strings.Split(sp, "/")
if len(info) == 2 {
return info[1]
}
}
}
return ""
}
func (self *SVolcEngineClient) GetICloudroles() ([]cloudprovider.ICloudrole, error) {
roles, err := self.ListRoles()
if err != nil {
return nil, err
}
ret := []cloudprovider.ICloudrole{}
for i := range roles {
roles[i].client = self
ret = append(ret, &roles[i])
}
return ret, nil
}
func (client *SVolcEngineClient) ListRoles() ([]SRole, error) {
params := map[string]string{
"Limit": "50",
}
offset := 0
ret := []SRole{}
for {
params["Offset"] = fmt.Sprintf("%d", offset)
resp, err := client.iamRequest("", "ListRoles", params)
if err != nil {
return nil, err
}
part := struct {
RoleMetadata []SRole
Total int
}{}
err = resp.Unmarshal(&part)
if err != nil {
return nil, err
}
ret = append(ret, part.RoleMetadata...)
if len(part.RoleMetadata) == 0 || len(ret) >= part.Total {
break
}
offset = len(ret)
}
return ret, nil
}
func (client *SVolcEngineClient) GetRole(name string) (*SRole, error) {
params := map[string]string{
"RoleName": name,
}
resp, err := client.iamRequest("", "GetRole", params)
if err != nil {
return nil, err
}
ret := &SRole{client: client}
err = resp.Unmarshal(ret, "Role")
if err != nil {
return nil, err
}
return ret, nil
}
func (client *SVolcEngineClient) CreateRole(name, statement, desc string) (*SRole, error) {
params := map[string]string{
"RoleName": name,
"DisplayName": name,
"TrustPolicyDocument": statement,
"Description": desc,
}
resp, err := client.iamRequest("", "CreateRole", params)
if err != nil {
return nil, err
}
ret := &SRole{client: client}
err = resp.Unmarshal(ret, "Role")
if err != nil {
return nil, err
}
return ret, nil
}
func (client *SVolcEngineClient) DeleteRole(name string) error {
params := map[string]string{
"RoleName": name,
}
_, err := client.iamRequest("", "DeleteRole", params)
return err
}
func (client *SVolcEngineClient) ListAttachedRolePolicies(name string) ([]SPolicy, error) {
params := map[string]string{
"RoleName": name,
}
resp, err := client.iamRequest("", "ListAttachedRolePolicies", params)
if err != nil {
return nil, err
}
ret := []SPolicy{}
err = resp.Unmarshal(&ret, "AttachedPolicyMetadata")
if err != nil {
return nil, err
}
return ret, nil
}
func (client *SVolcEngineClient) AttachRolePolicy(name, policy, policyType string) error {
params := map[string]string{
"RoleName": name,
"PolicyName": policy,
"PolicyType": policyType,
}
_, err := client.iamRequest("", "AttachRolePolicy", params)
return err
}
func (client *SVolcEngineClient) DetachRolePolicy(name, policy, policyType string) error {
params := map[string]string{
"RoleName": name,
"PolicyName": policy,
"PolicyType": policyType,
}
_, err := client.iamRequest("", "DetachRolePolicy", params)
return err
}
+202
View File
@@ -0,0 +1,202 @@
// Copyright 2023 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 volcengine
import (
"encoding/base64"
"fmt"
"strings"
"yunion.io/x/cloudmux/pkg/apis"
"yunion.io/x/cloudmux/pkg/apis/cloudid"
"yunion.io/x/cloudmux/pkg/cloudprovider"
"yunion.io/x/cloudmux/pkg/multicloud"
"yunion.io/x/jsonutils"
"yunion.io/x/pkg/errors"
"yunion.io/x/pkg/util/httputils"
"yunion.io/x/pkg/util/samlutils"
)
type SSamlProvider struct {
multicloud.SResourceBase
multicloud.STagBase
client *SVolcEngineClient
Trn string
EncodedSAMLMetadataDocument string
ProviderName string
SAMLProviderName string
IdpType string
SSOType string
Status string
Description string
}
func (self *SSamlProvider) GetName() string {
if len(self.SAMLProviderName) > 0 {
return self.SAMLProviderName
}
return self.ProviderName
}
func (self *SSamlProvider) GetGlobalId() string {
if len(self.SAMLProviderName) > 0 {
return self.SAMLProviderName
}
return self.ProviderName
}
func (self *SSamlProvider) GetId() string {
if len(self.SAMLProviderName) > 0 {
return self.SAMLProviderName
}
return self.ProviderName
}
func (self *SSamlProvider) GetAuthUrl(apiServer string) string {
input := samlutils.SIdpInitiatedLoginInput{
EntityID: cloudprovider.SAML_ENTITY_ID_VOLC_ENGINE,
IdpId: self.client.cpcfg.AccountId,
}
return httputils.JoinPath(apiServer, cloudid.SAML_IDP_PREFIX, fmt.Sprintf("sso?%s", jsonutils.Marshal(input).QueryString()))
}
func (self *SSamlProvider) Delete() error {
return self.client.DeleteSamlProvider(self.GetName())
}
func (self *SSamlProvider) GetStatus() string {
return apis.STATUS_AVAILABLE
}
func (self *SSamlProvider) GetMetadataDocument() (*samlutils.EntityDescriptor, error) {
provider, err := self.client.GetSamlProvider(self.GetName())
if err != nil {
return nil, err
}
data, err := base64.StdEncoding.DecodeString(provider.EncodedSAMLMetadataDocument)
if err != nil {
return nil, err
}
ret, err := samlutils.ParseMetadata(data)
if err != nil {
return nil, err
}
return &ret, nil
}
func (self *SSamlProvider) UpdateMetadata(metadata samlutils.EntityDescriptor) error {
return self.client.UpdateSAMLProvider(self.GetName(), metadata.String())
}
func (self *SVolcEngineClient) GetSamlProviders() ([]SSamlProvider, error) {
params := map[string]string{}
params["Limit"] = "50"
ret := []SSamlProvider{}
offset := 0
for {
params["Offset"] = fmt.Sprintf("%d", offset)
resp, err := self.iamRequest("", "ListSAMLProviders", params)
if err != nil {
return nil, err
}
part := struct {
SAMLProviders []SSamlProvider
Total int
}{}
err = resp.Unmarshal(&part)
if err != nil {
return nil, err
}
ret = append(ret, part.SAMLProviders...)
if len(ret) >= part.Total || len(part.SAMLProviders) == 0 {
break
}
offset = len(ret)
}
return ret, nil
}
func (self *SVolcEngineClient) GetICloudSAMLProviders() ([]cloudprovider.ICloudSAMLProvider, error) {
providers, err := self.GetSamlProviders()
if err != nil {
return nil, err
}
ret := []cloudprovider.ICloudSAMLProvider{}
for i := range providers {
providers[i].client = self
ret = append(ret, &providers[i])
}
return ret, nil
}
func (self *SVolcEngineClient) DeleteSamlProvider(name string) error {
params := map[string]string{
"SAMLProviderName": name,
}
_, err := self.iamRequest("", "DeleteSAMLProvider", params)
return err
}
func (self *SVolcEngineClient) CreateSAMLProvider(name, metadata, desc string) (*SSamlProvider, error) {
name = strings.ReplaceAll(name, ":", "_")
params := map[string]string{
"EncodedSAMLMetadataDocument": base64.StdEncoding.EncodeToString([]byte(metadata)),
"SAMLProviderName": name,
"SSOType": "1",
"Status": "1",
}
if len(desc) > 0 {
params["Description"] = desc
}
resp, err := self.iamRequest("", "CreateSAMLProvider", params)
if err != nil {
return nil, errors.Wrapf(err, "CreateSAMLProvider")
}
sp := &SSamlProvider{client: self}
err = resp.Unmarshal(sp)
if err != nil {
return nil, errors.Wrapf(err, "resp.Unmarshal")
}
return sp, nil
}
func (self *SVolcEngineClient) GetSamlProvider(name string) (*SSamlProvider, error) {
params := map[string]string{
"SAMLProviderName": name,
}
resp, err := self.iamRequest("", "GetSAMLProvider", params)
if err != nil {
return nil, err
}
ret := &SSamlProvider{client: self}
err = resp.Unmarshal(ret)
if err != nil {
return nil, err
}
return ret, nil
}
func (self *SVolcEngineClient) UpdateSAMLProvider(name, metadata string) error {
name = strings.ReplaceAll(name, ":", "_")
params := map[string]string{
"EncodedSAMLMetadataDocument": base64.StdEncoding.EncodeToString([]byte(metadata)),
"SAMLProviderName": name,
"Status": "1",
}
_, err := self.iamRequest("", "UpdateSAMLProvider", params)
return err
}
+308 -20
View File
@@ -15,15 +15,20 @@
package volcengine
import (
"time"
"fmt"
"yunion.io/x/cloudmux/pkg/cloudprovider"
"yunion.io/x/cloudmux/pkg/multicloud"
"yunion.io/x/pkg/errors"
)
type SUser struct {
multicloud.SBaseClouduser
client *SVolcEngineClient
Id int
CreateDate time.Time
UpdateDate time.Time
CreateDate string
UpdateDate string
Status string
AccountId string
UserName string
@@ -37,27 +42,310 @@ type SUser struct {
Source string
}
type SCallerIdentity struct {
AccountId string
UserId string
RoleId string
PrincipalId string
IdentityType string
func (user *SUser) GetGlobalId() string {
return user.UserName
}
func (client *SVolcEngineClient) GetCallerIdentity() (*SCallerIdentity, error) {
// sys is not currently supported
params := map[string]string{}
body, err := client.iamRequest("", "ListUsers", params)
func (user *SUser) GetName() string {
return user.UserName
}
func (user *SUser) GetEmailAddr() string {
return user.Email
}
func (user *SUser) GetInviteUrl() string {
return ""
}
func (user *SUser) Delete() error {
return user.client.DeleteUser(user.UserName)
}
func (user *SUser) GetICloudgroups() ([]cloudprovider.ICloudgroup, error) {
groups, err := user.client.ListGroupsForUser(user.UserName)
if err != nil {
return nil, err
}
id := &SCallerIdentity{}
users := []SUser{}
err = body.Unmarshal(&users, "UserMetadata")
if err != nil {
return nil, errors.Wrap(err, "resp.Unmarshal")
ret := []cloudprovider.ICloudgroup{}
for i := range groups {
groups[i].client = user.client
ret = append(ret, &groups[i])
}
id.AccountId = users[0].AccountId
return id, nil
return ret, nil
}
func (user *SUser) GetISystemCloudpolicies() ([]cloudprovider.ICloudpolicy, error) {
policies, err := user.client.ListAttachedUserPolicies(user.UserName)
if err != nil {
return nil, err
}
ret := []cloudprovider.ICloudpolicy{}
for i := range policies {
policies[i].client = user.client
if policies[i].PolicyType == "System" {
ret = append(ret, &policies[i])
}
}
return ret, nil
}
func (user *SUser) GetICustomCloudpolicies() ([]cloudprovider.ICloudpolicy, error) {
policies, err := user.client.ListAttachedUserPolicies(user.UserName)
if err != nil {
return nil, err
}
ret := []cloudprovider.ICloudpolicy{}
for i := range policies {
policies[i].client = user.client
if policies[i].PolicyType == "Custom" {
ret = append(ret, &policies[i])
}
}
return ret, nil
}
func (user *SUser) IsConsoleLogin() bool {
profile, err := user.client.GetLoginProfile(user.UserName)
if err != nil {
return false
}
return profile.LoginAllowed
}
func (user *SUser) ResetPassword(password string) error {
return user.client.UpdateLoginProfile(user.UserName, password, nil)
}
func (user *SUser) AttachSystemPolicy(policyName string) error {
return user.client.AttachUserPolicy(user.UserName, policyName, "System")
}
func (user *SUser) AttachCustomPolicy(policyName string) error {
return user.client.AttachUserPolicy(user.UserName, policyName, "Custom")
}
func (user *SUser) DetachSystemPolicy(policyName string) error {
return user.client.DetachUserPolicy(user.UserName, policyName, "System")
}
func (user *SUser) DetachCustomPolicy(policyName string) error {
return user.client.DetachUserPolicy(user.UserName, policyName, "Custom")
}
func (client *SVolcEngineClient) GetUsers() ([]SUser, error) {
params := map[string]string{
"Limit": "50",
}
offset := 0
ret := []SUser{}
for {
params["Offset"] = fmt.Sprintf("%d", offset)
resp, err := client.iamRequest("", "ListUsers", params)
if err != nil {
return nil, err
}
part := struct {
UserMetadata []SUser
Total int
}{}
err = resp.Unmarshal(&part)
if err != nil {
return nil, err
}
ret = append(ret, part.UserMetadata...)
if len(part.UserMetadata) == 0 || len(ret) >= part.Total {
break
}
offset = len(ret)
}
return ret, nil
}
func (self *SVolcEngineClient) DeleteUser(name string) error {
params := map[string]string{
"UserName": name,
}
_, err := self.iamRequest("", "DeleteUser", params)
return err
}
func (client *SVolcEngineClient) GetICloudusers() ([]cloudprovider.IClouduser, error) {
users, err := client.GetUsers()
if err != nil {
return nil, err
}
ret := []cloudprovider.IClouduser{}
for i := range users {
users[i].client = client
ret = append(ret, &users[i])
}
return ret, nil
}
func (client *SVolcEngineClient) CreateIClouduser(opts *cloudprovider.SClouduserCreateConfig) (cloudprovider.IClouduser, error) {
user, err := client.CreateUser(opts)
if err != nil {
return nil, err
}
err = client.CreateLoginProfile(user.UserName, opts.Password, &opts.IsConsoleLogin)
if err != nil {
return nil, errors.Wrapf(err, "CreateLoginProfile")
}
return user, nil
}
func (self *SVolcEngineClient) CreateUser(opts *cloudprovider.SClouduserCreateConfig) (*SUser, error) {
params := map[string]string{
"UserName": opts.Name,
"Description": opts.Desc,
"Email": opts.Email,
"MobilePhone": opts.MobilePhone,
}
resp, err := self.iamRequest("", "CreateUser", params)
if err != nil {
return nil, err
}
ret := &SUser{client: self}
err = resp.Unmarshal(ret, "User")
if err != nil {
return nil, err
}
return ret, nil
}
type LoginProfile struct {
PasswordResetRequired bool
LoginAllowed bool
LastLoginDate string
}
func (self *SVolcEngineClient) GetLoginProfile(name string) (*LoginProfile, error) {
params := map[string]string{
"UserName": name,
}
resp, err := self.iamRequest("", "GetLoginProfile", params)
if err != nil {
return nil, err
}
ret := &LoginProfile{}
err = resp.Unmarshal(ret, "LoginProfile")
if err != nil {
return nil, err
}
return ret, nil
}
func (self *SVolcEngineClient) CreateLoginProfile(name, password string, loginAllowd *bool) error {
params := map[string]string{
"UserName": name,
"Password": password,
}
if loginAllowd != nil {
params["LoginAllowed"] = fmt.Sprintf("%v", *loginAllowd)
}
_, err := self.iamRequest("", "CreateLoginProfile", params)
return err
}
func (self *SVolcEngineClient) UpdateLoginProfile(name, password string, loginAllowd *bool) error {
params := map[string]string{
"UserName": name,
"Password": password,
}
if loginAllowd != nil {
params["LoginAllowed"] = fmt.Sprintf("%v", *loginAllowd)
}
_, err := self.iamRequest("", "UpdateLoginProfile", params)
return err
}
func (client *SVolcEngineClient) ListGroupsForUser(name string) ([]SGroup, error) {
params := map[string]string{
"Limit": "50",
"UserName": name,
}
offset := 0
ret := []SGroup{}
for {
params["Offset"] = fmt.Sprintf("%d", offset)
resp, err := client.iamRequest("", "ListGroupsForUser", params)
if err != nil {
return nil, err
}
part := struct {
UserGroups []SGroup
Total int
}{}
err = resp.Unmarshal(&part)
if err != nil {
return nil, err
}
ret = append(ret, part.UserGroups...)
if len(part.UserGroups) == 0 || len(ret) >= part.Total {
break
}
offset = len(ret)
}
return ret, nil
}
func (client *SVolcEngineClient) ListAttachedUserPolicies(name string) ([]SPolicy, error) {
params := map[string]string{
"UserName": name,
}
resp, err := client.iamRequest("", "ListAttachedUserPolicies", params)
if err != nil {
return nil, err
}
ret := []SPolicy{}
err = resp.Unmarshal(&ret, "AttachedPolicyMetadata")
if err != nil {
return nil, err
}
return ret, nil
}
func (client *SVolcEngineClient) AttachUserPolicy(name, policy, policyType string) error {
params := map[string]string{
"UserName": name,
"PolicyName": policy,
"PolicyType": policyType,
}
_, err := client.iamRequest("", "AttachUserPolicy", params)
return err
}
func (client *SVolcEngineClient) DetachUserPolicy(name, policy, policyType string) error {
params := map[string]string{
"UserName": name,
"PolicyName": policy,
"PolicyType": policyType,
}
_, err := client.iamRequest("", "DetachUserPolicy", params)
return err
}
func (client *SVolcEngineClient) GetIClouduserByName(name string) (cloudprovider.IClouduser, error) {
user, err := client.GetUser(name)
if err != nil {
return nil, err
}
return user, nil
}
func (client *SVolcEngineClient) GetUser(name string) (*SUser, error) {
params := map[string]string{
"UserName": name,
}
resp, err := client.iamRequest("", "GetUser", params)
if err != nil {
return nil, err
}
ret := &SUser{client: client}
err = resp.Unmarshal(ret, "User")
if err != nil {
return nil, err
}
return ret, nil
}
+93 -38
View File
@@ -18,14 +18,18 @@ import (
"context"
"crypto/tls"
"fmt"
"io"
"net/http"
"net/http/httputil"
"net/url"
"strings"
"sync"
"time"
"github.com/fatih/color"
tos "github.com/volcengine/ve-tos-golang-sdk/v2/tos"
sdk "github.com/volcengine/volc-sdk-golang/base"
"moul.io/http2curl/v2"
"yunion.io/x/jsonutils"
"yunion.io/x/log"
"yunion.io/x/pkg/errors"
@@ -42,7 +46,7 @@ const (
CLOUD_PROVIDER_VOLCENGINE_EN = "VolcEngine"
VOLCENGINE_API_VERSION = "2020-04-01"
VOLCENGINE_IAM_API_VERSION = "2021-08-01"
VOLCENGINE_IAM_API_VERSION = "2018-01-01"
VOLCENGINE_OBSERVE_API_VERSION = "2018-01-01"
VOLCENGINE_BILLING_API_VERSION = "2022-01-01"
@@ -98,10 +102,6 @@ func (cfg *VolcEngineClientConfig) Debug(debug bool) *VolcEngineClientConfig {
return cfg
}
func (cfg VolcEngineClientConfig) Copy() VolcEngineClientConfig {
return cfg
}
type SVolcEngineClient struct {
*VolcEngineClientConfig
@@ -180,11 +180,16 @@ func (client *SVolcEngineClient) GetAccountId() string {
if len(client.ownerId) > 0 {
return client.ownerId
}
caller, err := client.GetCallerIdentity()
toscli, err := client.getTosClient(VOLCENGINE_DEFAULT_REGION)
if err != nil {
return ""
}
client.ownerId = caller.AccountId
out, err := toscli.ListBuckets(context.Background(), &tos.ListBucketsInput{})
if err != nil {
return ""
}
client.ownerId = out.Owner.ID
return client.ownerId
}
@@ -229,7 +234,7 @@ func (client *SVolcEngineClient) GetProjects() ([]SProject, error) {
if len(client.projects) >= total {
break
}
offset += total
offset = len(client.projects)
}
return client.projects, nil
}
@@ -287,19 +292,6 @@ func (client *SVolcEngineClient) jsonRequest(cred sdk.Credentials, domain string
"Version": []string{apiVersion},
}
var body interface{} = nil
if _params, ok := params.(map[string]string); ok {
for k, v := range _params {
query.Set(k, v)
}
} else {
body = params
}
u, err := url.Parse(fmt.Sprintf("http://%s?%s", domain, query.Encode()))
if err != nil {
return nil, errors.Wrapf(err, "url.Parse")
}
method := httputils.GET
for prefix, _method := range map[string]httputils.THttpMethod{
"Get": httputils.GET,
@@ -307,6 +299,7 @@ func (client *SVolcEngineClient) jsonRequest(cred sdk.Credentials, domain string
"List": httputils.GET,
"Delete": httputils.GET,
"Put": httputils.PUT,
"Create": httputils.POST,
} {
if strings.HasPrefix(apiName, prefix) {
method = _method
@@ -322,21 +315,84 @@ func (client *SVolcEngineClient) jsonRequest(cred sdk.Credentials, domain string
method = httputils.POST
}
req := httputils.NewJsonRequest(method, u.String(), body)
vErr := &sVolcError{}
_cli := &sCred{
form := url.Values{}
_params, _ := params.(map[string]string)
switch method {
case httputils.POST:
for k, v := range _params {
form.Set(k, v)
query.Set(k, v)
}
default:
for k, v := range _params {
query.Set(k, v)
}
}
u, err := url.Parse(fmt.Sprintf("http://%s?%s", domain, query.Encode()))
if err != nil {
return nil, errors.Wrapf(err, "url.Parse")
}
req, err := http.NewRequest(string(method), u.String(), strings.NewReader(form.Encode()))
if err != nil {
return nil, errors.Wrapf(err, "NewRequest")
}
cli := &sCred{
client: client,
cred: cred,
}
cli := httputils.NewJsonClient(_cli)
_, resp, err := cli.Send(context.Background(), req, vErr, client.debug)
resp, err := cli.Do(req)
if err != nil {
return nil, errors.Wrapf(err, apiName)
return nil, errors.Wrapf(err, "Do request")
}
if resp.Contains("Result") {
return resp.Get("Result")
defer resp.Body.Close()
red := color.New(color.FgRed, color.Bold).PrintlnFunc()
green := color.New(color.FgGreen, color.Bold).PrintlnFunc()
yellow := color.New(color.FgYellow, color.Bold).PrintlnFunc()
cyan := color.New(color.FgHiCyan, color.Bold).PrintlnFunc()
if client.debug {
dump, _ := httputil.DumpRequestOut(req, true)
yellow(string(dump))
if req.Header.Get("Content-Type") != "application/octet-stream" {
curlCmd, _ := http2curl.GetCurlCommand(req)
cyan("CURL:", curlCmd, "\n")
}
dump, _ = httputil.DumpResponse(resp, true)
if resp.StatusCode < 300 {
green(string(dump))
} else if resp.StatusCode < 400 {
yellow(string(dump))
} else {
red(string(dump))
}
}
return resp, nil
body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, errors.Wrapf(err, "Read body")
}
obj, err := jsonutils.Parse(body)
if err != nil {
return nil, errors.Wrapf(err, "Parse body %s", string(body))
}
// {"ResponseMetadata":{"RequestId":"202404021200176E2994C9222303CC731B","Action":"CreateUser","Version":"2018-01-01","Service":"iam","Region":"cn-beijing","Error":{"Code":"ParameterNotFound","Message":"The parameter 'UserName' is required."}}}
if obj.Contains("ResponseMetadata", "Error") {
ve := &sVolcError{StatusCode: resp.StatusCode}
obj.Unmarshal(ve, "ResponseMetadata")
return nil, ve
}
if obj.Contains("Result") {
return obj.Get("Result")
}
return obj, nil
}
func (client *SVolcEngineClient) getSdkCredential(region string, service string, token string) sdk.Credentials {
@@ -381,19 +437,16 @@ func (self *sVolcError) Error() string {
return jsonutils.Marshal(self).String()
}
func (self *sVolcError) ParseErrorFromJsonResponse(statusCode int, status string, body jsonutils.JSONObject) error {
if body != nil {
body.Unmarshal(self, "ResponseMetadata")
}
self.StatusCode = statusCode
return self
}
func (client *SVolcEngineClient) ecsRequest(region string, apiName string, params map[string]string) (jsonutils.JSONObject, error) {
cred := client.getDefaultCredential(region, VOLCENGINE_SERVICE_ECS)
return client.jsonRequest(cred, VOLCENGINE_API, VOLCENGINE_API_VERSION, apiName, params)
}
func (client *SVolcEngineClient) iam20210801Request(region string, apiName string, params map[string]string) (jsonutils.JSONObject, error) {
cred := client.getDefaultCredential(region, VOLCENGINE_SERVICE_IAM)
return client.jsonRequest(cred, VOLCENGINE_IAM_API, "2021-08-01", apiName, params)
}
func (client *SVolcEngineClient) iamRequest(region string, apiName string, params map[string]string) (jsonutils.JSONObject, error) {
cred := client.getDefaultCredential(region, VOLCENGINE_SERVICE_IAM)
return client.jsonRequest(cred, VOLCENGINE_IAM_API, VOLCENGINE_IAM_API_VERSION, apiName, params)
@@ -477,6 +530,8 @@ func (region *SVolcEngineClient) GetCapabilities() []string {
cloudprovider.CLOUD_CAPABILITY_NETWORK,
cloudprovider.CLOUD_CAPABILITY_SECURITY_GROUP,
cloudprovider.CLOUD_CAPABILITY_EIP,
cloudprovider.CLOUD_CAPABILITY_CLOUDID,
cloudprovider.CLOUD_CAPABILITY_SAML_AUTH,
cloudprovider.CLOUD_CAPABILITY_OBJECTSTORE,
}
return caps