diff --git a/pkg/openapi/client.go b/pkg/openapi/client.go index cd1943d7..a0dd6f53 100644 --- a/pkg/openapi/client.go +++ b/pkg/openapi/client.go @@ -15,6 +15,11 @@ var ( defaultStsApiEndpoint = "sts.aliyuncs.com" ) +type ClientInterface interface { + RamClientInterface + CSClientInterface +} + type Client struct { ramClient *ram.Client csClient *cs.Client diff --git a/pkg/openapi/cs.go b/pkg/openapi/cs.go index 50358271..281157de 100644 --- a/pkg/openapi/cs.go +++ b/pkg/openapi/cs.go @@ -23,7 +23,9 @@ type CSClientInterface interface { UpdateCluster(ctx context.Context, clusterId string, opt UpdateClusterOption) (*types.ClusterTask, error) GetTask(ctx context.Context, taskId string) (*types.ClusterTask, error) GetUserKubeConfig(ctx context.Context, clusterId string, privateIpAddress bool, temporaryDuration time.Duration) (*types.KubeConfig, error) + // Deprecated: use ListClustersV1 instead ListClusters(ctx context.Context) ([]types.Cluster, error) + ListClustersV1(ctx context.Context) ([]types.Cluster, error) GetAddonMetaData(ctx context.Context, clusterId string, name string) (*types.ClusterAddon, error) GetAddonStatus(ctx context.Context, clusterId string, name string) (*types.ClusterAddon, error) InstallAddon(ctx context.Context, clusterId string, addon types.ClusterAddon) error @@ -41,6 +43,7 @@ func (c *Client) GetCluster(ctx context.Context, clusterId string) (*types.Clust return cluster, nil } +// Deprecated: use ListClustersV1 instead func (c *Client) ListClusters(ctx context.Context) ([]types.Cluster, error) { client := c.csClient resp, err := client.DescribeClusters(&cs.DescribeClustersRequest{}) @@ -51,6 +54,35 @@ func (c *Client) ListClusters(ctx context.Context) ([]types.Cluster, error) { return convertDescribeClustersResponse(resp), nil } +func (c *Client) ListClustersV1(ctx context.Context) ([]types.Cluster, error) { + client := c.csClient + var ret []types.Cluster + var pageNumber int64 + + for { + resp, err := client.DescribeClustersV1(&cs.DescribeClustersV1Request{ + ClusterSpec: nil, + ClusterType: nil, + Name: nil, + PageNumber: tea.Int64(pageNumber), + //PageSize: tea.Int64(), + Profile: nil, + RegionId: nil, + }) + if err != nil { + return nil, err + } + clusters := convertDescribeClustersV1Response(resp) + if len(clusters) == 0 { + break + } + ret = append(ret, clusters...) + pageNumber++ + } + + return ret, nil +} + func (c *Client) UpdateCluster(ctx context.Context, clusterId string, opt UpdateClusterOption) (*types.ClusterTask, error) { client := c.csClient req := &cs.ModifyClusterRequest{ @@ -271,3 +303,26 @@ func convertDescribeClustersResponse(resp *cs.DescribeClustersResponse) []types. return clusters } + +func convertDescribeClustersV1Response(resp *cs.DescribeClustersV1Response) []types.Cluster { + body := resp.Body + if body == nil { + return nil + } + var clusters []types.Cluster + for _, item := range body.Clusters { + c := types.Cluster{} + c.ClusterId = tea.StringValue(item.ClusterId) + c.ClusterType = types.ClusterType(tea.StringValue(item.ClusterType)) + c.Name = tea.StringValue(item.Name) + c.RegionId = tea.StringValue(item.RegionId) + c.State = types.ClusterState(tea.StringValue(item.State)) + + metadata := &types.ClusterMetaData{} + _ = json.Unmarshal([]byte(tea.StringValue(item.MetaData)), metadata) + c.MetaData = *metadata + clusters = append(clusters, c) + } + + return clusters +} diff --git a/pkg/openapi/ram.go b/pkg/openapi/ram.go index 1bc950e0..fe7c2a5f 100644 --- a/pkg/openapi/ram.go +++ b/pkg/openapi/ram.go @@ -19,6 +19,8 @@ type RamClientInterface interface { GetPolicy(ctx context.Context, name, policyType string) (*types.RamPolicy, error) CreatePolicy(ctx context.Context, policy types.RamPolicy) (*types.RamPolicy, error) AttachPolicyToRole(ctx context.Context, policyName, policyType, roleName string) error + ListUsers(ctx context.Context) ([]types.RamUser, error) + ListRoles(ctx context.Context) ([]types.RamRole, error) } func (c *Client) GetRole(ctx context.Context, name string) (*types.RamRole, error) { @@ -293,9 +295,125 @@ func convertCreateRamPolicyResponse(r *types.RamPolicy, resp *ram.CreatePolicyRe r.Description = tea.StringValue(p.Description) } +func (c *Client) ListUsers(ctx context.Context) ([]types.RamUser, error) { + var users []types.RamUser + var marker string + for { + req := &ram.ListUsersRequest{ + Marker: nil, + MaxItems: tea.Int32(1000), + } + if marker != "" { + req.Marker = tea.String(marker) + } + resp, err := c.ramClient.ListUsers(req) + if err != nil { + return nil, err + } + items := convertListUsersResponse(resp) + users = append(users, items...) + if resp.Body != nil { + if !tea.BoolValue(resp.Body.IsTruncated) { + break + } + marker = tea.StringValue(resp.Body.Marker) + } + } + return users, nil +} + +func (c *Client) ListRoles(ctx context.Context) ([]types.RamRole, error) { + var roles []types.RamRole + var marker string + for { + req := &ram.ListRolesRequest{ + Marker: nil, + MaxItems: tea.Int32(1000), + } + if marker != "" { + req.Marker = tea.String(marker) + } + resp, err := c.ramClient.ListRoles(req) + if err != nil { + return nil, err + } + items := convertListRolesResponse(resp) + roles = append(roles, items...) + if resp.Body != nil { + if !tea.BoolValue(resp.Body.IsTruncated) { + break + } + marker = tea.StringValue(resp.Body.Marker) + } + } + return roles, nil +} + +func convertListUsersResponse(resp *ram.ListUsersResponse) []types.RamUser { + body := resp.Body + if body == nil { + return nil + } + p := body.Users + if p == nil { + return nil + } + us := p.User + if us == nil { + return nil + } + + var ret []types.RamUser + for _, u := range us { + ret = append(ret, types.RamUser{ + Id: tea.StringValue(u.UserId), + Name: tea.StringValue(u.UserName), + DisplayName: tea.StringValue(u.DisplayName), + Deleted: false, + }) + } + + return ret +} + +func convertListRolesResponse(resp *ram.ListRolesResponse) []types.RamRole { + body := resp.Body + if body == nil { + return nil + } + p := body.Roles + if p == nil { + return nil + } + us := p.Role + if us == nil { + return nil + } + + var ret []types.RamRole + for _, u := range us { + ret = append(ret, types.RamRole{ + RoleId: tea.StringValue(u.RoleId), + RoleName: tea.StringValue(u.RoleName), + Arn: tea.StringValue(u.Arn), + Description: tea.StringValue(u.Description), + AssumeRolePolicyDocument: nil, + MaxSessionDuration: tea.Int64Value(u.MaxSessionDuration), + Deleted: false, + }) + } + + return ret +} + func IsRamRoleNotExistErr(err error) bool { return isSdkErrWithCode(err, "EntityNotExist.Role") } + +func IsRamUserNotExistErr(err error) bool { + return isSdkErrWithCode(err, "EntityNotExist.User") +} + func IsRamPolicyNotExistErr(err error) bool { return isSdkErrWithCode(err, "EntityNotExist.Policy") } diff --git a/pkg/types/ram.go b/pkg/types/ram.go index 130abe51..dcf2a7df 100644 --- a/pkg/types/ram.go +++ b/pkg/types/ram.go @@ -4,6 +4,7 @@ import ( "encoding/json" "fmt" "reflect" + "strings" "github.com/AliyunContainerService/ack-ram-tool/pkg/log" "github.com/AliyunContainerService/ack-ram-tool/pkg/utils" @@ -20,6 +21,20 @@ var ( RamPolicyTypeCustom = "Custom" ) +type AccountType string + +const ( + AccountTypeRoot AccountType = "Root" + AccountTypeUser AccountType = "RamUser" + AccountTypeRole AccountType = "RamRole" +) + +type Account struct { + Type AccountType + User RamUser + Role RamRole +} + type RamRole struct { RoleName string RoleId string @@ -27,6 +42,14 @@ type RamRole struct { Description string AssumeRolePolicyDocument *RamPolicyDocument MaxSessionDuration int64 + Deleted bool +} + +type RamUser struct { + Id string + Name string + DisplayName string + Deleted bool } type RamPolicy struct { @@ -179,3 +202,68 @@ func (s *RamPolicyStatement) JSON() string { data, _ := json.Marshal(s) return string(data) } + +func (a Account) Id() string { + switch a.Type { + case AccountTypeUser: + return a.User.Id + case AccountTypeRole: + return a.Role.RoleId + } + return "" +} +func (a Account) Name() string { + switch a.Type { + case AccountTypeUser: + return a.User.Name + case AccountTypeRole: + return a.Role.RoleName + } + return "" +} + +func (a Account) Deleted() bool { + switch a.Type { + case AccountTypeUser: + return a.User.Deleted + case AccountTypeRole: + return a.Role.Deleted + } + return false +} + +func NewFakeAccount(uid int64) Account { + idStr := fmt.Sprintf("%d", uid) + acc := Account{} + switch { + case strings.HasPrefix(idStr, "1"), strings.HasPrefix(idStr, "5"): + acc.Type = AccountTypeRoot + acc.User = RamUser{ + Id: idStr, + } + case strings.HasPrefix(idStr, "2"): + acc.Type = AccountTypeUser + acc.User = RamUser{ + Id: idStr, + } + case strings.HasPrefix(idStr, "3"): + acc.Type = AccountTypeRole + acc.Role = RamRole{ + RoleId: idStr, + } + } + return acc +} + +func (a *Account) MarkDeleted() { + switch a.Type { + case AccountTypeUser: + u := a.User + u.Deleted = true + a.User = u + case AccountTypeRole: + r := a.Role + r.Deleted = true + a.Role = r + } +}