mirror of
https://github.com/gravitational/teleport.git
synced 2026-11-01 05:27:24 +08:00
702 lines
27 KiB
Go
702 lines
27 KiB
Go
/*
|
|
Copyright 2021 Gravitational, Inc.
|
|
|
|
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 mocks
|
|
|
|
import (
|
|
"sync"
|
|
|
|
"github.com/aws/aws-sdk-go/aws"
|
|
"github.com/aws/aws-sdk-go/aws/request"
|
|
"github.com/aws/aws-sdk-go/service/elasticache"
|
|
"github.com/aws/aws-sdk-go/service/elasticache/elasticacheiface"
|
|
"github.com/aws/aws-sdk-go/service/iam"
|
|
"github.com/aws/aws-sdk-go/service/iam/iamiface"
|
|
"github.com/aws/aws-sdk-go/service/memorydb"
|
|
"github.com/aws/aws-sdk-go/service/memorydb/memorydbiface"
|
|
"github.com/aws/aws-sdk-go/service/rds"
|
|
"github.com/aws/aws-sdk-go/service/rds/rdsiface"
|
|
"github.com/aws/aws-sdk-go/service/redshift"
|
|
"github.com/aws/aws-sdk-go/service/redshift/redshiftiface"
|
|
"github.com/aws/aws-sdk-go/service/sts"
|
|
"github.com/aws/aws-sdk-go/service/sts/stsiface"
|
|
"github.com/gravitational/trace"
|
|
)
|
|
|
|
// STSMock mocks AWS STS API.
|
|
type STSMock struct {
|
|
stsiface.STSAPI
|
|
ARN string
|
|
}
|
|
|
|
func (m *STSMock) GetCallerIdentityWithContext(aws.Context, *sts.GetCallerIdentityInput, ...request.Option) (*sts.GetCallerIdentityOutput, error) {
|
|
return &sts.GetCallerIdentityOutput{
|
|
Arn: aws.String(m.ARN),
|
|
}, nil
|
|
}
|
|
|
|
// RDSMock mocks AWS RDS API.
|
|
type RDSMock struct {
|
|
rdsiface.RDSAPI
|
|
DBInstances []*rds.DBInstance
|
|
DBClusters []*rds.DBCluster
|
|
DBProxies []*rds.DBProxy
|
|
DBProxyEndpoints []*rds.DBProxyEndpoint
|
|
DBEngineVersions []*rds.DBEngineVersion
|
|
DBProxyTargetPort int64
|
|
}
|
|
|
|
func (m *RDSMock) DescribeDBInstancesWithContext(ctx aws.Context, input *rds.DescribeDBInstancesInput, options ...request.Option) (*rds.DescribeDBInstancesOutput, error) {
|
|
if err := checkEngineFilters(input.Filters, m.DBEngineVersions); err != nil {
|
|
return nil, trace.Wrap(err)
|
|
}
|
|
instances, err := applyInstanceFilters(m.DBInstances, input.Filters)
|
|
if err != nil {
|
|
return nil, trace.Wrap(err)
|
|
}
|
|
if aws.StringValue(input.DBInstanceIdentifier) == "" {
|
|
return &rds.DescribeDBInstancesOutput{
|
|
DBInstances: instances,
|
|
}, nil
|
|
}
|
|
for _, instance := range instances {
|
|
if aws.StringValue(instance.DBInstanceIdentifier) == aws.StringValue(input.DBInstanceIdentifier) {
|
|
return &rds.DescribeDBInstancesOutput{
|
|
DBInstances: []*rds.DBInstance{instance},
|
|
}, nil
|
|
}
|
|
}
|
|
return nil, trace.NotFound("instance %v not found", aws.StringValue(input.DBInstanceIdentifier))
|
|
}
|
|
|
|
func (m *RDSMock) DescribeDBInstancesPagesWithContext(ctx aws.Context, input *rds.DescribeDBInstancesInput, fn func(*rds.DescribeDBInstancesOutput, bool) bool, options ...request.Option) error {
|
|
if err := checkEngineFilters(input.Filters, m.DBEngineVersions); err != nil {
|
|
return trace.Wrap(err)
|
|
}
|
|
instances, err := applyInstanceFilters(m.DBInstances, input.Filters)
|
|
if err != nil {
|
|
return trace.Wrap(err)
|
|
}
|
|
fn(&rds.DescribeDBInstancesOutput{
|
|
DBInstances: instances,
|
|
}, true)
|
|
return nil
|
|
}
|
|
|
|
func (m *RDSMock) DescribeDBClustersWithContext(ctx aws.Context, input *rds.DescribeDBClustersInput, options ...request.Option) (*rds.DescribeDBClustersOutput, error) {
|
|
if err := checkEngineFilters(input.Filters, m.DBEngineVersions); err != nil {
|
|
return nil, trace.Wrap(err)
|
|
}
|
|
clusters, err := applyClusterFilters(m.DBClusters, input.Filters)
|
|
if err != nil {
|
|
return nil, trace.Wrap(err)
|
|
}
|
|
if aws.StringValue(input.DBClusterIdentifier) == "" {
|
|
return &rds.DescribeDBClustersOutput{
|
|
DBClusters: clusters,
|
|
}, nil
|
|
}
|
|
for _, cluster := range clusters {
|
|
if aws.StringValue(cluster.DBClusterIdentifier) == aws.StringValue(input.DBClusterIdentifier) {
|
|
return &rds.DescribeDBClustersOutput{
|
|
DBClusters: []*rds.DBCluster{cluster},
|
|
}, nil
|
|
}
|
|
}
|
|
return nil, trace.NotFound("cluster %v not found", aws.StringValue(input.DBClusterIdentifier))
|
|
}
|
|
|
|
func (m *RDSMock) DescribeDBClustersPagesWithContext(aws aws.Context, input *rds.DescribeDBClustersInput, fn func(*rds.DescribeDBClustersOutput, bool) bool, options ...request.Option) error {
|
|
if err := checkEngineFilters(input.Filters, m.DBEngineVersions); err != nil {
|
|
return trace.Wrap(err)
|
|
}
|
|
clusters, err := applyClusterFilters(m.DBClusters, input.Filters)
|
|
if err != nil {
|
|
return trace.Wrap(err)
|
|
}
|
|
fn(&rds.DescribeDBClustersOutput{
|
|
DBClusters: clusters,
|
|
}, true)
|
|
return nil
|
|
}
|
|
|
|
func (m *RDSMock) ModifyDBInstanceWithContext(ctx aws.Context, input *rds.ModifyDBInstanceInput, options ...request.Option) (*rds.ModifyDBInstanceOutput, error) {
|
|
for i, instance := range m.DBInstances {
|
|
if aws.StringValue(instance.DBInstanceIdentifier) == aws.StringValue(input.DBInstanceIdentifier) {
|
|
if aws.BoolValue(input.EnableIAMDatabaseAuthentication) {
|
|
m.DBInstances[i].IAMDatabaseAuthenticationEnabled = aws.Bool(true)
|
|
}
|
|
return &rds.ModifyDBInstanceOutput{
|
|
DBInstance: m.DBInstances[i],
|
|
}, nil
|
|
}
|
|
}
|
|
return nil, trace.NotFound("instance %v not found", aws.StringValue(input.DBInstanceIdentifier))
|
|
}
|
|
|
|
func (m *RDSMock) ModifyDBClusterWithContext(ctx aws.Context, input *rds.ModifyDBClusterInput, options ...request.Option) (*rds.ModifyDBClusterOutput, error) {
|
|
for i, cluster := range m.DBClusters {
|
|
if aws.StringValue(cluster.DBClusterIdentifier) == aws.StringValue(input.DBClusterIdentifier) {
|
|
if aws.BoolValue(input.EnableIAMDatabaseAuthentication) {
|
|
m.DBClusters[i].IAMDatabaseAuthenticationEnabled = aws.Bool(true)
|
|
}
|
|
return &rds.ModifyDBClusterOutput{
|
|
DBCluster: m.DBClusters[i],
|
|
}, nil
|
|
}
|
|
}
|
|
return nil, trace.NotFound("cluster %v not found", aws.StringValue(input.DBClusterIdentifier))
|
|
}
|
|
func (m *RDSMock) DescribeDBProxiesWithContext(ctx aws.Context, input *rds.DescribeDBProxiesInput, options ...request.Option) (*rds.DescribeDBProxiesOutput, error) {
|
|
if aws.StringValue(input.DBProxyName) == "" {
|
|
return &rds.DescribeDBProxiesOutput{
|
|
DBProxies: m.DBProxies,
|
|
}, nil
|
|
}
|
|
for _, dbProxy := range m.DBProxies {
|
|
if aws.StringValue(dbProxy.DBProxyName) == aws.StringValue(input.DBProxyName) {
|
|
return &rds.DescribeDBProxiesOutput{
|
|
DBProxies: []*rds.DBProxy{dbProxy},
|
|
}, nil
|
|
}
|
|
}
|
|
return nil, trace.NotFound("proxy %v not found", aws.StringValue(input.DBProxyName))
|
|
}
|
|
func (m *RDSMock) DescribeDBProxyEndpointsWithContext(ctx aws.Context, input *rds.DescribeDBProxyEndpointsInput, options ...request.Option) (*rds.DescribeDBProxyEndpointsOutput, error) {
|
|
inputProxyName := aws.StringValue(input.DBProxyName)
|
|
inputProxyEndpointName := aws.StringValue(input.DBProxyEndpointName)
|
|
|
|
if inputProxyName == "" && inputProxyEndpointName == "" {
|
|
return &rds.DescribeDBProxyEndpointsOutput{
|
|
DBProxyEndpoints: m.DBProxyEndpoints,
|
|
}, nil
|
|
}
|
|
|
|
var endpoints []*rds.DBProxyEndpoint
|
|
for _, dbProxyEndpoiont := range m.DBProxyEndpoints {
|
|
if inputProxyEndpointName != "" &&
|
|
inputProxyEndpointName != aws.StringValue(dbProxyEndpoiont.DBProxyEndpointName) {
|
|
continue
|
|
}
|
|
|
|
if inputProxyName != "" &&
|
|
inputProxyName != aws.StringValue(dbProxyEndpoiont.DBProxyName) {
|
|
continue
|
|
}
|
|
|
|
endpoints = append(endpoints, dbProxyEndpoiont)
|
|
}
|
|
if len(endpoints) == 0 {
|
|
return nil, trace.NotFound("proxy endpoint %v not found", aws.StringValue(input.DBProxyEndpointName))
|
|
}
|
|
return &rds.DescribeDBProxyEndpointsOutput{DBProxyEndpoints: endpoints}, nil
|
|
}
|
|
func (m *RDSMock) DescribeDBProxyTargetsWithContext(ctx aws.Context, input *rds.DescribeDBProxyTargetsInput, options ...request.Option) (*rds.DescribeDBProxyTargetsOutput, error) {
|
|
// only mocking to return a port here
|
|
return &rds.DescribeDBProxyTargetsOutput{
|
|
Targets: []*rds.DBProxyTarget{{
|
|
Port: aws.Int64(m.DBProxyTargetPort),
|
|
}},
|
|
}, nil
|
|
}
|
|
func (m *RDSMock) DescribeDBProxiesPagesWithContext(ctx aws.Context, input *rds.DescribeDBProxiesInput, fn func(*rds.DescribeDBProxiesOutput, bool) bool, options ...request.Option) error {
|
|
fn(&rds.DescribeDBProxiesOutput{
|
|
DBProxies: m.DBProxies,
|
|
}, true)
|
|
return nil
|
|
}
|
|
func (m *RDSMock) DescribeDBProxyEndpointsPagesWithContext(ctx aws.Context, input *rds.DescribeDBProxyEndpointsInput, fn func(*rds.DescribeDBProxyEndpointsOutput, bool) bool, options ...request.Option) error {
|
|
fn(&rds.DescribeDBProxyEndpointsOutput{
|
|
DBProxyEndpoints: m.DBProxyEndpoints,
|
|
}, true)
|
|
return nil
|
|
}
|
|
func (m *RDSMock) ListTagsForResourceWithContext(ctx aws.Context, input *rds.ListTagsForResourceInput, options ...request.Option) (*rds.ListTagsForResourceOutput, error) {
|
|
return &rds.ListTagsForResourceOutput{}, nil
|
|
}
|
|
|
|
// IAMMock mocks AWS IAM API.
|
|
type IAMMock struct {
|
|
iamiface.IAMAPI
|
|
mu sync.RWMutex
|
|
// attachedRolePolicies maps roleName -> policyName -> policyDocument
|
|
attachedRolePolicies map[string]map[string]string
|
|
// attachedUserPolicies maps userName -> policyName -> policyDocument
|
|
attachedUserPolicies map[string]map[string]string
|
|
}
|
|
|
|
func (m *IAMMock) GetRolePolicyWithContext(ctx aws.Context, input *iam.GetRolePolicyInput, options ...request.Option) (*iam.GetRolePolicyOutput, error) {
|
|
m.mu.RLock()
|
|
defer m.mu.RUnlock()
|
|
policy, ok := m.attachedRolePolicies[*input.RoleName]
|
|
if !ok {
|
|
return nil, trace.NotFound("policy not found")
|
|
}
|
|
policyDocument, ok := policy[*input.PolicyName]
|
|
if !ok {
|
|
return nil, trace.NotFound("policy not found")
|
|
}
|
|
return &iam.GetRolePolicyOutput{
|
|
PolicyDocument: &policyDocument,
|
|
PolicyName: input.PolicyName,
|
|
RoleName: input.RoleName,
|
|
}, nil
|
|
}
|
|
|
|
func (m *IAMMock) PutRolePolicyWithContext(ctx aws.Context, input *iam.PutRolePolicyInput, options ...request.Option) (*iam.PutRolePolicyOutput, error) {
|
|
m.mu.Lock()
|
|
defer m.mu.Unlock()
|
|
if m.attachedRolePolicies == nil {
|
|
m.attachedRolePolicies = make(map[string]map[string]string)
|
|
}
|
|
if m.attachedRolePolicies[*input.RoleName] == nil {
|
|
m.attachedRolePolicies[*input.RoleName] = make(map[string]string)
|
|
}
|
|
m.attachedRolePolicies[*input.RoleName][*input.PolicyName] = *input.PolicyDocument
|
|
return &iam.PutRolePolicyOutput{}, nil
|
|
}
|
|
|
|
func (m *IAMMock) DeleteRolePolicyWithContext(ctx aws.Context, input *iam.DeleteRolePolicyInput, options ...request.Option) (*iam.DeleteRolePolicyOutput, error) {
|
|
m.mu.Lock()
|
|
defer m.mu.Unlock()
|
|
if _, ok := m.attachedRolePolicies[*input.RoleName]; ok {
|
|
delete(m.attachedRolePolicies[*input.RoleName], *input.PolicyName)
|
|
}
|
|
return &iam.DeleteRolePolicyOutput{}, nil
|
|
}
|
|
|
|
func (m *IAMMock) GetUserPolicyWithContext(ctx aws.Context, input *iam.GetUserPolicyInput, options ...request.Option) (*iam.GetUserPolicyOutput, error) {
|
|
m.mu.RLock()
|
|
defer m.mu.RUnlock()
|
|
policy, ok := m.attachedUserPolicies[*input.UserName]
|
|
if !ok {
|
|
return nil, trace.NotFound("policy not found")
|
|
}
|
|
policyDocument, ok := policy[*input.PolicyName]
|
|
if !ok {
|
|
return nil, trace.NotFound("policy not found")
|
|
}
|
|
return &iam.GetUserPolicyOutput{
|
|
PolicyDocument: &policyDocument,
|
|
PolicyName: input.PolicyName,
|
|
UserName: input.UserName,
|
|
}, nil
|
|
}
|
|
|
|
func (m *IAMMock) PutUserPolicyWithContext(ctx aws.Context, input *iam.PutUserPolicyInput, options ...request.Option) (*iam.PutUserPolicyOutput, error) {
|
|
m.mu.Lock()
|
|
defer m.mu.Unlock()
|
|
if m.attachedUserPolicies == nil {
|
|
m.attachedUserPolicies = make(map[string]map[string]string)
|
|
}
|
|
if m.attachedUserPolicies[*input.UserName] == nil {
|
|
m.attachedUserPolicies[*input.UserName] = make(map[string]string)
|
|
}
|
|
m.attachedUserPolicies[*input.UserName][*input.PolicyName] = *input.PolicyDocument
|
|
return &iam.PutUserPolicyOutput{}, nil
|
|
}
|
|
|
|
func (m *IAMMock) DeleteUserPolicyWithContext(ctx aws.Context, input *iam.DeleteUserPolicyInput, options ...request.Option) (*iam.DeleteUserPolicyOutput, error) {
|
|
m.mu.Lock()
|
|
defer m.mu.Unlock()
|
|
if _, ok := m.attachedUserPolicies[*input.UserName]; ok {
|
|
delete(m.attachedUserPolicies[*input.UserName], *input.PolicyName)
|
|
}
|
|
return &iam.DeleteUserPolicyOutput{}, nil
|
|
}
|
|
|
|
// RedshiftMock mocks AWS Redshift API.
|
|
type RedshiftMock struct {
|
|
redshiftiface.RedshiftAPI
|
|
Clusters []*redshift.Cluster
|
|
}
|
|
|
|
func (m *RedshiftMock) DescribeClustersWithContext(ctx aws.Context, input *redshift.DescribeClustersInput, options ...request.Option) (*redshift.DescribeClustersOutput, error) {
|
|
if aws.StringValue(input.ClusterIdentifier) == "" {
|
|
return &redshift.DescribeClustersOutput{
|
|
Clusters: m.Clusters,
|
|
}, nil
|
|
}
|
|
for _, cluster := range m.Clusters {
|
|
if aws.StringValue(cluster.ClusterIdentifier) == aws.StringValue(input.ClusterIdentifier) {
|
|
return &redshift.DescribeClustersOutput{
|
|
Clusters: []*redshift.Cluster{cluster},
|
|
}, nil
|
|
}
|
|
}
|
|
return nil, trace.NotFound("cluster %v not found", aws.StringValue(input.ClusterIdentifier))
|
|
}
|
|
|
|
func (m *RedshiftMock) DescribeClustersPagesWithContext(ctx aws.Context, input *redshift.DescribeClustersInput, fn func(*redshift.DescribeClustersOutput, bool) bool, options ...request.Option) error {
|
|
fn(&redshift.DescribeClustersOutput{
|
|
Clusters: m.Clusters,
|
|
}, true)
|
|
return nil
|
|
}
|
|
|
|
// RDSMockUnauth is a mock RDS client that returns access denied to each call.
|
|
type RDSMockUnauth struct {
|
|
rdsiface.RDSAPI
|
|
}
|
|
|
|
func (m *RDSMockUnauth) DescribeDBInstancesWithContext(ctx aws.Context, input *rds.DescribeDBInstancesInput, options ...request.Option) (*rds.DescribeDBInstancesOutput, error) {
|
|
return nil, trace.AccessDenied("unauthorized")
|
|
}
|
|
|
|
func (m *RDSMockUnauth) DescribeDBClustersWithContext(ctx aws.Context, input *rds.DescribeDBClustersInput, options ...request.Option) (*rds.DescribeDBClustersOutput, error) {
|
|
return nil, trace.AccessDenied("unauthorized")
|
|
}
|
|
|
|
func (m *RDSMockUnauth) ModifyDBInstanceWithContext(ctx aws.Context, input *rds.ModifyDBInstanceInput, options ...request.Option) (*rds.ModifyDBInstanceOutput, error) {
|
|
return nil, trace.AccessDenied("unauthorized")
|
|
}
|
|
|
|
func (m *RDSMockUnauth) ModifyDBClusterWithContext(ctx aws.Context, input *rds.ModifyDBClusterInput, options ...request.Option) (*rds.ModifyDBClusterOutput, error) {
|
|
return nil, trace.AccessDenied("unauthorized")
|
|
}
|
|
|
|
func (m *RDSMockUnauth) DescribeDBInstancesPagesWithContext(ctx aws.Context, input *rds.DescribeDBInstancesInput, fn func(*rds.DescribeDBInstancesOutput, bool) bool, options ...request.Option) error {
|
|
return trace.AccessDenied("unauthorized")
|
|
}
|
|
|
|
func (m *RDSMockUnauth) DescribeDBClustersPagesWithContext(aws aws.Context, input *rds.DescribeDBClustersInput, fn func(*rds.DescribeDBClustersOutput, bool) bool, options ...request.Option) error {
|
|
return trace.AccessDenied("unauthorized")
|
|
}
|
|
func (m *RDSMockUnauth) DescribeDBProxiesWithContext(ctx aws.Context, input *rds.DescribeDBProxiesInput, options ...request.Option) (*rds.DescribeDBProxiesOutput, error) {
|
|
return nil, trace.AccessDenied("unauthorized")
|
|
}
|
|
func (m *RDSMockUnauth) DescribeDBProxyEndpointsWithContext(ctx aws.Context, input *rds.DescribeDBProxyEndpointsInput, options ...request.Option) (*rds.DescribeDBProxyEndpointsOutput, error) {
|
|
return nil, trace.AccessDenied("unauthorized")
|
|
}
|
|
func (m *RDSMockUnauth) DescribeDBProxiesPagesWithContext(ctx aws.Context, input *rds.DescribeDBProxiesInput, fn func(*rds.DescribeDBProxiesOutput, bool) bool, options ...request.Option) error {
|
|
return trace.AccessDenied("unauthorized")
|
|
}
|
|
|
|
// RDSMockByDBType is a mock RDS client that mocks API calls by DB type
|
|
type RDSMockByDBType struct {
|
|
rdsiface.RDSAPI
|
|
DBInstances rdsiface.RDSAPI
|
|
DBClusters rdsiface.RDSAPI
|
|
DBProxies rdsiface.RDSAPI
|
|
}
|
|
|
|
func (m *RDSMockByDBType) DescribeDBInstancesWithContext(ctx aws.Context, input *rds.DescribeDBInstancesInput, options ...request.Option) (*rds.DescribeDBInstancesOutput, error) {
|
|
return m.DBInstances.DescribeDBInstancesWithContext(ctx, input, options...)
|
|
}
|
|
func (m *RDSMockByDBType) ModifyDBInstanceWithContext(ctx aws.Context, input *rds.ModifyDBInstanceInput, options ...request.Option) (*rds.ModifyDBInstanceOutput, error) {
|
|
return m.DBInstances.ModifyDBInstanceWithContext(ctx, input, options...)
|
|
}
|
|
func (m *RDSMockByDBType) DescribeDBInstancesPagesWithContext(ctx aws.Context, input *rds.DescribeDBInstancesInput, fn func(*rds.DescribeDBInstancesOutput, bool) bool, options ...request.Option) error {
|
|
return m.DBInstances.DescribeDBInstancesPagesWithContext(ctx, input, fn, options...)
|
|
}
|
|
|
|
func (m *RDSMockByDBType) DescribeDBClustersWithContext(ctx aws.Context, input *rds.DescribeDBClustersInput, options ...request.Option) (*rds.DescribeDBClustersOutput, error) {
|
|
return m.DBClusters.DescribeDBClustersWithContext(ctx, input, options...)
|
|
}
|
|
func (m *RDSMockByDBType) ModifyDBClusterWithContext(ctx aws.Context, input *rds.ModifyDBClusterInput, options ...request.Option) (*rds.ModifyDBClusterOutput, error) {
|
|
return m.DBClusters.ModifyDBClusterWithContext(ctx, input, options...)
|
|
}
|
|
func (m *RDSMockByDBType) DescribeDBClustersPagesWithContext(aws aws.Context, input *rds.DescribeDBClustersInput, fn func(*rds.DescribeDBClustersOutput, bool) bool, options ...request.Option) error {
|
|
return m.DBClusters.DescribeDBClustersPagesWithContext(aws, input, fn, options...)
|
|
}
|
|
func (m *RDSMockByDBType) DescribeDBProxiesWithContext(ctx aws.Context, input *rds.DescribeDBProxiesInput, options ...request.Option) (*rds.DescribeDBProxiesOutput, error) {
|
|
return m.DBProxies.DescribeDBProxiesWithContext(ctx, input, options...)
|
|
}
|
|
func (m *RDSMockByDBType) DescribeDBProxyEndpointsWithContext(ctx aws.Context, input *rds.DescribeDBProxyEndpointsInput, options ...request.Option) (*rds.DescribeDBProxyEndpointsOutput, error) {
|
|
return m.DBProxies.DescribeDBProxyEndpointsWithContext(ctx, input, options...)
|
|
}
|
|
func (m *RDSMockByDBType) DescribeDBProxiesPagesWithContext(ctx aws.Context, input *rds.DescribeDBProxiesInput, fn func(*rds.DescribeDBProxiesOutput, bool) bool, options ...request.Option) error {
|
|
return m.DBProxies.DescribeDBProxiesPagesWithContext(ctx, input, fn, options...)
|
|
}
|
|
|
|
// RedshiftMockUnauth is a mock Redshift client that returns access denied to each call.
|
|
type RedshiftMockUnauth struct {
|
|
redshiftiface.RedshiftAPI
|
|
}
|
|
|
|
func (m *RedshiftMockUnauth) DescribeClustersWithContext(ctx aws.Context, input *redshift.DescribeClustersInput, options ...request.Option) (*redshift.DescribeClustersOutput, error) {
|
|
return nil, trace.AccessDenied("unauthorized")
|
|
}
|
|
|
|
// IAMErrorMock is a mock IAM client that returns the provided Error to all
|
|
// APIs. If Error is not provided, all APIs returns trace.AccessDenied by
|
|
// default.
|
|
type IAMErrorMock struct {
|
|
iamiface.IAMAPI
|
|
Error error
|
|
}
|
|
|
|
func (m *IAMErrorMock) GetRolePolicyWithContext(ctx aws.Context, input *iam.GetRolePolicyInput, options ...request.Option) (*iam.GetRolePolicyOutput, error) {
|
|
if m.Error != nil {
|
|
return nil, m.Error
|
|
}
|
|
return nil, trace.AccessDenied("unauthorized")
|
|
}
|
|
|
|
func (m *IAMErrorMock) PutRolePolicyWithContext(ctx aws.Context, input *iam.PutRolePolicyInput, options ...request.Option) (*iam.PutRolePolicyOutput, error) {
|
|
if m.Error != nil {
|
|
return nil, m.Error
|
|
}
|
|
return nil, trace.AccessDenied("unauthorized")
|
|
}
|
|
|
|
func (m *IAMErrorMock) GetUserPolicyWithContext(ctx aws.Context, input *iam.GetUserPolicyInput, options ...request.Option) (*iam.GetUserPolicyOutput, error) {
|
|
if m.Error != nil {
|
|
return nil, m.Error
|
|
}
|
|
return nil, trace.AccessDenied("unauthorized")
|
|
}
|
|
|
|
func (m *IAMErrorMock) PutUserPolicyWithContext(ctx aws.Context, input *iam.PutUserPolicyInput, options ...request.Option) (*iam.PutUserPolicyOutput, error) {
|
|
if m.Error != nil {
|
|
return nil, m.Error
|
|
}
|
|
return nil, trace.AccessDenied("unauthorized")
|
|
}
|
|
|
|
// ElastiCache mocks AWS ElastiCache API.
|
|
type ElastiCacheMock struct {
|
|
elasticacheiface.ElastiCacheAPI
|
|
|
|
ReplicationGroups []*elasticache.ReplicationGroup
|
|
Users []*elasticache.User
|
|
TagsByARN map[string][]*elasticache.Tag
|
|
}
|
|
|
|
func (m *ElastiCacheMock) AddMockUser(user *elasticache.User, tagsMap map[string]string) {
|
|
m.Users = append(m.Users, user)
|
|
m.addTags(aws.StringValue(user.ARN), tagsMap)
|
|
}
|
|
func (m *ElastiCacheMock) addTags(arn string, tagsMap map[string]string) {
|
|
if m.TagsByARN == nil {
|
|
m.TagsByARN = make(map[string][]*elasticache.Tag)
|
|
}
|
|
|
|
var tags []*elasticache.Tag
|
|
for key, value := range tagsMap {
|
|
tags = append(tags, &elasticache.Tag{
|
|
Key: aws.String(key),
|
|
Value: aws.String(value),
|
|
})
|
|
}
|
|
m.TagsByARN[arn] = tags
|
|
}
|
|
|
|
func (m *ElastiCacheMock) DescribeReplicationGroupsWithContext(_ aws.Context, input *elasticache.DescribeReplicationGroupsInput, opts ...request.Option) (*elasticache.DescribeReplicationGroupsOutput, error) {
|
|
for _, replicationGroup := range m.ReplicationGroups {
|
|
if aws.StringValue(replicationGroup.ReplicationGroupId) == aws.StringValue(input.ReplicationGroupId) {
|
|
return &elasticache.DescribeReplicationGroupsOutput{
|
|
ReplicationGroups: []*elasticache.ReplicationGroup{replicationGroup},
|
|
}, nil
|
|
}
|
|
}
|
|
return nil, trace.NotFound("ElastiCache %v not found", aws.StringValue(input.ReplicationGroupId))
|
|
}
|
|
func (m *ElastiCacheMock) DescribeReplicationGroupsPagesWithContext(_ aws.Context, _ *elasticache.DescribeReplicationGroupsInput, fn func(*elasticache.DescribeReplicationGroupsOutput, bool) bool, _ ...request.Option) error {
|
|
fn(&elasticache.DescribeReplicationGroupsOutput{
|
|
ReplicationGroups: m.ReplicationGroups,
|
|
}, true)
|
|
return nil
|
|
}
|
|
func (m *ElastiCacheMock) DescribeUsersPagesWithContext(_ aws.Context, _ *elasticache.DescribeUsersInput, fn func(*elasticache.DescribeUsersOutput, bool) bool, _ ...request.Option) error {
|
|
fn(&elasticache.DescribeUsersOutput{
|
|
Users: m.Users,
|
|
}, true)
|
|
return nil
|
|
}
|
|
|
|
func (m *ElastiCacheMock) DescribeCacheClustersPagesWithContext(aws.Context, *elasticache.DescribeCacheClustersInput, func(*elasticache.DescribeCacheClustersOutput, bool) bool, ...request.Option) error {
|
|
return trace.AccessDenied("unauthorized")
|
|
}
|
|
func (m *ElastiCacheMock) DescribeCacheSubnetGroupsPagesWithContext(aws.Context, *elasticache.DescribeCacheSubnetGroupsInput, func(*elasticache.DescribeCacheSubnetGroupsOutput, bool) bool, ...request.Option) error {
|
|
return trace.AccessDenied("unauthorized")
|
|
}
|
|
func (m *ElastiCacheMock) ListTagsForResourceWithContext(_ aws.Context, input *elasticache.ListTagsForResourceInput, _ ...request.Option) (*elasticache.TagListMessage, error) {
|
|
if m.TagsByARN == nil {
|
|
return nil, trace.NotFound("no tags")
|
|
}
|
|
|
|
tags, ok := m.TagsByARN[aws.StringValue(input.ResourceName)]
|
|
if !ok {
|
|
return nil, trace.NotFound("no tags")
|
|
}
|
|
|
|
return &elasticache.TagListMessage{
|
|
TagList: tags,
|
|
}, nil
|
|
}
|
|
func (m *ElastiCacheMock) ModifyUserWithContext(_ aws.Context, input *elasticache.ModifyUserInput, opts ...request.Option) (*elasticache.ModifyUserOutput, error) {
|
|
for _, user := range m.Users {
|
|
if aws.StringValue(user.UserId) == aws.StringValue(input.UserId) {
|
|
return &elasticache.ModifyUserOutput{}, nil
|
|
}
|
|
}
|
|
return nil, trace.NotFound("user %s not found", aws.StringValue(input.UserId))
|
|
}
|
|
|
|
// MemoryDBMock mocks AWS MemoryDB API.
|
|
type MemoryDBMock struct {
|
|
memorydbiface.MemoryDBAPI
|
|
|
|
Clusters []*memorydb.Cluster
|
|
Users []*memorydb.User
|
|
TagsByARN map[string][]*memorydb.Tag
|
|
}
|
|
|
|
func (m *MemoryDBMock) AddMockUser(user *memorydb.User, tagsMap map[string]string) {
|
|
m.Users = append(m.Users, user)
|
|
m.addTags(aws.StringValue(user.ARN), tagsMap)
|
|
}
|
|
func (m *MemoryDBMock) addTags(arn string, tagsMap map[string]string) {
|
|
if m.TagsByARN == nil {
|
|
m.TagsByARN = make(map[string][]*memorydb.Tag)
|
|
}
|
|
|
|
var tags []*memorydb.Tag
|
|
for key, value := range tagsMap {
|
|
tags = append(tags, &memorydb.Tag{
|
|
Key: aws.String(key),
|
|
Value: aws.String(value),
|
|
})
|
|
}
|
|
m.TagsByARN[arn] = tags
|
|
}
|
|
func (m *MemoryDBMock) DescribeSubnetGroupsWithContext(aws.Context, *memorydb.DescribeSubnetGroupsInput, ...request.Option) (*memorydb.DescribeSubnetGroupsOutput, error) {
|
|
return nil, trace.AccessDenied("unauthorized")
|
|
}
|
|
func (m *MemoryDBMock) DescribeClustersWithContext(_ aws.Context, input *memorydb.DescribeClustersInput, _ ...request.Option) (*memorydb.DescribeClustersOutput, error) {
|
|
|
|
if aws.StringValue(input.ClusterName) == "" {
|
|
return &memorydb.DescribeClustersOutput{
|
|
Clusters: m.Clusters,
|
|
}, nil
|
|
}
|
|
|
|
for _, cluster := range m.Clusters {
|
|
if aws.StringValue(input.ClusterName) == aws.StringValue(cluster.Name) {
|
|
return &memorydb.DescribeClustersOutput{
|
|
Clusters: []*memorydb.Cluster{cluster},
|
|
}, nil
|
|
}
|
|
}
|
|
return nil, trace.NotFound("cluster %v not found", aws.StringValue(input.ClusterName))
|
|
}
|
|
func (m *MemoryDBMock) ListTagsWithContext(_ aws.Context, input *memorydb.ListTagsInput, _ ...request.Option) (*memorydb.ListTagsOutput, error) {
|
|
if m.TagsByARN == nil {
|
|
return nil, trace.NotFound("no tags")
|
|
}
|
|
|
|
tags, ok := m.TagsByARN[aws.StringValue(input.ResourceArn)]
|
|
if !ok {
|
|
return nil, trace.NotFound("no tags")
|
|
}
|
|
|
|
return &memorydb.ListTagsOutput{
|
|
TagList: tags,
|
|
}, nil
|
|
}
|
|
func (m *MemoryDBMock) DescribeUsersWithContext(aws.Context, *memorydb.DescribeUsersInput, ...request.Option) (*memorydb.DescribeUsersOutput, error) {
|
|
return &memorydb.DescribeUsersOutput{
|
|
Users: m.Users,
|
|
}, nil
|
|
}
|
|
func (m *MemoryDBMock) UpdateUserWithContext(_ aws.Context, input *memorydb.UpdateUserInput, opts ...request.Option) (*memorydb.UpdateUserOutput, error) {
|
|
for _, user := range m.Users {
|
|
if aws.StringValue(user.Name) == aws.StringValue(input.UserName) {
|
|
return &memorydb.UpdateUserOutput{}, nil
|
|
}
|
|
}
|
|
return nil, trace.NotFound("user %s not found", aws.StringValue(input.UserName))
|
|
}
|
|
|
|
// checkEngineFilters checks RDS filters to detect unrecognized engine filters.
|
|
func checkEngineFilters(filters []*rds.Filter, engineVersions []*rds.DBEngineVersion) error {
|
|
if len(filters) == 0 {
|
|
return nil
|
|
}
|
|
recognizedEngines := make(map[string]struct{})
|
|
for _, e := range engineVersions {
|
|
recognizedEngines[aws.StringValue(e.Engine)] = struct{}{}
|
|
}
|
|
for _, f := range filters {
|
|
if aws.StringValue(f.Name) != "engine" {
|
|
continue
|
|
}
|
|
for _, v := range f.Values {
|
|
if _, ok := recognizedEngines[aws.StringValue(v)]; !ok {
|
|
return trace.Errorf("unrecognized engine name %q", aws.StringValue(v))
|
|
}
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// applyInstanceFilters filters RDS DBInstances using the provided RDS filters.
|
|
func applyInstanceFilters(in []*rds.DBInstance, filters []*rds.Filter) ([]*rds.DBInstance, error) {
|
|
if len(filters) == 0 {
|
|
return in, nil
|
|
}
|
|
var out []*rds.DBInstance
|
|
efs := engineFilterSet(filters)
|
|
for _, instance := range in {
|
|
if instanceEngineMatches(instance, efs) {
|
|
out = append(out, instance)
|
|
}
|
|
}
|
|
return out, nil
|
|
}
|
|
|
|
// applyClusterFilters filters RDS DBClusters using the provided RDS filters.
|
|
func applyClusterFilters(in []*rds.DBCluster, filters []*rds.Filter) ([]*rds.DBCluster, error) {
|
|
if len(filters) == 0 {
|
|
return in, nil
|
|
}
|
|
var out []*rds.DBCluster
|
|
efs := engineFilterSet(filters)
|
|
for _, cluster := range in {
|
|
if clusterEngineMatches(cluster, efs) {
|
|
out = append(out, cluster)
|
|
}
|
|
}
|
|
return out, nil
|
|
}
|
|
|
|
// engineFilterSet builds a string set of engine names from a list of RDS filters.
|
|
func engineFilterSet(filters []*rds.Filter) map[string]struct{} {
|
|
out := make(map[string]struct{})
|
|
for _, f := range filters {
|
|
if aws.StringValue(f.Name) != "engine" {
|
|
continue
|
|
}
|
|
for _, v := range f.Values {
|
|
out[aws.StringValue(v)] = struct{}{}
|
|
}
|
|
}
|
|
return out
|
|
}
|
|
|
|
// instanceEngineMatches returns whether an RDS DBInstance engine matches any engine name in a filter set.
|
|
func instanceEngineMatches(instance *rds.DBInstance, filterSet map[string]struct{}) bool {
|
|
_, ok := filterSet[aws.StringValue(instance.Engine)]
|
|
return ok
|
|
}
|
|
|
|
// clusterEngineMatches returns whether an RDS DBCluster engine matches any engine name in a filter set.
|
|
func clusterEngineMatches(cluster *rds.DBCluster, filterSet map[string]struct{}) bool {
|
|
_, ok := filterSet[aws.StringValue(cluster.Engine)]
|
|
return ok
|
|
}
|