From 85eb6998b4457655d6842a1545cdc9a7b0b8861c Mon Sep 17 00:00:00 2001 From: Joel Diaz Date: Mon, 28 Jan 2019 17:16:01 -0500 Subject: [PATCH] WIP: credentials validation do a pre-flight check of permissions using cloud-credentials-operator validation to do a check on the creds being used for installation the initial list of permissions that gathers the AWS actions needed to perform an installation are taken verbatim from the IAM group permissions the hive team has been using to perform installation/uninstallation with (there absolutely could be some excess actions that used to be needed, but may no longer be needed) note that the permissions checks are done with the assumption of IAM policies consisting of 'Resource: "*"'. so a list of ["ec2:CreateRoute", "ec2:CreateSubnet"] is evaluated as whether we can peform ``` { "Statement": [ { "Action": [ "ec2:CreateRoute", "ec2:CreateSubnet" ], "Effect": "Allow", "Resource": "*" } ] } ``` --- Gopkg.lock | 34 +- pkg/asset/installconfig/platformcredscheck.go | 229 +++++- .../service/iam/iamiface/interface.go | 696 ++++++++++++++++++ .../cloud-credential-operator/LICENSE | 201 +++++ .../apis/cloudcredential/v1beta1/aws_types.go | 51 ++ .../pkg/apis/cloudcredential/v1beta1/codec.go | 111 +++ .../v1beta1/credentialsrequest_types.go | 134 ++++ .../pkg/apis/cloudcredential/v1beta1/doc.go | 23 + .../apis/cloudcredential/v1beta1/register.go | 46 ++ .../v1beta1/zz_generated.deepcopy.go | 235 ++++++ .../pkg/aws/client.go | 150 ++++ .../pkg/controller/assets/bindata.go | 106 +++ .../pkg/controller/utils/condition_utils.go | 119 +++ .../pkg/controller/utils/utils.go | 169 +++++ vendor/k8s.io/client-go/dynamic/interface.go | 59 ++ vendor/k8s.io/client-go/dynamic/scheme.go | 98 +++ vendor/k8s.io/client-go/dynamic/simple.go | 326 ++++++++ .../restmapper/category_expansion.go | 119 +++ .../k8s.io/client-go/restmapper/discovery.go | 339 +++++++++ .../k8s.io/client-go/restmapper/shortcut.go | 172 +++++ .../pkg/client/apiutil/apimachinery.go | 88 +++ .../controller-runtime/pkg/client/client.go | 162 ++++ .../pkg/client/client_cache.go | 145 ++++ .../pkg/client/interfaces.go | 292 ++++++++ .../controller-runtime/pkg/client/split.go | 59 ++ .../pkg/client/typed_client.go | 133 ++++ .../pkg/client/unstructured_client.go | 162 ++++ 27 files changed, 4451 insertions(+), 7 deletions(-) create mode 100644 vendor/github.com/aws/aws-sdk-go/service/iam/iamiface/interface.go create mode 100644 vendor/github.com/openshift/cloud-credential-operator/LICENSE create mode 100644 vendor/github.com/openshift/cloud-credential-operator/pkg/apis/cloudcredential/v1beta1/aws_types.go create mode 100644 vendor/github.com/openshift/cloud-credential-operator/pkg/apis/cloudcredential/v1beta1/codec.go create mode 100644 vendor/github.com/openshift/cloud-credential-operator/pkg/apis/cloudcredential/v1beta1/credentialsrequest_types.go create mode 100644 vendor/github.com/openshift/cloud-credential-operator/pkg/apis/cloudcredential/v1beta1/doc.go create mode 100644 vendor/github.com/openshift/cloud-credential-operator/pkg/apis/cloudcredential/v1beta1/register.go create mode 100644 vendor/github.com/openshift/cloud-credential-operator/pkg/apis/cloudcredential/v1beta1/zz_generated.deepcopy.go create mode 100644 vendor/github.com/openshift/cloud-credential-operator/pkg/aws/client.go create mode 100644 vendor/github.com/openshift/cloud-credential-operator/pkg/controller/assets/bindata.go create mode 100644 vendor/github.com/openshift/cloud-credential-operator/pkg/controller/utils/condition_utils.go create mode 100644 vendor/github.com/openshift/cloud-credential-operator/pkg/controller/utils/utils.go create mode 100644 vendor/k8s.io/client-go/dynamic/interface.go create mode 100644 vendor/k8s.io/client-go/dynamic/scheme.go create mode 100644 vendor/k8s.io/client-go/dynamic/simple.go create mode 100644 vendor/k8s.io/client-go/restmapper/category_expansion.go create mode 100644 vendor/k8s.io/client-go/restmapper/discovery.go create mode 100644 vendor/k8s.io/client-go/restmapper/shortcut.go create mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/client/apiutil/apimachinery.go create mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/client/client.go create mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/client/client_cache.go create mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/client/interfaces.go create mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/client/split.go create mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/client/typed_client.go create mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/client/unstructured_client.go diff --git a/Gopkg.lock b/Gopkg.lock index 77fa91cc722..88820a0e04e 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -33,7 +33,7 @@ version = "v2.0" [[projects]] - digest = "1:71aeaefbdd3162ffed6eb308354f677b71a5527fceecfe644391775601ccd673" + digest = "1:6847720f71c531763d731817bba9ea5563937dc2aa284670d6b4cdb181b29ab4" name = "github.com/aws/aws-sdk-go" packages = [ "aws", @@ -76,6 +76,7 @@ "service/elb", "service/elbv2", "service/iam", + "service/iam/iamiface", "service/resourcegroupstaggingapi", "service/route53", "service/s3", @@ -395,6 +396,19 @@ pruneopts = "NUT" revision = "f9132806c9914790e15f10d8c5d1e7a03408d7b2" +[[projects]] + branch = "master" + digest = "1:af1e2473c2f486475a443cb284779c8dfd7fe0df8f7b597577b2d42d47713749" + name = "github.com/openshift/cloud-credential-operator" + packages = [ + "pkg/apis/cloudcredential/v1beta1", + "pkg/aws", + "pkg/controller/assets", + "pkg/controller/utils", + ] + pruneopts = "NUT" + revision = "36a39e863058a89fde173173fcb3b14faf7181dc" + [[projects]] branch = "master" digest = "1:0889fa501ce44d01602f3721bbc52529bfe35469410b34d117c45916d43b1b22" @@ -743,10 +757,11 @@ version = "kubernetes-1.12.2" [[projects]] - digest = "1:08027a07c9a263deb5f51fcc801996e7d453b1ed1318c6c5eb7affd084bff3a9" + digest = "1:d4077b20d8ba3b64ff57af190a5aee42167d7cd6f3788ad0d67bdc7b427f4697" name = "k8s.io/client-go" packages = [ "discovery", + "dynamic", "kubernetes", "kubernetes/scheme", "kubernetes/typed/admissionregistration/v1alpha1", @@ -787,6 +802,7 @@ "plugin/pkg/client/auth/exec", "rest", "rest/watch", + "restmapper", "tools/auth", "tools/cache", "tools/clientcmd", @@ -855,12 +871,16 @@ source = "https://github.com/kubernetes-sigs/cluster-api-provider-openstack.git" [[projects]] - digest = "1:84a8609383bec11b71d52dd813f33f1d16614b91966940bdc2aa79bea864fa25" + digest = "1:9b89872389bed1e6647547b868c3f9fa813f8adf098ba0984bc672e4b78ae235" name = "sigs.k8s.io/controller-runtime" - packages = ["pkg/runtime/scheme"] + packages = [ + "pkg/client", + "pkg/client/apiutil", + "pkg/runtime/scheme", + ] pruneopts = "NUT" - revision = "5fd1e9e9fac5261e9ad9d47c375afc014fc31d21" - version = "v0.1.7" + revision = "12d98582e72927b6cd0123e2b4e819f9341ce62c" + version = "v0.1.10" [[projects]] digest = "1:8730e0150dfb2b7e173890c8b9868e7a273082ef8e39f4940e3506a481cf895c" @@ -916,6 +936,8 @@ "github.com/openshift/api/config/v1", "github.com/openshift/client-go/config/clientset/versioned", "github.com/openshift/client-go/route/clientset/versioned", + "github.com/openshift/cloud-credential-operator/pkg/aws", + "github.com/openshift/cloud-credential-operator/pkg/controller/utils", "github.com/openshift/cluster-api-provider-libvirt/pkg/apis/libvirtproviderconfig/v1alpha1", "github.com/openshift/cluster-network-operator/pkg/apis/networkoperator/v1", "github.com/openshift/library-go/pkg/config/clusteroperator/v1helpers", diff --git a/pkg/asset/installconfig/platformcredscheck.go b/pkg/asset/installconfig/platformcredscheck.go index 671ae141974..42c93797127 100644 --- a/pkg/asset/installconfig/platformcredscheck.go +++ b/pkg/asset/installconfig/platformcredscheck.go @@ -3,6 +3,8 @@ package installconfig import ( "fmt" + "github.com/sirupsen/logrus" + "github.com/gophercloud/utils/openstack/clientconfig" "github.com/openshift/installer/pkg/asset" awsconfig "github.com/openshift/installer/pkg/asset/installconfig/aws" @@ -10,8 +12,179 @@ import ( "github.com/openshift/installer/pkg/types/libvirt" "github.com/openshift/installer/pkg/types/none" "github.com/openshift/installer/pkg/types/openstack" + + ccaws "github.com/openshift/cloud-credential-operator/pkg/aws" + credvalidator "github.com/openshift/cloud-credential-operator/pkg/controller/utils" ) +var installPermissionsAWS = []string{ + // EC2 related perms + "ec2:AllocateAddress", + "ec2:AssociateAddress", + "ec2:AssociateDhcpOptions", + "ec2:AssociateRouteTable", + "ec2:AttachInternetGateway", + "ec2:AuthorizeSecurityGroupEgress", + "ec2:AuthorizeSecurityGroupIngress", + "ec2:CreateDhcpOptions", + "ec2:CreateInternetGateway", + "ec2:CreateNatGateway", + "ec2:CreateRoute", + "ec2:CreateRouteTable", + "ec2:CreateSecurityGroup", + "ec2:CreateSubnet", + "ec2:CreateTags", + "ec2:CreateVpc", + "ec2:CreateVpcEndpoint", + "ec2:CreateVolume", + "ec2:DescribeAccountAttributes", + "ec2:DescribeAddresses", + "ec2:DescribeAvailabilityZones", + "ec2:DescribeDhcpOptions", + "ec2:DescribeImages", + "ec2:DescribeInstanceAttribute", + "ec2:DescribeInstanceCreditSpecifications", + "ec2:DescribeInstances", + "ec2:DescribeInternetGateways", + "ec2:DescribeKeyPairs", + "ec2:DescribeNatGateways", + "ec2:DescribeNetworkAcls", + "ec2:DescribePrefixLists", + "ec2:DescribeRegions", + "ec2:DescribeRouteTables", + "ec2:DescribeSecurityGroups", + "ec2:DescribeSubnets", + "ec2:DescribeTags", + "ec2:DescribeVpcEndpoints", + "ec2:DescribeVpcs", + "ec2:DescribeVpcAttribute", + "ec2:DescribeVolumes", + "ec2:DescribeVpcClassicLink", + "ec2:DescribeVpcClassicLinkDnsSupport", + "ec2:ModifyInstanceAttribute", + "ec2:ModifySubnetAttribute", + "ec2:ModifyVpcAttribute", + "ec2:RevokeSecurityGroupEgress", + "ec2:RunInstances", + "ec2:TerminateInstances", + "ec2:DeleteDhcpOptions", + "ec2:DeleteRoute", + "ec2:RevokeSecurityGroupIngress", + "ec2:DisassociateRouteTable", + "ec2:ReplaceRouteTableAssociation", + "ec2:DeleteRouteTable", + "ec2:DeleteSubnet", + "ec2:DescribeNetworkInterfaces", + "ec2:ModifyNetworkInterfaceAttribute", + "ec2:DeleteNatGateway", + "ec2:DeleteSecurityGroup", + "ec2:DetachInternetGateway", + "ec2:DeleteInternetGateway", + "ec2:ReleaseAddress", + "ec2:DeleteVpc", + + // ELB related perms + "elasticloadbalancing:AddTags", + "elasticloadbalancing:ApplySecurityGroupsToLoadBalancer", + "elasticloadbalancing:AttachLoadBalancerToSubnets", + "elasticloadbalancing:CreateListener", + "elasticloadbalancing:CreateLoadBalancer", + "elasticloadbalancing:CreateLoadBalancerListeners", + "elasticloadbalancing:CreateTargetGroup", + "elasticloadbalancing:ConfigureHealthCheck", + "elasticloadbalancing:DeleteLoadBalancer", + "elasticloadbalancing:DeregisterInstancesFromLoadBalancer", + "elasticloadbalancing:DeregisterTargets", + "elasticloadbalancing:DescribeInstanceHealth", + "elasticloadbalancing:DescribeListeners", + "elasticloadbalancing:DescribeLoadBalancers", + "elasticloadbalancing:DescribeLoadBalancerAttributes", + "elasticloadbalancing:DescribeTags", + "elasticloadbalancing:DescribeTargetGroupAttributes", + "elasticloadbalancing:DescribeTargetHealth", + "elasticloadbalancing:ModifyLoadBalancerAttributes", + "elasticloadbalancing:ModifyTargetGroup", + "elasticloadbalancing:ModifyTargetGroupAttributes", + "elasticloadbalancing:RegisterTargets", + "elasticloadbalancing:RegisterInstancesWithLoadBalancer", + "elasticloadbalancing:SetLoadBalancerPoliciesOfListener", + + // IAM related perms + "iam:AddRoleToInstanceProfile", + "iam:CreateInstanceProfile", + "iam:CreateRole", + "iam:GetInstanceProfile", + "iam:GetUser", + "iam:GetRole", + "iam:GetRolePolicy", + "iam:PassRole", + "iam:PutRolePolicy", + "iam:DeleteRolePolicy", + "iam:RemoveRoleFromInstanceProfile", + "iam:DeleteInstanceProfile", + "iam:ListInstanceProfilesForRole", + "iam:ListRoles", + "iam:DeleteRole", + + // Route53 related perms + "route53:ChangeResourceRecordSets", + "route53:ChangeTagsForResource", + "route53:GetChange", + "route53:GetHostedZone", + "route53:CreateHostedZone", + "route53:DeleteHostedZone", + "route53:ListHostedZones", + "route53:ListHostedZonesByName", + "route53:ListResourceRecordSets", + "route53:ListTagsForResource", + "route53:UpdateHostedZoneComment", + + // S3 related perms + "s3:CreateBucket", + "s3:ListBucket", + "s3:GetBucketCors", + "s3:GetBucketWebsite", + "s3:GetBucketVersioning", + "s3:GetAccelerateConfiguration", + "s3:GetEncryptionConfiguration", + "s3:GetBucketRequestPayment", + "s3:GetBucketLogging", + "s3:GetLifecycleConfiguration", + "s3:GetBucketReplication", + "s3:GetReplicationConfiguration", + "s3:GetBucketLocation", + "s3:GetBucketTagging", + "s3:DeleteBucket", + "s3:PutBucketAcl", + "s3:PutBucketTagging", + "s3:PutEncryptionConfiguration", + + // More S3 (would be nice to ) + "s3:PutObject", + "s3:PutObjectAcl", + "s3:PutObjectTagging", + "s3:GetObject", + "s3:GetObjectAcl", + "s3:GetObjectTagging", + "s3:GetObjectVersion", + "s3:DeleteObject", + + // ??? + "sts:GetCallerIdentity", + + // Uninstall-specific perms + "autoscaling:DescribeAutoScalingGroups", + "ec2:DeleteNetworkInterface", + "ec2:DeleteVolume", + "ec2:DeleteVpcEndpoints", + "elasticloadbalancing:DescribeTargetGroups", + "elasticloadbalancing:DeleteTargetGroup", + "iam:ListInstanceProfiles", + "iam:ListRolePolicies", + "s3:ListAllMyBuckets", + "tag:GetResources", +} + // PlatformCredsCheck is an asset that checks the platform credentials, asks for them or errors out if invalid // the cluster. type PlatformCredsCheck struct { @@ -35,7 +208,7 @@ func (a *PlatformCredsCheck) Generate(dependencies asset.Parents) error { platform := ic.Config.Platform.Name() switch platform { case aws.Name: - _, err = awsconfig.GetSession() + err = validateAWSCreds() case libvirt.Name: case none.Name: case openstack.Name: @@ -46,6 +219,14 @@ func (a *PlatformCredsCheck) Generate(dependencies asset.Parents) error { err = fmt.Errorf("unknown platform type %q", platform) } + if err != nil { + return err + } + + if ic != nil { + panic(fmt.Sprintf("XXX DONT PROVISION")) + } + return err } @@ -53,3 +234,49 @@ func (a *PlatformCredsCheck) Generate(dependencies asset.Parents) error { func (a *PlatformCredsCheck) Name() string { return "Platform Credentials Check" } + +func validateAWSCreds() error { + ssn, err := awsconfig.GetSession() + if err != nil { + return err + } + + creds, err := ssn.Config.Credentials.Get() + if err != nil { + return err + } + + logger := logrus.New() + awsClient, err := ccaws.NewClient([]byte(creds.AccessKeyID), []byte(creds.SecretAccessKey)) + if err != nil { + return fmt.Errorf("error building aws client to check credentials against: %v", err) + } + + // Check whether we can do an installation + canInstall, err := credvalidator.CheckPermissionsAgainstActions(awsClient, installPermissionsAWS, logger) + if err != nil { + return fmt.Errorf("error checking whether we have enough permissions to install: %v", err) + } + if !canInstall { + return fmt.Errorf("current credentials insufficient for performing cluster installation") + } + + // Check whether we can mint new creds for cluster services interacting with the cloud + canMint, err := credvalidator.CheckCloudCredCreation(awsClient, logger) + if err != nil { + return fmt.Errorf("error checking whether we can mint new creds with current credentials: %v", err) + } + + // Check whether we can use the current credentials in passthrough mode to satisfy + // cluster services interacting with the cloud + canPassthrough, err := credvalidator.CheckCloudCredPassthrough(awsClient, logger) + if err != nil { + return fmt.Errorf("error checking whether we can use current creds in passthrough mode: %v", err) + } + + if !canMint && !canPassthrough { + return fmt.Errorf("AWS credentials cannot be used to either create new creds or use as-is") + } + + return nil +} diff --git a/vendor/github.com/aws/aws-sdk-go/service/iam/iamiface/interface.go b/vendor/github.com/aws/aws-sdk-go/service/iam/iamiface/interface.go new file mode 100644 index 00000000000..c0a7e7ed309 --- /dev/null +++ b/vendor/github.com/aws/aws-sdk-go/service/iam/iamiface/interface.go @@ -0,0 +1,696 @@ +// Code generated by private/model/cli/gen-api/main.go. DO NOT EDIT. + +// Package iamiface provides an interface to enable mocking the AWS Identity and Access Management service client +// for testing your code. +// +// It is important to note that this interface will have breaking changes +// when the service model is updated and adds new API operations, paginators, +// and waiters. +package iamiface + +import ( + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/request" + "github.com/aws/aws-sdk-go/service/iam" +) + +// IAMAPI provides an interface to enable mocking the +// iam.IAM service client's API operation, +// paginators, and waiters. This make unit testing your code that calls out +// to the SDK's service client's calls easier. +// +// The best way to use this interface is so the SDK's service client's calls +// can be stubbed out for unit testing your code with the SDK without needing +// to inject custom request handlers into the SDK's request pipeline. +// +// // myFunc uses an SDK service client to make a request to +// // AWS Identity and Access Management. +// func myFunc(svc iamiface.IAMAPI) bool { +// // Make svc.AddClientIDToOpenIDConnectProvider request +// } +// +// func main() { +// sess := session.New() +// svc := iam.New(sess) +// +// myFunc(svc) +// } +// +// In your _test.go file: +// +// // Define a mock struct to be used in your unit tests of myFunc. +// type mockIAMClient struct { +// iamiface.IAMAPI +// } +// func (m *mockIAMClient) AddClientIDToOpenIDConnectProvider(input *iam.AddClientIDToOpenIDConnectProviderInput) (*iam.AddClientIDToOpenIDConnectProviderOutput, error) { +// // mock response/functionality +// } +// +// func TestMyFunc(t *testing.T) { +// // Setup Test +// mockSvc := &mockIAMClient{} +// +// myfunc(mockSvc) +// +// // Verify myFunc's functionality +// } +// +// It is important to note that this interface will have breaking changes +// when the service model is updated and adds new API operations, paginators, +// and waiters. Its suggested to use the pattern above for testing, or using +// tooling to generate mocks to satisfy the interfaces. +type IAMAPI interface { + AddClientIDToOpenIDConnectProvider(*iam.AddClientIDToOpenIDConnectProviderInput) (*iam.AddClientIDToOpenIDConnectProviderOutput, error) + AddClientIDToOpenIDConnectProviderWithContext(aws.Context, *iam.AddClientIDToOpenIDConnectProviderInput, ...request.Option) (*iam.AddClientIDToOpenIDConnectProviderOutput, error) + AddClientIDToOpenIDConnectProviderRequest(*iam.AddClientIDToOpenIDConnectProviderInput) (*request.Request, *iam.AddClientIDToOpenIDConnectProviderOutput) + + AddRoleToInstanceProfile(*iam.AddRoleToInstanceProfileInput) (*iam.AddRoleToInstanceProfileOutput, error) + AddRoleToInstanceProfileWithContext(aws.Context, *iam.AddRoleToInstanceProfileInput, ...request.Option) (*iam.AddRoleToInstanceProfileOutput, error) + AddRoleToInstanceProfileRequest(*iam.AddRoleToInstanceProfileInput) (*request.Request, *iam.AddRoleToInstanceProfileOutput) + + AddUserToGroup(*iam.AddUserToGroupInput) (*iam.AddUserToGroupOutput, error) + AddUserToGroupWithContext(aws.Context, *iam.AddUserToGroupInput, ...request.Option) (*iam.AddUserToGroupOutput, error) + AddUserToGroupRequest(*iam.AddUserToGroupInput) (*request.Request, *iam.AddUserToGroupOutput) + + AttachGroupPolicy(*iam.AttachGroupPolicyInput) (*iam.AttachGroupPolicyOutput, error) + AttachGroupPolicyWithContext(aws.Context, *iam.AttachGroupPolicyInput, ...request.Option) (*iam.AttachGroupPolicyOutput, error) + AttachGroupPolicyRequest(*iam.AttachGroupPolicyInput) (*request.Request, *iam.AttachGroupPolicyOutput) + + AttachRolePolicy(*iam.AttachRolePolicyInput) (*iam.AttachRolePolicyOutput, error) + AttachRolePolicyWithContext(aws.Context, *iam.AttachRolePolicyInput, ...request.Option) (*iam.AttachRolePolicyOutput, error) + AttachRolePolicyRequest(*iam.AttachRolePolicyInput) (*request.Request, *iam.AttachRolePolicyOutput) + + AttachUserPolicy(*iam.AttachUserPolicyInput) (*iam.AttachUserPolicyOutput, error) + AttachUserPolicyWithContext(aws.Context, *iam.AttachUserPolicyInput, ...request.Option) (*iam.AttachUserPolicyOutput, error) + AttachUserPolicyRequest(*iam.AttachUserPolicyInput) (*request.Request, *iam.AttachUserPolicyOutput) + + ChangePassword(*iam.ChangePasswordInput) (*iam.ChangePasswordOutput, error) + ChangePasswordWithContext(aws.Context, *iam.ChangePasswordInput, ...request.Option) (*iam.ChangePasswordOutput, error) + ChangePasswordRequest(*iam.ChangePasswordInput) (*request.Request, *iam.ChangePasswordOutput) + + CreateAccessKey(*iam.CreateAccessKeyInput) (*iam.CreateAccessKeyOutput, error) + CreateAccessKeyWithContext(aws.Context, *iam.CreateAccessKeyInput, ...request.Option) (*iam.CreateAccessKeyOutput, error) + CreateAccessKeyRequest(*iam.CreateAccessKeyInput) (*request.Request, *iam.CreateAccessKeyOutput) + + CreateAccountAlias(*iam.CreateAccountAliasInput) (*iam.CreateAccountAliasOutput, error) + CreateAccountAliasWithContext(aws.Context, *iam.CreateAccountAliasInput, ...request.Option) (*iam.CreateAccountAliasOutput, error) + CreateAccountAliasRequest(*iam.CreateAccountAliasInput) (*request.Request, *iam.CreateAccountAliasOutput) + + CreateGroup(*iam.CreateGroupInput) (*iam.CreateGroupOutput, error) + CreateGroupWithContext(aws.Context, *iam.CreateGroupInput, ...request.Option) (*iam.CreateGroupOutput, error) + CreateGroupRequest(*iam.CreateGroupInput) (*request.Request, *iam.CreateGroupOutput) + + CreateInstanceProfile(*iam.CreateInstanceProfileInput) (*iam.CreateInstanceProfileOutput, error) + CreateInstanceProfileWithContext(aws.Context, *iam.CreateInstanceProfileInput, ...request.Option) (*iam.CreateInstanceProfileOutput, error) + CreateInstanceProfileRequest(*iam.CreateInstanceProfileInput) (*request.Request, *iam.CreateInstanceProfileOutput) + + CreateLoginProfile(*iam.CreateLoginProfileInput) (*iam.CreateLoginProfileOutput, error) + CreateLoginProfileWithContext(aws.Context, *iam.CreateLoginProfileInput, ...request.Option) (*iam.CreateLoginProfileOutput, error) + CreateLoginProfileRequest(*iam.CreateLoginProfileInput) (*request.Request, *iam.CreateLoginProfileOutput) + + CreateOpenIDConnectProvider(*iam.CreateOpenIDConnectProviderInput) (*iam.CreateOpenIDConnectProviderOutput, error) + CreateOpenIDConnectProviderWithContext(aws.Context, *iam.CreateOpenIDConnectProviderInput, ...request.Option) (*iam.CreateOpenIDConnectProviderOutput, error) + CreateOpenIDConnectProviderRequest(*iam.CreateOpenIDConnectProviderInput) (*request.Request, *iam.CreateOpenIDConnectProviderOutput) + + CreatePolicy(*iam.CreatePolicyInput) (*iam.CreatePolicyOutput, error) + CreatePolicyWithContext(aws.Context, *iam.CreatePolicyInput, ...request.Option) (*iam.CreatePolicyOutput, error) + CreatePolicyRequest(*iam.CreatePolicyInput) (*request.Request, *iam.CreatePolicyOutput) + + CreatePolicyVersion(*iam.CreatePolicyVersionInput) (*iam.CreatePolicyVersionOutput, error) + CreatePolicyVersionWithContext(aws.Context, *iam.CreatePolicyVersionInput, ...request.Option) (*iam.CreatePolicyVersionOutput, error) + CreatePolicyVersionRequest(*iam.CreatePolicyVersionInput) (*request.Request, *iam.CreatePolicyVersionOutput) + + CreateRole(*iam.CreateRoleInput) (*iam.CreateRoleOutput, error) + CreateRoleWithContext(aws.Context, *iam.CreateRoleInput, ...request.Option) (*iam.CreateRoleOutput, error) + CreateRoleRequest(*iam.CreateRoleInput) (*request.Request, *iam.CreateRoleOutput) + + CreateSAMLProvider(*iam.CreateSAMLProviderInput) (*iam.CreateSAMLProviderOutput, error) + CreateSAMLProviderWithContext(aws.Context, *iam.CreateSAMLProviderInput, ...request.Option) (*iam.CreateSAMLProviderOutput, error) + CreateSAMLProviderRequest(*iam.CreateSAMLProviderInput) (*request.Request, *iam.CreateSAMLProviderOutput) + + CreateServiceLinkedRole(*iam.CreateServiceLinkedRoleInput) (*iam.CreateServiceLinkedRoleOutput, error) + CreateServiceLinkedRoleWithContext(aws.Context, *iam.CreateServiceLinkedRoleInput, ...request.Option) (*iam.CreateServiceLinkedRoleOutput, error) + CreateServiceLinkedRoleRequest(*iam.CreateServiceLinkedRoleInput) (*request.Request, *iam.CreateServiceLinkedRoleOutput) + + CreateServiceSpecificCredential(*iam.CreateServiceSpecificCredentialInput) (*iam.CreateServiceSpecificCredentialOutput, error) + CreateServiceSpecificCredentialWithContext(aws.Context, *iam.CreateServiceSpecificCredentialInput, ...request.Option) (*iam.CreateServiceSpecificCredentialOutput, error) + CreateServiceSpecificCredentialRequest(*iam.CreateServiceSpecificCredentialInput) (*request.Request, *iam.CreateServiceSpecificCredentialOutput) + + CreateUser(*iam.CreateUserInput) (*iam.CreateUserOutput, error) + CreateUserWithContext(aws.Context, *iam.CreateUserInput, ...request.Option) (*iam.CreateUserOutput, error) + CreateUserRequest(*iam.CreateUserInput) (*request.Request, *iam.CreateUserOutput) + + CreateVirtualMFADevice(*iam.CreateVirtualMFADeviceInput) (*iam.CreateVirtualMFADeviceOutput, error) + CreateVirtualMFADeviceWithContext(aws.Context, *iam.CreateVirtualMFADeviceInput, ...request.Option) (*iam.CreateVirtualMFADeviceOutput, error) + CreateVirtualMFADeviceRequest(*iam.CreateVirtualMFADeviceInput) (*request.Request, *iam.CreateVirtualMFADeviceOutput) + + DeactivateMFADevice(*iam.DeactivateMFADeviceInput) (*iam.DeactivateMFADeviceOutput, error) + DeactivateMFADeviceWithContext(aws.Context, *iam.DeactivateMFADeviceInput, ...request.Option) (*iam.DeactivateMFADeviceOutput, error) + DeactivateMFADeviceRequest(*iam.DeactivateMFADeviceInput) (*request.Request, *iam.DeactivateMFADeviceOutput) + + DeleteAccessKey(*iam.DeleteAccessKeyInput) (*iam.DeleteAccessKeyOutput, error) + DeleteAccessKeyWithContext(aws.Context, *iam.DeleteAccessKeyInput, ...request.Option) (*iam.DeleteAccessKeyOutput, error) + DeleteAccessKeyRequest(*iam.DeleteAccessKeyInput) (*request.Request, *iam.DeleteAccessKeyOutput) + + DeleteAccountAlias(*iam.DeleteAccountAliasInput) (*iam.DeleteAccountAliasOutput, error) + DeleteAccountAliasWithContext(aws.Context, *iam.DeleteAccountAliasInput, ...request.Option) (*iam.DeleteAccountAliasOutput, error) + DeleteAccountAliasRequest(*iam.DeleteAccountAliasInput) (*request.Request, *iam.DeleteAccountAliasOutput) + + DeleteAccountPasswordPolicy(*iam.DeleteAccountPasswordPolicyInput) (*iam.DeleteAccountPasswordPolicyOutput, error) + DeleteAccountPasswordPolicyWithContext(aws.Context, *iam.DeleteAccountPasswordPolicyInput, ...request.Option) (*iam.DeleteAccountPasswordPolicyOutput, error) + DeleteAccountPasswordPolicyRequest(*iam.DeleteAccountPasswordPolicyInput) (*request.Request, *iam.DeleteAccountPasswordPolicyOutput) + + DeleteGroup(*iam.DeleteGroupInput) (*iam.DeleteGroupOutput, error) + DeleteGroupWithContext(aws.Context, *iam.DeleteGroupInput, ...request.Option) (*iam.DeleteGroupOutput, error) + DeleteGroupRequest(*iam.DeleteGroupInput) (*request.Request, *iam.DeleteGroupOutput) + + DeleteGroupPolicy(*iam.DeleteGroupPolicyInput) (*iam.DeleteGroupPolicyOutput, error) + DeleteGroupPolicyWithContext(aws.Context, *iam.DeleteGroupPolicyInput, ...request.Option) (*iam.DeleteGroupPolicyOutput, error) + DeleteGroupPolicyRequest(*iam.DeleteGroupPolicyInput) (*request.Request, *iam.DeleteGroupPolicyOutput) + + DeleteInstanceProfile(*iam.DeleteInstanceProfileInput) (*iam.DeleteInstanceProfileOutput, error) + DeleteInstanceProfileWithContext(aws.Context, *iam.DeleteInstanceProfileInput, ...request.Option) (*iam.DeleteInstanceProfileOutput, error) + DeleteInstanceProfileRequest(*iam.DeleteInstanceProfileInput) (*request.Request, *iam.DeleteInstanceProfileOutput) + + DeleteLoginProfile(*iam.DeleteLoginProfileInput) (*iam.DeleteLoginProfileOutput, error) + DeleteLoginProfileWithContext(aws.Context, *iam.DeleteLoginProfileInput, ...request.Option) (*iam.DeleteLoginProfileOutput, error) + DeleteLoginProfileRequest(*iam.DeleteLoginProfileInput) (*request.Request, *iam.DeleteLoginProfileOutput) + + DeleteOpenIDConnectProvider(*iam.DeleteOpenIDConnectProviderInput) (*iam.DeleteOpenIDConnectProviderOutput, error) + DeleteOpenIDConnectProviderWithContext(aws.Context, *iam.DeleteOpenIDConnectProviderInput, ...request.Option) (*iam.DeleteOpenIDConnectProviderOutput, error) + DeleteOpenIDConnectProviderRequest(*iam.DeleteOpenIDConnectProviderInput) (*request.Request, *iam.DeleteOpenIDConnectProviderOutput) + + DeletePolicy(*iam.DeletePolicyInput) (*iam.DeletePolicyOutput, error) + DeletePolicyWithContext(aws.Context, *iam.DeletePolicyInput, ...request.Option) (*iam.DeletePolicyOutput, error) + DeletePolicyRequest(*iam.DeletePolicyInput) (*request.Request, *iam.DeletePolicyOutput) + + DeletePolicyVersion(*iam.DeletePolicyVersionInput) (*iam.DeletePolicyVersionOutput, error) + DeletePolicyVersionWithContext(aws.Context, *iam.DeletePolicyVersionInput, ...request.Option) (*iam.DeletePolicyVersionOutput, error) + DeletePolicyVersionRequest(*iam.DeletePolicyVersionInput) (*request.Request, *iam.DeletePolicyVersionOutput) + + DeleteRole(*iam.DeleteRoleInput) (*iam.DeleteRoleOutput, error) + DeleteRoleWithContext(aws.Context, *iam.DeleteRoleInput, ...request.Option) (*iam.DeleteRoleOutput, error) + DeleteRoleRequest(*iam.DeleteRoleInput) (*request.Request, *iam.DeleteRoleOutput) + + DeleteRolePermissionsBoundary(*iam.DeleteRolePermissionsBoundaryInput) (*iam.DeleteRolePermissionsBoundaryOutput, error) + DeleteRolePermissionsBoundaryWithContext(aws.Context, *iam.DeleteRolePermissionsBoundaryInput, ...request.Option) (*iam.DeleteRolePermissionsBoundaryOutput, error) + DeleteRolePermissionsBoundaryRequest(*iam.DeleteRolePermissionsBoundaryInput) (*request.Request, *iam.DeleteRolePermissionsBoundaryOutput) + + DeleteRolePolicy(*iam.DeleteRolePolicyInput) (*iam.DeleteRolePolicyOutput, error) + DeleteRolePolicyWithContext(aws.Context, *iam.DeleteRolePolicyInput, ...request.Option) (*iam.DeleteRolePolicyOutput, error) + DeleteRolePolicyRequest(*iam.DeleteRolePolicyInput) (*request.Request, *iam.DeleteRolePolicyOutput) + + DeleteSAMLProvider(*iam.DeleteSAMLProviderInput) (*iam.DeleteSAMLProviderOutput, error) + DeleteSAMLProviderWithContext(aws.Context, *iam.DeleteSAMLProviderInput, ...request.Option) (*iam.DeleteSAMLProviderOutput, error) + DeleteSAMLProviderRequest(*iam.DeleteSAMLProviderInput) (*request.Request, *iam.DeleteSAMLProviderOutput) + + DeleteSSHPublicKey(*iam.DeleteSSHPublicKeyInput) (*iam.DeleteSSHPublicKeyOutput, error) + DeleteSSHPublicKeyWithContext(aws.Context, *iam.DeleteSSHPublicKeyInput, ...request.Option) (*iam.DeleteSSHPublicKeyOutput, error) + DeleteSSHPublicKeyRequest(*iam.DeleteSSHPublicKeyInput) (*request.Request, *iam.DeleteSSHPublicKeyOutput) + + DeleteServerCertificate(*iam.DeleteServerCertificateInput) (*iam.DeleteServerCertificateOutput, error) + DeleteServerCertificateWithContext(aws.Context, *iam.DeleteServerCertificateInput, ...request.Option) (*iam.DeleteServerCertificateOutput, error) + DeleteServerCertificateRequest(*iam.DeleteServerCertificateInput) (*request.Request, *iam.DeleteServerCertificateOutput) + + DeleteServiceLinkedRole(*iam.DeleteServiceLinkedRoleInput) (*iam.DeleteServiceLinkedRoleOutput, error) + DeleteServiceLinkedRoleWithContext(aws.Context, *iam.DeleteServiceLinkedRoleInput, ...request.Option) (*iam.DeleteServiceLinkedRoleOutput, error) + DeleteServiceLinkedRoleRequest(*iam.DeleteServiceLinkedRoleInput) (*request.Request, *iam.DeleteServiceLinkedRoleOutput) + + DeleteServiceSpecificCredential(*iam.DeleteServiceSpecificCredentialInput) (*iam.DeleteServiceSpecificCredentialOutput, error) + DeleteServiceSpecificCredentialWithContext(aws.Context, *iam.DeleteServiceSpecificCredentialInput, ...request.Option) (*iam.DeleteServiceSpecificCredentialOutput, error) + DeleteServiceSpecificCredentialRequest(*iam.DeleteServiceSpecificCredentialInput) (*request.Request, *iam.DeleteServiceSpecificCredentialOutput) + + DeleteSigningCertificate(*iam.DeleteSigningCertificateInput) (*iam.DeleteSigningCertificateOutput, error) + DeleteSigningCertificateWithContext(aws.Context, *iam.DeleteSigningCertificateInput, ...request.Option) (*iam.DeleteSigningCertificateOutput, error) + DeleteSigningCertificateRequest(*iam.DeleteSigningCertificateInput) (*request.Request, *iam.DeleteSigningCertificateOutput) + + DeleteUser(*iam.DeleteUserInput) (*iam.DeleteUserOutput, error) + DeleteUserWithContext(aws.Context, *iam.DeleteUserInput, ...request.Option) (*iam.DeleteUserOutput, error) + DeleteUserRequest(*iam.DeleteUserInput) (*request.Request, *iam.DeleteUserOutput) + + DeleteUserPermissionsBoundary(*iam.DeleteUserPermissionsBoundaryInput) (*iam.DeleteUserPermissionsBoundaryOutput, error) + DeleteUserPermissionsBoundaryWithContext(aws.Context, *iam.DeleteUserPermissionsBoundaryInput, ...request.Option) (*iam.DeleteUserPermissionsBoundaryOutput, error) + DeleteUserPermissionsBoundaryRequest(*iam.DeleteUserPermissionsBoundaryInput) (*request.Request, *iam.DeleteUserPermissionsBoundaryOutput) + + DeleteUserPolicy(*iam.DeleteUserPolicyInput) (*iam.DeleteUserPolicyOutput, error) + DeleteUserPolicyWithContext(aws.Context, *iam.DeleteUserPolicyInput, ...request.Option) (*iam.DeleteUserPolicyOutput, error) + DeleteUserPolicyRequest(*iam.DeleteUserPolicyInput) (*request.Request, *iam.DeleteUserPolicyOutput) + + DeleteVirtualMFADevice(*iam.DeleteVirtualMFADeviceInput) (*iam.DeleteVirtualMFADeviceOutput, error) + DeleteVirtualMFADeviceWithContext(aws.Context, *iam.DeleteVirtualMFADeviceInput, ...request.Option) (*iam.DeleteVirtualMFADeviceOutput, error) + DeleteVirtualMFADeviceRequest(*iam.DeleteVirtualMFADeviceInput) (*request.Request, *iam.DeleteVirtualMFADeviceOutput) + + DetachGroupPolicy(*iam.DetachGroupPolicyInput) (*iam.DetachGroupPolicyOutput, error) + DetachGroupPolicyWithContext(aws.Context, *iam.DetachGroupPolicyInput, ...request.Option) (*iam.DetachGroupPolicyOutput, error) + DetachGroupPolicyRequest(*iam.DetachGroupPolicyInput) (*request.Request, *iam.DetachGroupPolicyOutput) + + DetachRolePolicy(*iam.DetachRolePolicyInput) (*iam.DetachRolePolicyOutput, error) + DetachRolePolicyWithContext(aws.Context, *iam.DetachRolePolicyInput, ...request.Option) (*iam.DetachRolePolicyOutput, error) + DetachRolePolicyRequest(*iam.DetachRolePolicyInput) (*request.Request, *iam.DetachRolePolicyOutput) + + DetachUserPolicy(*iam.DetachUserPolicyInput) (*iam.DetachUserPolicyOutput, error) + DetachUserPolicyWithContext(aws.Context, *iam.DetachUserPolicyInput, ...request.Option) (*iam.DetachUserPolicyOutput, error) + DetachUserPolicyRequest(*iam.DetachUserPolicyInput) (*request.Request, *iam.DetachUserPolicyOutput) + + EnableMFADevice(*iam.EnableMFADeviceInput) (*iam.EnableMFADeviceOutput, error) + EnableMFADeviceWithContext(aws.Context, *iam.EnableMFADeviceInput, ...request.Option) (*iam.EnableMFADeviceOutput, error) + EnableMFADeviceRequest(*iam.EnableMFADeviceInput) (*request.Request, *iam.EnableMFADeviceOutput) + + GenerateCredentialReport(*iam.GenerateCredentialReportInput) (*iam.GenerateCredentialReportOutput, error) + GenerateCredentialReportWithContext(aws.Context, *iam.GenerateCredentialReportInput, ...request.Option) (*iam.GenerateCredentialReportOutput, error) + GenerateCredentialReportRequest(*iam.GenerateCredentialReportInput) (*request.Request, *iam.GenerateCredentialReportOutput) + + GenerateServiceLastAccessedDetails(*iam.GenerateServiceLastAccessedDetailsInput) (*iam.GenerateServiceLastAccessedDetailsOutput, error) + GenerateServiceLastAccessedDetailsWithContext(aws.Context, *iam.GenerateServiceLastAccessedDetailsInput, ...request.Option) (*iam.GenerateServiceLastAccessedDetailsOutput, error) + GenerateServiceLastAccessedDetailsRequest(*iam.GenerateServiceLastAccessedDetailsInput) (*request.Request, *iam.GenerateServiceLastAccessedDetailsOutput) + + GetAccessKeyLastUsed(*iam.GetAccessKeyLastUsedInput) (*iam.GetAccessKeyLastUsedOutput, error) + GetAccessKeyLastUsedWithContext(aws.Context, *iam.GetAccessKeyLastUsedInput, ...request.Option) (*iam.GetAccessKeyLastUsedOutput, error) + GetAccessKeyLastUsedRequest(*iam.GetAccessKeyLastUsedInput) (*request.Request, *iam.GetAccessKeyLastUsedOutput) + + GetAccountAuthorizationDetails(*iam.GetAccountAuthorizationDetailsInput) (*iam.GetAccountAuthorizationDetailsOutput, error) + GetAccountAuthorizationDetailsWithContext(aws.Context, *iam.GetAccountAuthorizationDetailsInput, ...request.Option) (*iam.GetAccountAuthorizationDetailsOutput, error) + GetAccountAuthorizationDetailsRequest(*iam.GetAccountAuthorizationDetailsInput) (*request.Request, *iam.GetAccountAuthorizationDetailsOutput) + + GetAccountAuthorizationDetailsPages(*iam.GetAccountAuthorizationDetailsInput, func(*iam.GetAccountAuthorizationDetailsOutput, bool) bool) error + GetAccountAuthorizationDetailsPagesWithContext(aws.Context, *iam.GetAccountAuthorizationDetailsInput, func(*iam.GetAccountAuthorizationDetailsOutput, bool) bool, ...request.Option) error + + GetAccountPasswordPolicy(*iam.GetAccountPasswordPolicyInput) (*iam.GetAccountPasswordPolicyOutput, error) + GetAccountPasswordPolicyWithContext(aws.Context, *iam.GetAccountPasswordPolicyInput, ...request.Option) (*iam.GetAccountPasswordPolicyOutput, error) + GetAccountPasswordPolicyRequest(*iam.GetAccountPasswordPolicyInput) (*request.Request, *iam.GetAccountPasswordPolicyOutput) + + GetAccountSummary(*iam.GetAccountSummaryInput) (*iam.GetAccountSummaryOutput, error) + GetAccountSummaryWithContext(aws.Context, *iam.GetAccountSummaryInput, ...request.Option) (*iam.GetAccountSummaryOutput, error) + GetAccountSummaryRequest(*iam.GetAccountSummaryInput) (*request.Request, *iam.GetAccountSummaryOutput) + + GetContextKeysForCustomPolicy(*iam.GetContextKeysForCustomPolicyInput) (*iam.GetContextKeysForPolicyResponse, error) + GetContextKeysForCustomPolicyWithContext(aws.Context, *iam.GetContextKeysForCustomPolicyInput, ...request.Option) (*iam.GetContextKeysForPolicyResponse, error) + GetContextKeysForCustomPolicyRequest(*iam.GetContextKeysForCustomPolicyInput) (*request.Request, *iam.GetContextKeysForPolicyResponse) + + GetContextKeysForPrincipalPolicy(*iam.GetContextKeysForPrincipalPolicyInput) (*iam.GetContextKeysForPolicyResponse, error) + GetContextKeysForPrincipalPolicyWithContext(aws.Context, *iam.GetContextKeysForPrincipalPolicyInput, ...request.Option) (*iam.GetContextKeysForPolicyResponse, error) + GetContextKeysForPrincipalPolicyRequest(*iam.GetContextKeysForPrincipalPolicyInput) (*request.Request, *iam.GetContextKeysForPolicyResponse) + + GetCredentialReport(*iam.GetCredentialReportInput) (*iam.GetCredentialReportOutput, error) + GetCredentialReportWithContext(aws.Context, *iam.GetCredentialReportInput, ...request.Option) (*iam.GetCredentialReportOutput, error) + GetCredentialReportRequest(*iam.GetCredentialReportInput) (*request.Request, *iam.GetCredentialReportOutput) + + GetGroup(*iam.GetGroupInput) (*iam.GetGroupOutput, error) + GetGroupWithContext(aws.Context, *iam.GetGroupInput, ...request.Option) (*iam.GetGroupOutput, error) + GetGroupRequest(*iam.GetGroupInput) (*request.Request, *iam.GetGroupOutput) + + GetGroupPages(*iam.GetGroupInput, func(*iam.GetGroupOutput, bool) bool) error + GetGroupPagesWithContext(aws.Context, *iam.GetGroupInput, func(*iam.GetGroupOutput, bool) bool, ...request.Option) error + + GetGroupPolicy(*iam.GetGroupPolicyInput) (*iam.GetGroupPolicyOutput, error) + GetGroupPolicyWithContext(aws.Context, *iam.GetGroupPolicyInput, ...request.Option) (*iam.GetGroupPolicyOutput, error) + GetGroupPolicyRequest(*iam.GetGroupPolicyInput) (*request.Request, *iam.GetGroupPolicyOutput) + + GetInstanceProfile(*iam.GetInstanceProfileInput) (*iam.GetInstanceProfileOutput, error) + GetInstanceProfileWithContext(aws.Context, *iam.GetInstanceProfileInput, ...request.Option) (*iam.GetInstanceProfileOutput, error) + GetInstanceProfileRequest(*iam.GetInstanceProfileInput) (*request.Request, *iam.GetInstanceProfileOutput) + + GetLoginProfile(*iam.GetLoginProfileInput) (*iam.GetLoginProfileOutput, error) + GetLoginProfileWithContext(aws.Context, *iam.GetLoginProfileInput, ...request.Option) (*iam.GetLoginProfileOutput, error) + GetLoginProfileRequest(*iam.GetLoginProfileInput) (*request.Request, *iam.GetLoginProfileOutput) + + GetOpenIDConnectProvider(*iam.GetOpenIDConnectProviderInput) (*iam.GetOpenIDConnectProviderOutput, error) + GetOpenIDConnectProviderWithContext(aws.Context, *iam.GetOpenIDConnectProviderInput, ...request.Option) (*iam.GetOpenIDConnectProviderOutput, error) + GetOpenIDConnectProviderRequest(*iam.GetOpenIDConnectProviderInput) (*request.Request, *iam.GetOpenIDConnectProviderOutput) + + GetPolicy(*iam.GetPolicyInput) (*iam.GetPolicyOutput, error) + GetPolicyWithContext(aws.Context, *iam.GetPolicyInput, ...request.Option) (*iam.GetPolicyOutput, error) + GetPolicyRequest(*iam.GetPolicyInput) (*request.Request, *iam.GetPolicyOutput) + + GetPolicyVersion(*iam.GetPolicyVersionInput) (*iam.GetPolicyVersionOutput, error) + GetPolicyVersionWithContext(aws.Context, *iam.GetPolicyVersionInput, ...request.Option) (*iam.GetPolicyVersionOutput, error) + GetPolicyVersionRequest(*iam.GetPolicyVersionInput) (*request.Request, *iam.GetPolicyVersionOutput) + + GetRole(*iam.GetRoleInput) (*iam.GetRoleOutput, error) + GetRoleWithContext(aws.Context, *iam.GetRoleInput, ...request.Option) (*iam.GetRoleOutput, error) + GetRoleRequest(*iam.GetRoleInput) (*request.Request, *iam.GetRoleOutput) + + GetRolePolicy(*iam.GetRolePolicyInput) (*iam.GetRolePolicyOutput, error) + GetRolePolicyWithContext(aws.Context, *iam.GetRolePolicyInput, ...request.Option) (*iam.GetRolePolicyOutput, error) + GetRolePolicyRequest(*iam.GetRolePolicyInput) (*request.Request, *iam.GetRolePolicyOutput) + + GetSAMLProvider(*iam.GetSAMLProviderInput) (*iam.GetSAMLProviderOutput, error) + GetSAMLProviderWithContext(aws.Context, *iam.GetSAMLProviderInput, ...request.Option) (*iam.GetSAMLProviderOutput, error) + GetSAMLProviderRequest(*iam.GetSAMLProviderInput) (*request.Request, *iam.GetSAMLProviderOutput) + + GetSSHPublicKey(*iam.GetSSHPublicKeyInput) (*iam.GetSSHPublicKeyOutput, error) + GetSSHPublicKeyWithContext(aws.Context, *iam.GetSSHPublicKeyInput, ...request.Option) (*iam.GetSSHPublicKeyOutput, error) + GetSSHPublicKeyRequest(*iam.GetSSHPublicKeyInput) (*request.Request, *iam.GetSSHPublicKeyOutput) + + GetServerCertificate(*iam.GetServerCertificateInput) (*iam.GetServerCertificateOutput, error) + GetServerCertificateWithContext(aws.Context, *iam.GetServerCertificateInput, ...request.Option) (*iam.GetServerCertificateOutput, error) + GetServerCertificateRequest(*iam.GetServerCertificateInput) (*request.Request, *iam.GetServerCertificateOutput) + + GetServiceLastAccessedDetails(*iam.GetServiceLastAccessedDetailsInput) (*iam.GetServiceLastAccessedDetailsOutput, error) + GetServiceLastAccessedDetailsWithContext(aws.Context, *iam.GetServiceLastAccessedDetailsInput, ...request.Option) (*iam.GetServiceLastAccessedDetailsOutput, error) + GetServiceLastAccessedDetailsRequest(*iam.GetServiceLastAccessedDetailsInput) (*request.Request, *iam.GetServiceLastAccessedDetailsOutput) + + GetServiceLastAccessedDetailsWithEntities(*iam.GetServiceLastAccessedDetailsWithEntitiesInput) (*iam.GetServiceLastAccessedDetailsWithEntitiesOutput, error) + GetServiceLastAccessedDetailsWithEntitiesWithContext(aws.Context, *iam.GetServiceLastAccessedDetailsWithEntitiesInput, ...request.Option) (*iam.GetServiceLastAccessedDetailsWithEntitiesOutput, error) + GetServiceLastAccessedDetailsWithEntitiesRequest(*iam.GetServiceLastAccessedDetailsWithEntitiesInput) (*request.Request, *iam.GetServiceLastAccessedDetailsWithEntitiesOutput) + + GetServiceLinkedRoleDeletionStatus(*iam.GetServiceLinkedRoleDeletionStatusInput) (*iam.GetServiceLinkedRoleDeletionStatusOutput, error) + GetServiceLinkedRoleDeletionStatusWithContext(aws.Context, *iam.GetServiceLinkedRoleDeletionStatusInput, ...request.Option) (*iam.GetServiceLinkedRoleDeletionStatusOutput, error) + GetServiceLinkedRoleDeletionStatusRequest(*iam.GetServiceLinkedRoleDeletionStatusInput) (*request.Request, *iam.GetServiceLinkedRoleDeletionStatusOutput) + + GetUser(*iam.GetUserInput) (*iam.GetUserOutput, error) + GetUserWithContext(aws.Context, *iam.GetUserInput, ...request.Option) (*iam.GetUserOutput, error) + GetUserRequest(*iam.GetUserInput) (*request.Request, *iam.GetUserOutput) + + GetUserPolicy(*iam.GetUserPolicyInput) (*iam.GetUserPolicyOutput, error) + GetUserPolicyWithContext(aws.Context, *iam.GetUserPolicyInput, ...request.Option) (*iam.GetUserPolicyOutput, error) + GetUserPolicyRequest(*iam.GetUserPolicyInput) (*request.Request, *iam.GetUserPolicyOutput) + + ListAccessKeys(*iam.ListAccessKeysInput) (*iam.ListAccessKeysOutput, error) + ListAccessKeysWithContext(aws.Context, *iam.ListAccessKeysInput, ...request.Option) (*iam.ListAccessKeysOutput, error) + ListAccessKeysRequest(*iam.ListAccessKeysInput) (*request.Request, *iam.ListAccessKeysOutput) + + ListAccessKeysPages(*iam.ListAccessKeysInput, func(*iam.ListAccessKeysOutput, bool) bool) error + ListAccessKeysPagesWithContext(aws.Context, *iam.ListAccessKeysInput, func(*iam.ListAccessKeysOutput, bool) bool, ...request.Option) error + + ListAccountAliases(*iam.ListAccountAliasesInput) (*iam.ListAccountAliasesOutput, error) + ListAccountAliasesWithContext(aws.Context, *iam.ListAccountAliasesInput, ...request.Option) (*iam.ListAccountAliasesOutput, error) + ListAccountAliasesRequest(*iam.ListAccountAliasesInput) (*request.Request, *iam.ListAccountAliasesOutput) + + ListAccountAliasesPages(*iam.ListAccountAliasesInput, func(*iam.ListAccountAliasesOutput, bool) bool) error + ListAccountAliasesPagesWithContext(aws.Context, *iam.ListAccountAliasesInput, func(*iam.ListAccountAliasesOutput, bool) bool, ...request.Option) error + + ListAttachedGroupPolicies(*iam.ListAttachedGroupPoliciesInput) (*iam.ListAttachedGroupPoliciesOutput, error) + ListAttachedGroupPoliciesWithContext(aws.Context, *iam.ListAttachedGroupPoliciesInput, ...request.Option) (*iam.ListAttachedGroupPoliciesOutput, error) + ListAttachedGroupPoliciesRequest(*iam.ListAttachedGroupPoliciesInput) (*request.Request, *iam.ListAttachedGroupPoliciesOutput) + + ListAttachedGroupPoliciesPages(*iam.ListAttachedGroupPoliciesInput, func(*iam.ListAttachedGroupPoliciesOutput, bool) bool) error + ListAttachedGroupPoliciesPagesWithContext(aws.Context, *iam.ListAttachedGroupPoliciesInput, func(*iam.ListAttachedGroupPoliciesOutput, bool) bool, ...request.Option) error + + ListAttachedRolePolicies(*iam.ListAttachedRolePoliciesInput) (*iam.ListAttachedRolePoliciesOutput, error) + ListAttachedRolePoliciesWithContext(aws.Context, *iam.ListAttachedRolePoliciesInput, ...request.Option) (*iam.ListAttachedRolePoliciesOutput, error) + ListAttachedRolePoliciesRequest(*iam.ListAttachedRolePoliciesInput) (*request.Request, *iam.ListAttachedRolePoliciesOutput) + + ListAttachedRolePoliciesPages(*iam.ListAttachedRolePoliciesInput, func(*iam.ListAttachedRolePoliciesOutput, bool) bool) error + ListAttachedRolePoliciesPagesWithContext(aws.Context, *iam.ListAttachedRolePoliciesInput, func(*iam.ListAttachedRolePoliciesOutput, bool) bool, ...request.Option) error + + ListAttachedUserPolicies(*iam.ListAttachedUserPoliciesInput) (*iam.ListAttachedUserPoliciesOutput, error) + ListAttachedUserPoliciesWithContext(aws.Context, *iam.ListAttachedUserPoliciesInput, ...request.Option) (*iam.ListAttachedUserPoliciesOutput, error) + ListAttachedUserPoliciesRequest(*iam.ListAttachedUserPoliciesInput) (*request.Request, *iam.ListAttachedUserPoliciesOutput) + + ListAttachedUserPoliciesPages(*iam.ListAttachedUserPoliciesInput, func(*iam.ListAttachedUserPoliciesOutput, bool) bool) error + ListAttachedUserPoliciesPagesWithContext(aws.Context, *iam.ListAttachedUserPoliciesInput, func(*iam.ListAttachedUserPoliciesOutput, bool) bool, ...request.Option) error + + ListEntitiesForPolicy(*iam.ListEntitiesForPolicyInput) (*iam.ListEntitiesForPolicyOutput, error) + ListEntitiesForPolicyWithContext(aws.Context, *iam.ListEntitiesForPolicyInput, ...request.Option) (*iam.ListEntitiesForPolicyOutput, error) + ListEntitiesForPolicyRequest(*iam.ListEntitiesForPolicyInput) (*request.Request, *iam.ListEntitiesForPolicyOutput) + + ListEntitiesForPolicyPages(*iam.ListEntitiesForPolicyInput, func(*iam.ListEntitiesForPolicyOutput, bool) bool) error + ListEntitiesForPolicyPagesWithContext(aws.Context, *iam.ListEntitiesForPolicyInput, func(*iam.ListEntitiesForPolicyOutput, bool) bool, ...request.Option) error + + ListGroupPolicies(*iam.ListGroupPoliciesInput) (*iam.ListGroupPoliciesOutput, error) + ListGroupPoliciesWithContext(aws.Context, *iam.ListGroupPoliciesInput, ...request.Option) (*iam.ListGroupPoliciesOutput, error) + ListGroupPoliciesRequest(*iam.ListGroupPoliciesInput) (*request.Request, *iam.ListGroupPoliciesOutput) + + ListGroupPoliciesPages(*iam.ListGroupPoliciesInput, func(*iam.ListGroupPoliciesOutput, bool) bool) error + ListGroupPoliciesPagesWithContext(aws.Context, *iam.ListGroupPoliciesInput, func(*iam.ListGroupPoliciesOutput, bool) bool, ...request.Option) error + + ListGroups(*iam.ListGroupsInput) (*iam.ListGroupsOutput, error) + ListGroupsWithContext(aws.Context, *iam.ListGroupsInput, ...request.Option) (*iam.ListGroupsOutput, error) + ListGroupsRequest(*iam.ListGroupsInput) (*request.Request, *iam.ListGroupsOutput) + + ListGroupsPages(*iam.ListGroupsInput, func(*iam.ListGroupsOutput, bool) bool) error + ListGroupsPagesWithContext(aws.Context, *iam.ListGroupsInput, func(*iam.ListGroupsOutput, bool) bool, ...request.Option) error + + ListGroupsForUser(*iam.ListGroupsForUserInput) (*iam.ListGroupsForUserOutput, error) + ListGroupsForUserWithContext(aws.Context, *iam.ListGroupsForUserInput, ...request.Option) (*iam.ListGroupsForUserOutput, error) + ListGroupsForUserRequest(*iam.ListGroupsForUserInput) (*request.Request, *iam.ListGroupsForUserOutput) + + ListGroupsForUserPages(*iam.ListGroupsForUserInput, func(*iam.ListGroupsForUserOutput, bool) bool) error + ListGroupsForUserPagesWithContext(aws.Context, *iam.ListGroupsForUserInput, func(*iam.ListGroupsForUserOutput, bool) bool, ...request.Option) error + + ListInstanceProfiles(*iam.ListInstanceProfilesInput) (*iam.ListInstanceProfilesOutput, error) + ListInstanceProfilesWithContext(aws.Context, *iam.ListInstanceProfilesInput, ...request.Option) (*iam.ListInstanceProfilesOutput, error) + ListInstanceProfilesRequest(*iam.ListInstanceProfilesInput) (*request.Request, *iam.ListInstanceProfilesOutput) + + ListInstanceProfilesPages(*iam.ListInstanceProfilesInput, func(*iam.ListInstanceProfilesOutput, bool) bool) error + ListInstanceProfilesPagesWithContext(aws.Context, *iam.ListInstanceProfilesInput, func(*iam.ListInstanceProfilesOutput, bool) bool, ...request.Option) error + + ListInstanceProfilesForRole(*iam.ListInstanceProfilesForRoleInput) (*iam.ListInstanceProfilesForRoleOutput, error) + ListInstanceProfilesForRoleWithContext(aws.Context, *iam.ListInstanceProfilesForRoleInput, ...request.Option) (*iam.ListInstanceProfilesForRoleOutput, error) + ListInstanceProfilesForRoleRequest(*iam.ListInstanceProfilesForRoleInput) (*request.Request, *iam.ListInstanceProfilesForRoleOutput) + + ListInstanceProfilesForRolePages(*iam.ListInstanceProfilesForRoleInput, func(*iam.ListInstanceProfilesForRoleOutput, bool) bool) error + ListInstanceProfilesForRolePagesWithContext(aws.Context, *iam.ListInstanceProfilesForRoleInput, func(*iam.ListInstanceProfilesForRoleOutput, bool) bool, ...request.Option) error + + ListMFADevices(*iam.ListMFADevicesInput) (*iam.ListMFADevicesOutput, error) + ListMFADevicesWithContext(aws.Context, *iam.ListMFADevicesInput, ...request.Option) (*iam.ListMFADevicesOutput, error) + ListMFADevicesRequest(*iam.ListMFADevicesInput) (*request.Request, *iam.ListMFADevicesOutput) + + ListMFADevicesPages(*iam.ListMFADevicesInput, func(*iam.ListMFADevicesOutput, bool) bool) error + ListMFADevicesPagesWithContext(aws.Context, *iam.ListMFADevicesInput, func(*iam.ListMFADevicesOutput, bool) bool, ...request.Option) error + + ListOpenIDConnectProviders(*iam.ListOpenIDConnectProvidersInput) (*iam.ListOpenIDConnectProvidersOutput, error) + ListOpenIDConnectProvidersWithContext(aws.Context, *iam.ListOpenIDConnectProvidersInput, ...request.Option) (*iam.ListOpenIDConnectProvidersOutput, error) + ListOpenIDConnectProvidersRequest(*iam.ListOpenIDConnectProvidersInput) (*request.Request, *iam.ListOpenIDConnectProvidersOutput) + + ListPolicies(*iam.ListPoliciesInput) (*iam.ListPoliciesOutput, error) + ListPoliciesWithContext(aws.Context, *iam.ListPoliciesInput, ...request.Option) (*iam.ListPoliciesOutput, error) + ListPoliciesRequest(*iam.ListPoliciesInput) (*request.Request, *iam.ListPoliciesOutput) + + ListPoliciesPages(*iam.ListPoliciesInput, func(*iam.ListPoliciesOutput, bool) bool) error + ListPoliciesPagesWithContext(aws.Context, *iam.ListPoliciesInput, func(*iam.ListPoliciesOutput, bool) bool, ...request.Option) error + + ListPoliciesGrantingServiceAccess(*iam.ListPoliciesGrantingServiceAccessInput) (*iam.ListPoliciesGrantingServiceAccessOutput, error) + ListPoliciesGrantingServiceAccessWithContext(aws.Context, *iam.ListPoliciesGrantingServiceAccessInput, ...request.Option) (*iam.ListPoliciesGrantingServiceAccessOutput, error) + ListPoliciesGrantingServiceAccessRequest(*iam.ListPoliciesGrantingServiceAccessInput) (*request.Request, *iam.ListPoliciesGrantingServiceAccessOutput) + + ListPolicyVersions(*iam.ListPolicyVersionsInput) (*iam.ListPolicyVersionsOutput, error) + ListPolicyVersionsWithContext(aws.Context, *iam.ListPolicyVersionsInput, ...request.Option) (*iam.ListPolicyVersionsOutput, error) + ListPolicyVersionsRequest(*iam.ListPolicyVersionsInput) (*request.Request, *iam.ListPolicyVersionsOutput) + + ListPolicyVersionsPages(*iam.ListPolicyVersionsInput, func(*iam.ListPolicyVersionsOutput, bool) bool) error + ListPolicyVersionsPagesWithContext(aws.Context, *iam.ListPolicyVersionsInput, func(*iam.ListPolicyVersionsOutput, bool) bool, ...request.Option) error + + ListRolePolicies(*iam.ListRolePoliciesInput) (*iam.ListRolePoliciesOutput, error) + ListRolePoliciesWithContext(aws.Context, *iam.ListRolePoliciesInput, ...request.Option) (*iam.ListRolePoliciesOutput, error) + ListRolePoliciesRequest(*iam.ListRolePoliciesInput) (*request.Request, *iam.ListRolePoliciesOutput) + + ListRolePoliciesPages(*iam.ListRolePoliciesInput, func(*iam.ListRolePoliciesOutput, bool) bool) error + ListRolePoliciesPagesWithContext(aws.Context, *iam.ListRolePoliciesInput, func(*iam.ListRolePoliciesOutput, bool) bool, ...request.Option) error + + ListRoleTags(*iam.ListRoleTagsInput) (*iam.ListRoleTagsOutput, error) + ListRoleTagsWithContext(aws.Context, *iam.ListRoleTagsInput, ...request.Option) (*iam.ListRoleTagsOutput, error) + ListRoleTagsRequest(*iam.ListRoleTagsInput) (*request.Request, *iam.ListRoleTagsOutput) + + ListRoles(*iam.ListRolesInput) (*iam.ListRolesOutput, error) + ListRolesWithContext(aws.Context, *iam.ListRolesInput, ...request.Option) (*iam.ListRolesOutput, error) + ListRolesRequest(*iam.ListRolesInput) (*request.Request, *iam.ListRolesOutput) + + ListRolesPages(*iam.ListRolesInput, func(*iam.ListRolesOutput, bool) bool) error + ListRolesPagesWithContext(aws.Context, *iam.ListRolesInput, func(*iam.ListRolesOutput, bool) bool, ...request.Option) error + + ListSAMLProviders(*iam.ListSAMLProvidersInput) (*iam.ListSAMLProvidersOutput, error) + ListSAMLProvidersWithContext(aws.Context, *iam.ListSAMLProvidersInput, ...request.Option) (*iam.ListSAMLProvidersOutput, error) + ListSAMLProvidersRequest(*iam.ListSAMLProvidersInput) (*request.Request, *iam.ListSAMLProvidersOutput) + + ListSSHPublicKeys(*iam.ListSSHPublicKeysInput) (*iam.ListSSHPublicKeysOutput, error) + ListSSHPublicKeysWithContext(aws.Context, *iam.ListSSHPublicKeysInput, ...request.Option) (*iam.ListSSHPublicKeysOutput, error) + ListSSHPublicKeysRequest(*iam.ListSSHPublicKeysInput) (*request.Request, *iam.ListSSHPublicKeysOutput) + + ListSSHPublicKeysPages(*iam.ListSSHPublicKeysInput, func(*iam.ListSSHPublicKeysOutput, bool) bool) error + ListSSHPublicKeysPagesWithContext(aws.Context, *iam.ListSSHPublicKeysInput, func(*iam.ListSSHPublicKeysOutput, bool) bool, ...request.Option) error + + ListServerCertificates(*iam.ListServerCertificatesInput) (*iam.ListServerCertificatesOutput, error) + ListServerCertificatesWithContext(aws.Context, *iam.ListServerCertificatesInput, ...request.Option) (*iam.ListServerCertificatesOutput, error) + ListServerCertificatesRequest(*iam.ListServerCertificatesInput) (*request.Request, *iam.ListServerCertificatesOutput) + + ListServerCertificatesPages(*iam.ListServerCertificatesInput, func(*iam.ListServerCertificatesOutput, bool) bool) error + ListServerCertificatesPagesWithContext(aws.Context, *iam.ListServerCertificatesInput, func(*iam.ListServerCertificatesOutput, bool) bool, ...request.Option) error + + ListServiceSpecificCredentials(*iam.ListServiceSpecificCredentialsInput) (*iam.ListServiceSpecificCredentialsOutput, error) + ListServiceSpecificCredentialsWithContext(aws.Context, *iam.ListServiceSpecificCredentialsInput, ...request.Option) (*iam.ListServiceSpecificCredentialsOutput, error) + ListServiceSpecificCredentialsRequest(*iam.ListServiceSpecificCredentialsInput) (*request.Request, *iam.ListServiceSpecificCredentialsOutput) + + ListSigningCertificates(*iam.ListSigningCertificatesInput) (*iam.ListSigningCertificatesOutput, error) + ListSigningCertificatesWithContext(aws.Context, *iam.ListSigningCertificatesInput, ...request.Option) (*iam.ListSigningCertificatesOutput, error) + ListSigningCertificatesRequest(*iam.ListSigningCertificatesInput) (*request.Request, *iam.ListSigningCertificatesOutput) + + ListSigningCertificatesPages(*iam.ListSigningCertificatesInput, func(*iam.ListSigningCertificatesOutput, bool) bool) error + ListSigningCertificatesPagesWithContext(aws.Context, *iam.ListSigningCertificatesInput, func(*iam.ListSigningCertificatesOutput, bool) bool, ...request.Option) error + + ListUserPolicies(*iam.ListUserPoliciesInput) (*iam.ListUserPoliciesOutput, error) + ListUserPoliciesWithContext(aws.Context, *iam.ListUserPoliciesInput, ...request.Option) (*iam.ListUserPoliciesOutput, error) + ListUserPoliciesRequest(*iam.ListUserPoliciesInput) (*request.Request, *iam.ListUserPoliciesOutput) + + ListUserPoliciesPages(*iam.ListUserPoliciesInput, func(*iam.ListUserPoliciesOutput, bool) bool) error + ListUserPoliciesPagesWithContext(aws.Context, *iam.ListUserPoliciesInput, func(*iam.ListUserPoliciesOutput, bool) bool, ...request.Option) error + + ListUserTags(*iam.ListUserTagsInput) (*iam.ListUserTagsOutput, error) + ListUserTagsWithContext(aws.Context, *iam.ListUserTagsInput, ...request.Option) (*iam.ListUserTagsOutput, error) + ListUserTagsRequest(*iam.ListUserTagsInput) (*request.Request, *iam.ListUserTagsOutput) + + ListUsers(*iam.ListUsersInput) (*iam.ListUsersOutput, error) + ListUsersWithContext(aws.Context, *iam.ListUsersInput, ...request.Option) (*iam.ListUsersOutput, error) + ListUsersRequest(*iam.ListUsersInput) (*request.Request, *iam.ListUsersOutput) + + ListUsersPages(*iam.ListUsersInput, func(*iam.ListUsersOutput, bool) bool) error + ListUsersPagesWithContext(aws.Context, *iam.ListUsersInput, func(*iam.ListUsersOutput, bool) bool, ...request.Option) error + + ListVirtualMFADevices(*iam.ListVirtualMFADevicesInput) (*iam.ListVirtualMFADevicesOutput, error) + ListVirtualMFADevicesWithContext(aws.Context, *iam.ListVirtualMFADevicesInput, ...request.Option) (*iam.ListVirtualMFADevicesOutput, error) + ListVirtualMFADevicesRequest(*iam.ListVirtualMFADevicesInput) (*request.Request, *iam.ListVirtualMFADevicesOutput) + + ListVirtualMFADevicesPages(*iam.ListVirtualMFADevicesInput, func(*iam.ListVirtualMFADevicesOutput, bool) bool) error + ListVirtualMFADevicesPagesWithContext(aws.Context, *iam.ListVirtualMFADevicesInput, func(*iam.ListVirtualMFADevicesOutput, bool) bool, ...request.Option) error + + PutGroupPolicy(*iam.PutGroupPolicyInput) (*iam.PutGroupPolicyOutput, error) + PutGroupPolicyWithContext(aws.Context, *iam.PutGroupPolicyInput, ...request.Option) (*iam.PutGroupPolicyOutput, error) + PutGroupPolicyRequest(*iam.PutGroupPolicyInput) (*request.Request, *iam.PutGroupPolicyOutput) + + PutRolePermissionsBoundary(*iam.PutRolePermissionsBoundaryInput) (*iam.PutRolePermissionsBoundaryOutput, error) + PutRolePermissionsBoundaryWithContext(aws.Context, *iam.PutRolePermissionsBoundaryInput, ...request.Option) (*iam.PutRolePermissionsBoundaryOutput, error) + PutRolePermissionsBoundaryRequest(*iam.PutRolePermissionsBoundaryInput) (*request.Request, *iam.PutRolePermissionsBoundaryOutput) + + PutRolePolicy(*iam.PutRolePolicyInput) (*iam.PutRolePolicyOutput, error) + PutRolePolicyWithContext(aws.Context, *iam.PutRolePolicyInput, ...request.Option) (*iam.PutRolePolicyOutput, error) + PutRolePolicyRequest(*iam.PutRolePolicyInput) (*request.Request, *iam.PutRolePolicyOutput) + + PutUserPermissionsBoundary(*iam.PutUserPermissionsBoundaryInput) (*iam.PutUserPermissionsBoundaryOutput, error) + PutUserPermissionsBoundaryWithContext(aws.Context, *iam.PutUserPermissionsBoundaryInput, ...request.Option) (*iam.PutUserPermissionsBoundaryOutput, error) + PutUserPermissionsBoundaryRequest(*iam.PutUserPermissionsBoundaryInput) (*request.Request, *iam.PutUserPermissionsBoundaryOutput) + + PutUserPolicy(*iam.PutUserPolicyInput) (*iam.PutUserPolicyOutput, error) + PutUserPolicyWithContext(aws.Context, *iam.PutUserPolicyInput, ...request.Option) (*iam.PutUserPolicyOutput, error) + PutUserPolicyRequest(*iam.PutUserPolicyInput) (*request.Request, *iam.PutUserPolicyOutput) + + RemoveClientIDFromOpenIDConnectProvider(*iam.RemoveClientIDFromOpenIDConnectProviderInput) (*iam.RemoveClientIDFromOpenIDConnectProviderOutput, error) + RemoveClientIDFromOpenIDConnectProviderWithContext(aws.Context, *iam.RemoveClientIDFromOpenIDConnectProviderInput, ...request.Option) (*iam.RemoveClientIDFromOpenIDConnectProviderOutput, error) + RemoveClientIDFromOpenIDConnectProviderRequest(*iam.RemoveClientIDFromOpenIDConnectProviderInput) (*request.Request, *iam.RemoveClientIDFromOpenIDConnectProviderOutput) + + RemoveRoleFromInstanceProfile(*iam.RemoveRoleFromInstanceProfileInput) (*iam.RemoveRoleFromInstanceProfileOutput, error) + RemoveRoleFromInstanceProfileWithContext(aws.Context, *iam.RemoveRoleFromInstanceProfileInput, ...request.Option) (*iam.RemoveRoleFromInstanceProfileOutput, error) + RemoveRoleFromInstanceProfileRequest(*iam.RemoveRoleFromInstanceProfileInput) (*request.Request, *iam.RemoveRoleFromInstanceProfileOutput) + + RemoveUserFromGroup(*iam.RemoveUserFromGroupInput) (*iam.RemoveUserFromGroupOutput, error) + RemoveUserFromGroupWithContext(aws.Context, *iam.RemoveUserFromGroupInput, ...request.Option) (*iam.RemoveUserFromGroupOutput, error) + RemoveUserFromGroupRequest(*iam.RemoveUserFromGroupInput) (*request.Request, *iam.RemoveUserFromGroupOutput) + + ResetServiceSpecificCredential(*iam.ResetServiceSpecificCredentialInput) (*iam.ResetServiceSpecificCredentialOutput, error) + ResetServiceSpecificCredentialWithContext(aws.Context, *iam.ResetServiceSpecificCredentialInput, ...request.Option) (*iam.ResetServiceSpecificCredentialOutput, error) + ResetServiceSpecificCredentialRequest(*iam.ResetServiceSpecificCredentialInput) (*request.Request, *iam.ResetServiceSpecificCredentialOutput) + + ResyncMFADevice(*iam.ResyncMFADeviceInput) (*iam.ResyncMFADeviceOutput, error) + ResyncMFADeviceWithContext(aws.Context, *iam.ResyncMFADeviceInput, ...request.Option) (*iam.ResyncMFADeviceOutput, error) + ResyncMFADeviceRequest(*iam.ResyncMFADeviceInput) (*request.Request, *iam.ResyncMFADeviceOutput) + + SetDefaultPolicyVersion(*iam.SetDefaultPolicyVersionInput) (*iam.SetDefaultPolicyVersionOutput, error) + SetDefaultPolicyVersionWithContext(aws.Context, *iam.SetDefaultPolicyVersionInput, ...request.Option) (*iam.SetDefaultPolicyVersionOutput, error) + SetDefaultPolicyVersionRequest(*iam.SetDefaultPolicyVersionInput) (*request.Request, *iam.SetDefaultPolicyVersionOutput) + + SimulateCustomPolicy(*iam.SimulateCustomPolicyInput) (*iam.SimulatePolicyResponse, error) + SimulateCustomPolicyWithContext(aws.Context, *iam.SimulateCustomPolicyInput, ...request.Option) (*iam.SimulatePolicyResponse, error) + SimulateCustomPolicyRequest(*iam.SimulateCustomPolicyInput) (*request.Request, *iam.SimulatePolicyResponse) + + SimulateCustomPolicyPages(*iam.SimulateCustomPolicyInput, func(*iam.SimulatePolicyResponse, bool) bool) error + SimulateCustomPolicyPagesWithContext(aws.Context, *iam.SimulateCustomPolicyInput, func(*iam.SimulatePolicyResponse, bool) bool, ...request.Option) error + + SimulatePrincipalPolicy(*iam.SimulatePrincipalPolicyInput) (*iam.SimulatePolicyResponse, error) + SimulatePrincipalPolicyWithContext(aws.Context, *iam.SimulatePrincipalPolicyInput, ...request.Option) (*iam.SimulatePolicyResponse, error) + SimulatePrincipalPolicyRequest(*iam.SimulatePrincipalPolicyInput) (*request.Request, *iam.SimulatePolicyResponse) + + SimulatePrincipalPolicyPages(*iam.SimulatePrincipalPolicyInput, func(*iam.SimulatePolicyResponse, bool) bool) error + SimulatePrincipalPolicyPagesWithContext(aws.Context, *iam.SimulatePrincipalPolicyInput, func(*iam.SimulatePolicyResponse, bool) bool, ...request.Option) error + + TagRole(*iam.TagRoleInput) (*iam.TagRoleOutput, error) + TagRoleWithContext(aws.Context, *iam.TagRoleInput, ...request.Option) (*iam.TagRoleOutput, error) + TagRoleRequest(*iam.TagRoleInput) (*request.Request, *iam.TagRoleOutput) + + TagUser(*iam.TagUserInput) (*iam.TagUserOutput, error) + TagUserWithContext(aws.Context, *iam.TagUserInput, ...request.Option) (*iam.TagUserOutput, error) + TagUserRequest(*iam.TagUserInput) (*request.Request, *iam.TagUserOutput) + + UntagRole(*iam.UntagRoleInput) (*iam.UntagRoleOutput, error) + UntagRoleWithContext(aws.Context, *iam.UntagRoleInput, ...request.Option) (*iam.UntagRoleOutput, error) + UntagRoleRequest(*iam.UntagRoleInput) (*request.Request, *iam.UntagRoleOutput) + + UntagUser(*iam.UntagUserInput) (*iam.UntagUserOutput, error) + UntagUserWithContext(aws.Context, *iam.UntagUserInput, ...request.Option) (*iam.UntagUserOutput, error) + UntagUserRequest(*iam.UntagUserInput) (*request.Request, *iam.UntagUserOutput) + + UpdateAccessKey(*iam.UpdateAccessKeyInput) (*iam.UpdateAccessKeyOutput, error) + UpdateAccessKeyWithContext(aws.Context, *iam.UpdateAccessKeyInput, ...request.Option) (*iam.UpdateAccessKeyOutput, error) + UpdateAccessKeyRequest(*iam.UpdateAccessKeyInput) (*request.Request, *iam.UpdateAccessKeyOutput) + + UpdateAccountPasswordPolicy(*iam.UpdateAccountPasswordPolicyInput) (*iam.UpdateAccountPasswordPolicyOutput, error) + UpdateAccountPasswordPolicyWithContext(aws.Context, *iam.UpdateAccountPasswordPolicyInput, ...request.Option) (*iam.UpdateAccountPasswordPolicyOutput, error) + UpdateAccountPasswordPolicyRequest(*iam.UpdateAccountPasswordPolicyInput) (*request.Request, *iam.UpdateAccountPasswordPolicyOutput) + + UpdateAssumeRolePolicy(*iam.UpdateAssumeRolePolicyInput) (*iam.UpdateAssumeRolePolicyOutput, error) + UpdateAssumeRolePolicyWithContext(aws.Context, *iam.UpdateAssumeRolePolicyInput, ...request.Option) (*iam.UpdateAssumeRolePolicyOutput, error) + UpdateAssumeRolePolicyRequest(*iam.UpdateAssumeRolePolicyInput) (*request.Request, *iam.UpdateAssumeRolePolicyOutput) + + UpdateGroup(*iam.UpdateGroupInput) (*iam.UpdateGroupOutput, error) + UpdateGroupWithContext(aws.Context, *iam.UpdateGroupInput, ...request.Option) (*iam.UpdateGroupOutput, error) + UpdateGroupRequest(*iam.UpdateGroupInput) (*request.Request, *iam.UpdateGroupOutput) + + UpdateLoginProfile(*iam.UpdateLoginProfileInput) (*iam.UpdateLoginProfileOutput, error) + UpdateLoginProfileWithContext(aws.Context, *iam.UpdateLoginProfileInput, ...request.Option) (*iam.UpdateLoginProfileOutput, error) + UpdateLoginProfileRequest(*iam.UpdateLoginProfileInput) (*request.Request, *iam.UpdateLoginProfileOutput) + + UpdateOpenIDConnectProviderThumbprint(*iam.UpdateOpenIDConnectProviderThumbprintInput) (*iam.UpdateOpenIDConnectProviderThumbprintOutput, error) + UpdateOpenIDConnectProviderThumbprintWithContext(aws.Context, *iam.UpdateOpenIDConnectProviderThumbprintInput, ...request.Option) (*iam.UpdateOpenIDConnectProviderThumbprintOutput, error) + UpdateOpenIDConnectProviderThumbprintRequest(*iam.UpdateOpenIDConnectProviderThumbprintInput) (*request.Request, *iam.UpdateOpenIDConnectProviderThumbprintOutput) + + UpdateRole(*iam.UpdateRoleInput) (*iam.UpdateRoleOutput, error) + UpdateRoleWithContext(aws.Context, *iam.UpdateRoleInput, ...request.Option) (*iam.UpdateRoleOutput, error) + UpdateRoleRequest(*iam.UpdateRoleInput) (*request.Request, *iam.UpdateRoleOutput) + + UpdateRoleDescription(*iam.UpdateRoleDescriptionInput) (*iam.UpdateRoleDescriptionOutput, error) + UpdateRoleDescriptionWithContext(aws.Context, *iam.UpdateRoleDescriptionInput, ...request.Option) (*iam.UpdateRoleDescriptionOutput, error) + UpdateRoleDescriptionRequest(*iam.UpdateRoleDescriptionInput) (*request.Request, *iam.UpdateRoleDescriptionOutput) + + UpdateSAMLProvider(*iam.UpdateSAMLProviderInput) (*iam.UpdateSAMLProviderOutput, error) + UpdateSAMLProviderWithContext(aws.Context, *iam.UpdateSAMLProviderInput, ...request.Option) (*iam.UpdateSAMLProviderOutput, error) + UpdateSAMLProviderRequest(*iam.UpdateSAMLProviderInput) (*request.Request, *iam.UpdateSAMLProviderOutput) + + UpdateSSHPublicKey(*iam.UpdateSSHPublicKeyInput) (*iam.UpdateSSHPublicKeyOutput, error) + UpdateSSHPublicKeyWithContext(aws.Context, *iam.UpdateSSHPublicKeyInput, ...request.Option) (*iam.UpdateSSHPublicKeyOutput, error) + UpdateSSHPublicKeyRequest(*iam.UpdateSSHPublicKeyInput) (*request.Request, *iam.UpdateSSHPublicKeyOutput) + + UpdateServerCertificate(*iam.UpdateServerCertificateInput) (*iam.UpdateServerCertificateOutput, error) + UpdateServerCertificateWithContext(aws.Context, *iam.UpdateServerCertificateInput, ...request.Option) (*iam.UpdateServerCertificateOutput, error) + UpdateServerCertificateRequest(*iam.UpdateServerCertificateInput) (*request.Request, *iam.UpdateServerCertificateOutput) + + UpdateServiceSpecificCredential(*iam.UpdateServiceSpecificCredentialInput) (*iam.UpdateServiceSpecificCredentialOutput, error) + UpdateServiceSpecificCredentialWithContext(aws.Context, *iam.UpdateServiceSpecificCredentialInput, ...request.Option) (*iam.UpdateServiceSpecificCredentialOutput, error) + UpdateServiceSpecificCredentialRequest(*iam.UpdateServiceSpecificCredentialInput) (*request.Request, *iam.UpdateServiceSpecificCredentialOutput) + + UpdateSigningCertificate(*iam.UpdateSigningCertificateInput) (*iam.UpdateSigningCertificateOutput, error) + UpdateSigningCertificateWithContext(aws.Context, *iam.UpdateSigningCertificateInput, ...request.Option) (*iam.UpdateSigningCertificateOutput, error) + UpdateSigningCertificateRequest(*iam.UpdateSigningCertificateInput) (*request.Request, *iam.UpdateSigningCertificateOutput) + + UpdateUser(*iam.UpdateUserInput) (*iam.UpdateUserOutput, error) + UpdateUserWithContext(aws.Context, *iam.UpdateUserInput, ...request.Option) (*iam.UpdateUserOutput, error) + UpdateUserRequest(*iam.UpdateUserInput) (*request.Request, *iam.UpdateUserOutput) + + UploadSSHPublicKey(*iam.UploadSSHPublicKeyInput) (*iam.UploadSSHPublicKeyOutput, error) + UploadSSHPublicKeyWithContext(aws.Context, *iam.UploadSSHPublicKeyInput, ...request.Option) (*iam.UploadSSHPublicKeyOutput, error) + UploadSSHPublicKeyRequest(*iam.UploadSSHPublicKeyInput) (*request.Request, *iam.UploadSSHPublicKeyOutput) + + UploadServerCertificate(*iam.UploadServerCertificateInput) (*iam.UploadServerCertificateOutput, error) + UploadServerCertificateWithContext(aws.Context, *iam.UploadServerCertificateInput, ...request.Option) (*iam.UploadServerCertificateOutput, error) + UploadServerCertificateRequest(*iam.UploadServerCertificateInput) (*request.Request, *iam.UploadServerCertificateOutput) + + UploadSigningCertificate(*iam.UploadSigningCertificateInput) (*iam.UploadSigningCertificateOutput, error) + UploadSigningCertificateWithContext(aws.Context, *iam.UploadSigningCertificateInput, ...request.Option) (*iam.UploadSigningCertificateOutput, error) + UploadSigningCertificateRequest(*iam.UploadSigningCertificateInput) (*request.Request, *iam.UploadSigningCertificateOutput) + + WaitUntilInstanceProfileExists(*iam.GetInstanceProfileInput) error + WaitUntilInstanceProfileExistsWithContext(aws.Context, *iam.GetInstanceProfileInput, ...request.WaiterOption) error + + WaitUntilUserExists(*iam.GetUserInput) error + WaitUntilUserExistsWithContext(aws.Context, *iam.GetUserInput, ...request.WaiterOption) error +} + +var _ IAMAPI = (*iam.IAM)(nil) diff --git a/vendor/github.com/openshift/cloud-credential-operator/LICENSE b/vendor/github.com/openshift/cloud-credential-operator/LICENSE new file mode 100644 index 00000000000..261eeb9e9f8 --- /dev/null +++ b/vendor/github.com/openshift/cloud-credential-operator/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. diff --git a/vendor/github.com/openshift/cloud-credential-operator/pkg/apis/cloudcredential/v1beta1/aws_types.go b/vendor/github.com/openshift/cloud-credential-operator/pkg/apis/cloudcredential/v1beta1/aws_types.go new file mode 100644 index 00000000000..76b2ad1e4ef --- /dev/null +++ b/vendor/github.com/openshift/cloud-credential-operator/pkg/apis/cloudcredential/v1beta1/aws_types.go @@ -0,0 +1,51 @@ +/* +Copyright 2018 The OpenShift Authors. + +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 v1beta1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// TODO: these types should eventually be broken out, along with the actuator, to a separate repo. + +// AWSProviderSpec contains the required information to create a user policy in AWS. +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object +type AWSProviderSpec struct { + metav1.TypeMeta `json:",inline"` + // StatementEntries contains a list of policy statements that should be associated with this credentials access key. + StatementEntries []StatementEntry `json:"statementEntries"` +} + +// StatementEntry models an AWS policy statement entry. +type StatementEntry struct { + // Effect indicates if this policy statement is to Allow or Deny. + Effect string `json:"effect"` + // Action describes the particular AWS service actions that should be allowed or denied. (i.e. ec2:StartInstances, iam:ChangePassword) + Action []string `json:"action"` + // Resource specifies the object(s) this statement should apply to. (or "*" for all) + Resource string `json:"resource"` +} + +// AWSStatus containes the status of the credentials request in AWS. +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object +type AWSProviderStatus struct { + metav1.TypeMeta `json:",inline"` + // User is the name of the User created in AWS for these credentials. + User string `json:"user"` + // Policy is the name of the policy attached to the user in AWS. + Policy string `json:"policy"` +} diff --git a/vendor/github.com/openshift/cloud-credential-operator/pkg/apis/cloudcredential/v1beta1/codec.go b/vendor/github.com/openshift/cloud-credential-operator/pkg/apis/cloudcredential/v1beta1/codec.go new file mode 100644 index 00000000000..819e9a636dc --- /dev/null +++ b/vendor/github.com/openshift/cloud-credential-operator/pkg/apis/cloudcredential/v1beta1/codec.go @@ -0,0 +1,111 @@ +/* +Copyright 2018 The OpenShift Authors. + +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 v1beta1 + +import ( + "bytes" + "fmt" + + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/serializer" +) + +// NewScheme creates a new Scheme +func NewScheme() (*runtime.Scheme, error) { + return SchemeBuilder.Build() +} + +// AWSProviderCodec is a runtime codec for the AWS provider. +// +k8s:deepcopy-gen=false +type AWSProviderCodec struct { + encoder runtime.Encoder + decoder runtime.Decoder +} + +// NewCodec creates a serializer/deserializer for the provider configuration +func NewCodec() (*AWSProviderCodec, error) { + scheme, err := NewScheme() + if err != nil { + return nil, err + } + codecFactory := serializer.NewCodecFactory(scheme) + encoder, err := newEncoder(&codecFactory) + if err != nil { + return nil, err + } + codec := AWSProviderCodec{ + encoder: encoder, + decoder: codecFactory.UniversalDecoder(SchemeGroupVersion), + } + return &codec, nil +} + +// EncodeProvider serializes an object to the provider spec. +func (codec *AWSProviderCodec) EncodeProviderSpec(in runtime.Object) (*runtime.RawExtension, error) { + var buf bytes.Buffer + if err := codec.encoder.Encode(in, &buf); err != nil { + return nil, fmt.Errorf("encoding failed: %v", err) + } + return &runtime.RawExtension{Raw: buf.Bytes()}, nil +} + +// DecodeProviderSpec deserializes an object from the provider config. +func (codec *AWSProviderCodec) DecodeProviderSpec(providerConfig *runtime.RawExtension, out runtime.Object) (*AWSProviderSpec, error) { + obj, _, err := codec.decoder.Decode(providerConfig.Raw, nil, out) + if err != nil { + return nil, fmt.Errorf("decoding failure: %v", err) + } + s, ok := obj.(*AWSProviderSpec) + if !ok { + return nil, fmt.Errorf("error casting to AWSProviderSpec") + } + return s, nil +} + +// EncodeProviderStatus serializes the provider status. +func (codec *AWSProviderCodec) EncodeProviderStatus(in runtime.Object) (*runtime.RawExtension, error) { + var buf bytes.Buffer + if err := codec.encoder.Encode(in, &buf); err != nil { + return nil, fmt.Errorf("encoding failed: %v", err) + } + return &runtime.RawExtension{Raw: buf.Bytes()}, nil +} + +// DecodeProviderStatus deserializes the provider status. +func (codec *AWSProviderCodec) DecodeProviderStatus(providerStatus *runtime.RawExtension, out runtime.Object) (*AWSProviderStatus, error) { + if providerStatus != nil { + obj, _, err := codec.decoder.Decode(providerStatus.Raw, nil, out) + if err != nil { + return nil, fmt.Errorf("decoding failure: %v", err) + } + s, ok := obj.(*AWSProviderStatus) + if !ok { + return nil, fmt.Errorf("error casting to AWSProviderStatus") + } + return s, nil + } + return &AWSProviderStatus{}, nil +} + +func newEncoder(codecFactory *serializer.CodecFactory) (runtime.Encoder, error) { + serializerInfos := codecFactory.SupportedMediaTypes() + if len(serializerInfos) == 0 { + return nil, fmt.Errorf("unable to find any serlializers") + } + encoder := codecFactory.EncoderForVersion(serializerInfos[0].Serializer, SchemeGroupVersion) + return encoder, nil +} diff --git a/vendor/github.com/openshift/cloud-credential-operator/pkg/apis/cloudcredential/v1beta1/credentialsrequest_types.go b/vendor/github.com/openshift/cloud-credential-operator/pkg/apis/cloudcredential/v1beta1/credentialsrequest_types.go new file mode 100644 index 00000000000..2149467a596 --- /dev/null +++ b/vendor/github.com/openshift/cloud-credential-operator/pkg/apis/cloudcredential/v1beta1/credentialsrequest_types.go @@ -0,0 +1,134 @@ +/* +Copyright 2018 The OpenShift Authors. + +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 v1beta1 + +import ( + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" +) + +const ( + // FinalizerDeprovision is used on CredentialsRequests to ensure we delete the + // credentials in AWS before allowing the CredentialsRequest to be deleted in etcd. + FinalizerDeprovision string = "cloudcredential.openshift.io/deprovision" + + // AnnotationCredentialsRequest is used on Secrets created as a target of CredentailsRequests. + // The annotation value will map back to the namespace/name of the CredentialsRequest that created + // or adopted the secret. + AnnotationCredentialsRequest string = "cloudcredential.openshift.io/credentials-request" + + // AnnotationAWSPolicyLastApplied is added to target Secrets indicating the last AWS policy + // we successfully applied. It is used to compare if changes are necessary, without requiring + // AWS credentials to view the actual state. + AnnotationAWSPolicyLastApplied string = "cloudcredential.openshift.io/aws-policy-last-applied" +) + +// NOTE: Run "make" to regenerate code after modifying this file + +// CredentialsRequestSpec defines the desired state of CredentialsRequest +type CredentialsRequestSpec struct { + // SecretRef points to the secret where the credentials should be stored once generated. + SecretRef corev1.ObjectReference `json:"secretRef"` + + // ProviderSpec contains the cloud provider specific credentials specification. + ProviderSpec *runtime.RawExtension `json:"providerSpec,omitempty"` +} + +// CredentialsRequestStatus defines the observed state of CredentialsRequest +type CredentialsRequestStatus struct { + // Provisioned is true once the credentials have been initially provisioned. + Provisioned bool `json:"provisioned"` + + // LastSyncTimestamp is the time that the credentials were last synced. + LastSyncTimestamp *metav1.Time `json:"lastSyncTimestamp,omitempty"` + + // LastSyncGeneration is the generation of the credentials request resource + // that was last synced. Used to determine if the object has changed and + // requires a sync. + LastSyncGeneration int64 `json:"lastSyncGeneration"` + + // ProviderStatus contains cloud provider specific status. + ProviderStatus *runtime.RawExtension `json:"providerStatus,omitempty"` + + // Conditions includes detailed status for the CredentialsRequest + Conditions []CredentialsRequestCondition `json:"conditions"` +} + +// +genclient +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// CredentialsRequest is the Schema for the credentialsrequests API +// +k8s:openapi-gen=true +// +kubebuilder:subresource:status +type CredentialsRequest struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec CredentialsRequestSpec `json:"spec"` + Status CredentialsRequestStatus `json:"status,omitempty"` +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// CredentialsRequestList contains a list of CredentialsRequest +type CredentialsRequestList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []CredentialsRequest `json:"items"` +} + +// CredentialsRequestCondition contains details for any of the conditions on a CredentialsRequest object +type CredentialsRequestCondition struct { + // Type is the specific type of the condition + Type CredentialsRequestConditionType `json:"type"` + // Status is the status of the condition + Status corev1.ConditionStatus `json:"status"` + // LastProbeTime is the last time we probed the condition + LastProbeTime metav1.Time `json:"lastProbeTime,omitempty"` + // LastTransitionTime is the last time the condition transitioned from one status to another. + LastTransitionTime metav1.Time `json:"lastTransitionTime,omitempty"` + // Reason is a unique, one-word, CamelCase reason for the condition's last transition + Reason string `json:"reason,omitempty"` + // Message is a human-readable message indicating details about the last transition + Message string `json:"message,omitempty"` +} + +// CredentialsRequestConditionType are the valid condition types for a CredentialsRequest +type CredentialsRequestConditionType string + +// These are valid conditions for a CredentialsRequest +const ( + // InsufficientCloudCredentials is true when the cloud credentials are deemed to be insufficient + // to either mint custom creds to satisfy the CredentialsRequest or insufficient to + // be able to be passed along as-is to satisfy the CredentialsRequest + InsufficientCloudCredentials CredentialsRequestConditionType = "InsufficientCloudCreds" + // MissingTargetNamespace is true when the namespace specified to hold the resulting + // credentials is not present + MissingTargetNamespace CredentialsRequestConditionType = "MissingTargetNamespace" + // CredentialsProvisionFailure is true whenver there has been an issue while trying + // to provision the credentials (either passthrough or minting). Error message will + // be stored directly in the condition message. + CredentialsProvisionFailure CredentialsRequestConditionType = "CredentialsGrantFailure" + // CredentialsDeprovisionFailure is true whenever there is an error when trying + // to clean up any previously-created cloud resources + CredentialsDeprovisionFailure CredentialsRequestConditionType = "CredentialsDeprovisionFailure" +) + +func init() { + SchemeBuilder.Register(&CredentialsRequest{}, &CredentialsRequestList{}, &AWSProviderStatus{}, &AWSProviderSpec{}) +} diff --git a/vendor/github.com/openshift/cloud-credential-operator/pkg/apis/cloudcredential/v1beta1/doc.go b/vendor/github.com/openshift/cloud-credential-operator/pkg/apis/cloudcredential/v1beta1/doc.go new file mode 100644 index 00000000000..d77bb79685c --- /dev/null +++ b/vendor/github.com/openshift/cloud-credential-operator/pkg/apis/cloudcredential/v1beta1/doc.go @@ -0,0 +1,23 @@ +/* +Copyright 2018 The OpenShift Authors. + +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 v1beta1 contains API Schema definitions for the cloudcredential v1beta1 API group +// +k8s:openapi-gen=true +// +k8s:deepcopy-gen=package,register +// +k8s:conversion-gen=github.com/openshift/cloud-credential-operator/pkg/apis/cloudcredential +// +k8s:defaulter-gen=TypeMeta +// +groupName=cloudcredential.openshift.io +package v1beta1 diff --git a/vendor/github.com/openshift/cloud-credential-operator/pkg/apis/cloudcredential/v1beta1/register.go b/vendor/github.com/openshift/cloud-credential-operator/pkg/apis/cloudcredential/v1beta1/register.go new file mode 100644 index 00000000000..586e386375e --- /dev/null +++ b/vendor/github.com/openshift/cloud-credential-operator/pkg/apis/cloudcredential/v1beta1/register.go @@ -0,0 +1,46 @@ +/* +Copyright 2018 The OpenShift Authors. + +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. +*/ + +// NOTE: Boilerplate only. Ignore this file. + +// Package v1beta1 contains API Schema definitions for the cloudcredential v1beta1 API group +// +k8s:openapi-gen=true +// +k8s:deepcopy-gen=package,register +// +k8s:conversion-gen=github.com/openshift/cloud-credential-operator/pkg/apis/cloudcredential +// +k8s:defaulter-gen=TypeMeta +// +groupName=cloudcredential.openshift.io +package v1beta1 + +import ( + "k8s.io/apimachinery/pkg/runtime/schema" + "sigs.k8s.io/controller-runtime/pkg/runtime/scheme" +) + +var ( + // SchemeGroupVersion is group version used to register these objects + SchemeGroupVersion = schema.GroupVersion{Group: "cloudcredential.openshift.io", Version: "v1beta1"} + + // SchemeBuilder is used to add go types to the GroupVersionKind scheme + SchemeBuilder = &scheme.Builder{GroupVersion: SchemeGroupVersion} + + // AddToScheme is required by pkg/client/... + AddToScheme = SchemeBuilder.AddToScheme +) + +// Resource is required by pkg/client/listers/... +func Resource(resource string) schema.GroupResource { + return SchemeGroupVersion.WithResource(resource).GroupResource() +} diff --git a/vendor/github.com/openshift/cloud-credential-operator/pkg/apis/cloudcredential/v1beta1/zz_generated.deepcopy.go b/vendor/github.com/openshift/cloud-credential-operator/pkg/apis/cloudcredential/v1beta1/zz_generated.deepcopy.go new file mode 100644 index 00000000000..39859ab2c20 --- /dev/null +++ b/vendor/github.com/openshift/cloud-credential-operator/pkg/apis/cloudcredential/v1beta1/zz_generated.deepcopy.go @@ -0,0 +1,235 @@ +// +build !ignore_autogenerated + +/* +Copyright 2018 The OpenShift Authors. + +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. +*/ +// Code generated by main. DO NOT EDIT. + +package v1beta1 + +import ( + runtime "k8s.io/apimachinery/pkg/runtime" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *AWSProviderSpec) DeepCopyInto(out *AWSProviderSpec) { + *out = *in + out.TypeMeta = in.TypeMeta + if in.StatementEntries != nil { + in, out := &in.StatementEntries, &out.StatementEntries + *out = make([]StatementEntry, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AWSProviderSpec. +func (in *AWSProviderSpec) DeepCopy() *AWSProviderSpec { + if in == nil { + return nil + } + out := new(AWSProviderSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *AWSProviderSpec) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *AWSProviderStatus) DeepCopyInto(out *AWSProviderStatus) { + *out = *in + out.TypeMeta = in.TypeMeta + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AWSProviderStatus. +func (in *AWSProviderStatus) DeepCopy() *AWSProviderStatus { + if in == nil { + return nil + } + out := new(AWSProviderStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *AWSProviderStatus) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CredentialsRequest) DeepCopyInto(out *CredentialsRequest) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CredentialsRequest. +func (in *CredentialsRequest) DeepCopy() *CredentialsRequest { + if in == nil { + return nil + } + out := new(CredentialsRequest) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *CredentialsRequest) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CredentialsRequestCondition) DeepCopyInto(out *CredentialsRequestCondition) { + *out = *in + in.LastProbeTime.DeepCopyInto(&out.LastProbeTime) + in.LastTransitionTime.DeepCopyInto(&out.LastTransitionTime) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CredentialsRequestCondition. +func (in *CredentialsRequestCondition) DeepCopy() *CredentialsRequestCondition { + if in == nil { + return nil + } + out := new(CredentialsRequestCondition) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CredentialsRequestList) DeepCopyInto(out *CredentialsRequestList) { + *out = *in + out.TypeMeta = in.TypeMeta + out.ListMeta = in.ListMeta + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]CredentialsRequest, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CredentialsRequestList. +func (in *CredentialsRequestList) DeepCopy() *CredentialsRequestList { + if in == nil { + return nil + } + out := new(CredentialsRequestList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *CredentialsRequestList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CredentialsRequestSpec) DeepCopyInto(out *CredentialsRequestSpec) { + *out = *in + out.SecretRef = in.SecretRef + if in.ProviderSpec != nil { + in, out := &in.ProviderSpec, &out.ProviderSpec + *out = new(runtime.RawExtension) + (*in).DeepCopyInto(*out) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CredentialsRequestSpec. +func (in *CredentialsRequestSpec) DeepCopy() *CredentialsRequestSpec { + if in == nil { + return nil + } + out := new(CredentialsRequestSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CredentialsRequestStatus) DeepCopyInto(out *CredentialsRequestStatus) { + *out = *in + if in.LastSyncTimestamp != nil { + in, out := &in.LastSyncTimestamp, &out.LastSyncTimestamp + *out = (*in).DeepCopy() + } + if in.ProviderStatus != nil { + in, out := &in.ProviderStatus, &out.ProviderStatus + *out = new(runtime.RawExtension) + (*in).DeepCopyInto(*out) + } + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make([]CredentialsRequestCondition, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CredentialsRequestStatus. +func (in *CredentialsRequestStatus) DeepCopy() *CredentialsRequestStatus { + if in == nil { + return nil + } + out := new(CredentialsRequestStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *StatementEntry) DeepCopyInto(out *StatementEntry) { + *out = *in + if in.Action != nil { + in, out := &in.Action, &out.Action + *out = make([]string, len(*in)) + copy(*out, *in) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StatementEntry. +func (in *StatementEntry) DeepCopy() *StatementEntry { + if in == nil { + return nil + } + out := new(StatementEntry) + in.DeepCopyInto(out) + return out +} diff --git a/vendor/github.com/openshift/cloud-credential-operator/pkg/aws/client.go b/vendor/github.com/openshift/cloud-credential-operator/pkg/aws/client.go new file mode 100644 index 00000000000..1bee8d36fb3 --- /dev/null +++ b/vendor/github.com/openshift/cloud-credential-operator/pkg/aws/client.go @@ -0,0 +1,150 @@ +/* +Copyright 2018 The OpenShift Authors. + +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 aws + +import ( + "context" + "fmt" + + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/types" + + "sigs.k8s.io/controller-runtime/pkg/client" + + awssdk "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/credentials" + "github.com/aws/aws-sdk-go/aws/session" + "github.com/aws/aws-sdk-go/service/iam" + "github.com/aws/aws-sdk-go/service/iam/iamiface" +) + +const ( + awsCredsSecretIDKey = "aws_access_key_id" + awsCredsSecretAccessKey = "aws_secret_access_key" +) + +//go:generate mockgen -source=./client.go -destination=./mock/client_generated.go -package=mock + +// Client is a wrapper object for actual AWS SDK clients to allow for easier testing. +type Client interface { + //IAM + CreateAccessKey(*iam.CreateAccessKeyInput) (*iam.CreateAccessKeyOutput, error) + CreateUser(*iam.CreateUserInput) (*iam.CreateUserOutput, error) + DeleteAccessKey(*iam.DeleteAccessKeyInput) (*iam.DeleteAccessKeyOutput, error) + DeleteUser(*iam.DeleteUserInput) (*iam.DeleteUserOutput, error) + DeleteUserPolicy(*iam.DeleteUserPolicyInput) (*iam.DeleteUserPolicyOutput, error) + GetUser(*iam.GetUserInput) (*iam.GetUserOutput, error) + ListAccessKeys(*iam.ListAccessKeysInput) (*iam.ListAccessKeysOutput, error) + ListUserPolicies(*iam.ListUserPoliciesInput) (*iam.ListUserPoliciesOutput, error) + PutUserPolicy(*iam.PutUserPolicyInput) (*iam.PutUserPolicyOutput, error) + GetUserPolicy(*iam.GetUserPolicyInput) (*iam.GetUserPolicyOutput, error) + SimulatePrincipalPolicy(*iam.SimulatePrincipalPolicyInput) (*iam.SimulatePolicyResponse, error) + TagUser(*iam.TagUserInput) (*iam.TagUserOutput, error) +} + +type awsClient struct { + iamClient iamiface.IAMAPI +} + +func (c *awsClient) CreateAccessKey(input *iam.CreateAccessKeyInput) (*iam.CreateAccessKeyOutput, error) { + return c.iamClient.CreateAccessKey(input) +} + +func (c *awsClient) CreateUser(input *iam.CreateUserInput) (*iam.CreateUserOutput, error) { + return c.iamClient.CreateUser(input) +} + +func (c *awsClient) DeleteAccessKey(input *iam.DeleteAccessKeyInput) (*iam.DeleteAccessKeyOutput, error) { + return c.iamClient.DeleteAccessKey(input) +} + +func (c *awsClient) DeleteUser(input *iam.DeleteUserInput) (*iam.DeleteUserOutput, error) { + return c.iamClient.DeleteUser(input) +} + +func (c *awsClient) DeleteUserPolicy(input *iam.DeleteUserPolicyInput) (*iam.DeleteUserPolicyOutput, error) { + return c.iamClient.DeleteUserPolicy(input) +} +func (c *awsClient) GetUser(input *iam.GetUserInput) (*iam.GetUserOutput, error) { + return c.iamClient.GetUser(input) +} + +func (c *awsClient) ListAccessKeys(input *iam.ListAccessKeysInput) (*iam.ListAccessKeysOutput, error) { + return c.iamClient.ListAccessKeys(input) +} + +func (c *awsClient) ListUserPolicies(input *iam.ListUserPoliciesInput) (*iam.ListUserPoliciesOutput, error) { + return c.iamClient.ListUserPolicies(input) +} + +func (c *awsClient) PutUserPolicy(input *iam.PutUserPolicyInput) (*iam.PutUserPolicyOutput, error) { + return c.iamClient.PutUserPolicy(input) +} + +func (c *awsClient) GetUserPolicy(input *iam.GetUserPolicyInput) (*iam.GetUserPolicyOutput, error) { + return c.iamClient.GetUserPolicy(input) +} + +func (c *awsClient) SimulatePrincipalPolicy(input *iam.SimulatePrincipalPolicyInput) (*iam.SimulatePolicyResponse, error) { + return c.iamClient.SimulatePrincipalPolicy(input) +} + +func (c *awsClient) TagUser(input *iam.TagUserInput) (*iam.TagUserOutput, error) { + return c.iamClient.TagUser(input) +} + +// NewClient creates our client wrapper object for the actual AWS clients we use. +func NewClient(accessKeyID, secretAccessKey []byte) (Client, error) { + awsConfig := &awssdk.Config{} + + awsConfig.Credentials = credentials.NewStaticCredentials( + string(accessKeyID), string(secretAccessKey), "") + + s, err := session.NewSession(awsConfig) + if err != nil { + return nil, err + } + + return &awsClient{ + iamClient: iam.New(s), + }, nil +} + +func LoadCredsFromSecret(kubeClient client.Client, namespace, secretName string) ([]byte, []byte, error) { + + secret := &corev1.Secret{} + err := kubeClient.Get(context.TODO(), + types.NamespacedName{ + Name: secretName, + Namespace: namespace, + }, + secret) + if err != nil { + return nil, nil, err + } + accessKeyID, ok := secret.Data[awsCredsSecretIDKey] + if !ok { + return nil, nil, fmt.Errorf("AWS credentials secret %v did not contain key %v", + secretName, awsCredsSecretIDKey) + } + secretAccessKey, ok := secret.Data[awsCredsSecretAccessKey] + if !ok { + return nil, nil, fmt.Errorf("AWS credentials secret %v did not contain key %v", + secretName, awsCredsSecretAccessKey) + } + return accessKeyID, secretAccessKey, nil +} diff --git a/vendor/github.com/openshift/cloud-credential-operator/pkg/controller/assets/bindata.go b/vendor/github.com/openshift/cloud-credential-operator/pkg/controller/assets/bindata.go new file mode 100644 index 00000000000..ff3ed87aa17 --- /dev/null +++ b/vendor/github.com/openshift/cloud-credential-operator/pkg/controller/assets/bindata.go @@ -0,0 +1,106 @@ +package assets + +import ( + "fmt" + "strings" +) + +var _config_samples_credminter_v1_credentialsrequest_yaml = []byte(`apiVersion: cloudcredential.openshift.io/v1beta1 +kind: CredentialsRequest +metadata: + labels: + controller-tools.k8s.io: "1.0" + name: openshift-image-registry +spec: + secretRef: + name: installer-cloud-credentials + namespace: myproject2 + providerSpec: + apiVersion: cloudcredential.openshift.io/v1beta1 + kind: AWSProviderSpec + statementEntries: + - effect: Allow + action: + - s3:CreateBucket + - s3:DeleteBucket + resource: "*" +--- + +`) + +func config_samples_credminter_v1_credentialsrequest_yaml() ([]byte, error) { + return _config_samples_credminter_v1_credentialsrequest_yaml, nil +} + +// Asset loads and returns the asset for the given name. +// It returns an error if the asset could not be found or +// could not be loaded. +func Asset(name string) ([]byte, error) { + cannonicalName := strings.Replace(name, "\\", "/", -1) + if f, ok := _bindata[cannonicalName]; ok { + return f() + } + return nil, fmt.Errorf("Asset %s not found", name) +} + +// AssetNames returns the names of the assets. +func AssetNames() []string { + names := make([]string, 0, len(_bindata)) + for name := range _bindata { + names = append(names, name) + } + return names +} + +// _bindata is a table, holding each asset generator, mapped to its name. +var _bindata = map[string]func() ([]byte, error){ + "config/samples/credminter_v1_credentialsrequest.yaml": config_samples_credminter_v1_credentialsrequest_yaml, +} + +// AssetDir returns the file names below a certain +// directory embedded in the file by go-bindata. +// For example if you run go-bindata on data/... and data contains the +// following hierarchy: +// data/ +// foo.txt +// img/ +// a.png +// b.png +// then AssetDir("data") would return []string{"foo.txt", "img"} +// AssetDir("data/img") would return []string{"a.png", "b.png"} +// AssetDir("foo.txt") and AssetDir("notexist") would return an error +// AssetDir("") will return []string{"data"}. +func AssetDir(name string) ([]string, error) { + node := _bintree + if len(name) != 0 { + cannonicalName := strings.Replace(name, "\\", "/", -1) + pathList := strings.Split(cannonicalName, "/") + for _, p := range pathList { + node = node.Children[p] + if node == nil { + return nil, fmt.Errorf("Asset %s not found", name) + } + } + } + if node.Func != nil { + return nil, fmt.Errorf("Asset %s not found", name) + } + rv := make([]string, 0, len(node.Children)) + for name := range node.Children { + rv = append(rv, name) + } + return rv, nil +} + +type _bintree_t struct { + Func func() ([]byte, error) + Children map[string]*_bintree_t +} + +var _bintree = &_bintree_t{nil, map[string]*_bintree_t{ + "config": {nil, map[string]*_bintree_t{ + "samples": {nil, map[string]*_bintree_t{ + "credminter_v1_credentialsrequest.yaml": {config_samples_credminter_v1_credentialsrequest_yaml, map[string]*_bintree_t{}}, + }}, + }}, +}} diff --git a/vendor/github.com/openshift/cloud-credential-operator/pkg/controller/utils/condition_utils.go b/vendor/github.com/openshift/cloud-credential-operator/pkg/controller/utils/condition_utils.go new file mode 100644 index 00000000000..939de8e4d69 --- /dev/null +++ b/vendor/github.com/openshift/cloud-credential-operator/pkg/controller/utils/condition_utils.go @@ -0,0 +1,119 @@ +/* +Copyright 2018 The OpenShift Authors. + +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 utils + +import ( + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + ccv1beta1 "github.com/openshift/cloud-credential-operator/pkg/apis/cloudcredential/v1beta1" +) + +// UpdateConditionCheck tests whether a condition should be updated from the +// old condition to the new condition. Returns true if the condition should +// be updated. +type UpdateConditionCheck func(oldReason, oldMessage, newReason, newMessage string) bool + +// UpdateConditionAlways returns true. The condition will always be updated. +func UpdateConditionAlways(_, _, _, _ string) bool { + return true +} + +// UpdateConditionIfReasonOrMessageChange returns true if there is a change +// in the reason or the message of the condition. +func UpdateConditionIfReasonOrMessageChange(oldReason, oldMessage, newReason, newMessage string) bool { + return oldReason != newReason || + oldMessage != newMessage +} + +// UpdateConditionNever return false. The condition will never be updated, +// unless there is a change in the status of the condition. +func UpdateConditionNever(_, _, _, _ string) bool { + return false +} + +// FindCredentialsRequestCondition finds in the cluster the condition that has the +// specified condition type. If none exists, then returns nil. +func FindCredentialsRequestCondition(conditions []ccv1beta1.CredentialsRequestCondition, conditionType ccv1beta1.CredentialsRequestConditionType) *ccv1beta1.CredentialsRequestCondition { + for i, condition := range conditions { + if condition.Type == conditionType { + return &conditions[i] + } + } + return nil +} + +func shouldUpdateCondition( + oldStatus corev1.ConditionStatus, oldReason, oldMessage string, + newStatus corev1.ConditionStatus, newReason, newMessage string, + updateConditionCheck UpdateConditionCheck, +) bool { + if oldStatus != newStatus { + return true + } + return updateConditionCheck(oldReason, oldMessage, newReason, newMessage) +} + +// SetCredentialsRequestCondition sets the condition for the CredentialsRequest and returns the new slice of conditions. +// If the CredentialsRequest does not already have a condition with the specified type, +// a condition will be added to the slice if and only if the specified +// status is True. +// If the CredentialsRequest does already have a condition with the specified type, +// the condition will be updated if either of the following are true. +// 1) Requested status is different than existing status. +// 2) The updateConditionCheck function returns true. +func SetCredentialsRequestCondition( + conditions []ccv1beta1.CredentialsRequestCondition, + conditionType ccv1beta1.CredentialsRequestConditionType, + status corev1.ConditionStatus, + reason string, + message string, + updateConditionCheck UpdateConditionCheck, +) []ccv1beta1.CredentialsRequestCondition { + now := metav1.Now() + existingCondition := FindCredentialsRequestCondition(conditions, conditionType) + if existingCondition == nil { + if status == corev1.ConditionTrue { + conditions = append( + conditions, + ccv1beta1.CredentialsRequestCondition{ + Type: conditionType, + Status: status, + Reason: reason, + Message: message, + LastTransitionTime: now, + LastProbeTime: now, + }, + ) + } + } else { + if shouldUpdateCondition( + existingCondition.Status, existingCondition.Reason, existingCondition.Message, + status, reason, message, + updateConditionCheck, + ) { + if existingCondition.Status != status { + existingCondition.LastTransitionTime = now + } + existingCondition.Status = status + existingCondition.Reason = reason + existingCondition.Message = message + existingCondition.LastProbeTime = now + } + } + return conditions +} diff --git a/vendor/github.com/openshift/cloud-credential-operator/pkg/controller/utils/utils.go b/vendor/github.com/openshift/cloud-credential-operator/pkg/controller/utils/utils.go new file mode 100644 index 00000000000..53f293c0481 --- /dev/null +++ b/vendor/github.com/openshift/cloud-credential-operator/pkg/controller/utils/utils.go @@ -0,0 +1,169 @@ +package utils + +import ( + "fmt" + + log "github.com/sirupsen/logrus" + + ccv1beta1 "github.com/openshift/cloud-credential-operator/pkg/apis/cloudcredential/v1beta1" + ccaws "github.com/openshift/cloud-credential-operator/pkg/aws" + "github.com/openshift/cloud-credential-operator/pkg/controller/assets" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/iam" + + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/serializer" +) + +// credMintingActions is a list of AWS verbs needed to run in the mode where the +// cloud-credential-operator can mint new creds to satisfy CredentialRequest CRDs +var ( + CredMintingActions = []string{ + "iam:CreateAccessKey", + "iam:CreateUser", + "iam:DeleteAccessKey", + "iam:DeleteUser", + "iam:DeleteUserPolicy", + "iam:GetUser", + "iam:ListAccessKeys", + "iam:PutUserPolicy", + "iam:TagUser", + "iam:SimulatePrincipalPolicy", // needed so we can verify the above list of course + } + + credentailRequestScheme = runtime.NewScheme() + credentialRequestCodec = serializer.NewCodecFactory(credentailRequestScheme) +) + +func init() { + if err := ccv1beta1.AddToScheme(credentailRequestScheme); err != nil { + panic(err) + } +} + +// CheckCloudCredCreation will see whether we have enough permissions to create new sub-creds +func CheckCloudCredCreation(awsClient ccaws.Client, logger log.FieldLogger) (bool, error) { + return CheckPermissionsAgainstActions(awsClient, CredMintingActions, logger) +} + +// CheckPermissionsUsingQueryClient will use queryClient to query whether the credentials in targetClient can perform the actions +// listed in the statementEntries. queryClient will need iam:GetUser and iam:SimulatePrincipalPolicy +func CheckPermissionsUsingQueryClient(queryClient, targetClient ccaws.Client, statementEntries []ccv1beta1.StatementEntry, logger log.FieldLogger) (bool, error) { + targetUsername, err := targetClient.GetUser(nil) + if err != nil { + return false, fmt.Errorf("error querying current username: %v", err) + } + + allowList := []*string{} + for _, statement := range statementEntries { + for _, action := range statement.Action { + allowList = append(allowList, aws.String(action)) + } + } + + results, err := queryClient.SimulatePrincipalPolicy(&iam.SimulatePrincipalPolicyInput{ + PolicySourceArn: targetUsername.User.Arn, + ActionNames: allowList, + }) + if err != nil { + return false, fmt.Errorf("error simulating policy: %v", err) + } + + // Either they are all allowed and we reutrn 'true', or it's a failure + allClear := true + for _, result := range results.EvaluationResults { + if *result.EvalDecision != "allowed" { + // Don't return on the first failure, so we can log the full list + // of failed/denied actions + logger.WithField("action", *result.EvalActionName).Warning("Action not allowed with tested creds") + allClear = false + } + } + + if !allClear { + logger.Warningf("Tested creds not able to perform all requested actions") + return false, nil + } + + return true, nil + +} + +// CheckPermissionsAgainstStatementList will test to see whether the list of actions in the provided +// list of StatementEntries can work with the credentials used by the passed-in awsClient +func CheckPermissionsAgainstStatementList(awsClient ccaws.Client, statementEntries []ccv1beta1.StatementEntry, logger log.FieldLogger) (bool, error) { + return CheckPermissionsUsingQueryClient(awsClient, awsClient, statementEntries, logger) +} + +// CheckPermissionsAgainstActions will take the static list of Actions to check whether the provided +// awsClient creds have sufficient permissions to perform the actions. +// Will return true/false indicating whether the permissions are sufficient. +func CheckPermissionsAgainstActions(awsClient ccaws.Client, actionList []string, logger log.FieldLogger) (bool, error) { + statementList := []ccv1beta1.StatementEntry{ + { + Action: actionList, + Resource: "*", + Effect: "Allow", + }, + } + + return CheckPermissionsAgainstStatementList(awsClient, statementList, logger) +} + +// CheckCloudCredPassthrough will see if the provided creds are good enough to pass through +// to other components as-is based on the generated list of permissions needed from the static +// manifests in the repo +func CheckCloudCredPassthrough(awsClient ccaws.Client, logger log.FieldLogger) (bool, error) { + statementList := []ccv1beta1.StatementEntry{} + + // Read in the static assets containing all the needed CredentialRequests/permissions + assetList := assets.AssetNames() + for _, oneAsset := range assetList { + crBytes, err := assets.Asset(oneAsset) + if err != nil { + return false, fmt.Errorf("error parsing CredentialRequest object: %v", err) + } + + statements, err := getCredentialRequestStatements(crBytes) + if err != nil { + return false, fmt.Errorf("error processing CredentialRequest: %v", err) + } + + statementList = append(statementList, statements...) + } + + return CheckPermissionsAgainstStatementList(awsClient, statementList, logger) +} + +func readCredentialRequest(cr []byte) (*ccv1beta1.CredentialsRequest, error) { + + newObj, err := runtime.Decode(credentialRequestCodec.UniversalDecoder(ccv1beta1.SchemeGroupVersion), cr) + if err != nil { + return nil, fmt.Errorf("error decoding credentialrequest: %v", err) + } + return newObj.(*ccv1beta1.CredentialsRequest), nil +} + +func getCredentialRequestStatements(crBytes []byte) ([]ccv1beta1.StatementEntry, error) { + statementList := []ccv1beta1.StatementEntry{} + + awsCodec, err := ccv1beta1.NewCodec() + if err != nil { + return statementList, fmt.Errorf("error creating credentialrequest codec: %v", err) + } + + cr, err := readCredentialRequest(crBytes) + if err != nil { + return statementList, err + } + + awsSpec, err := awsCodec.DecodeProviderSpec(cr.Spec.ProviderSpec, &ccv1beta1.AWSProviderSpec{}) + if err != nil { + return statementList, fmt.Errorf("error decoding spec.ProviderSpec: %v", err) + } + + statementList = append(statementList, awsSpec.StatementEntries...) + + return statementList, nil +} diff --git a/vendor/k8s.io/client-go/dynamic/interface.go b/vendor/k8s.io/client-go/dynamic/interface.go new file mode 100644 index 00000000000..c457be1780b --- /dev/null +++ b/vendor/k8s.io/client-go/dynamic/interface.go @@ -0,0 +1,59 @@ +/* +Copyright 2016 The Kubernetes Authors. + +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 dynamic + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apimachinery/pkg/types" + "k8s.io/apimachinery/pkg/watch" +) + +type Interface interface { + Resource(resource schema.GroupVersionResource) NamespaceableResourceInterface +} + +type ResourceInterface interface { + Create(obj *unstructured.Unstructured, options metav1.CreateOptions, subresources ...string) (*unstructured.Unstructured, error) + Update(obj *unstructured.Unstructured, options metav1.UpdateOptions, subresources ...string) (*unstructured.Unstructured, error) + UpdateStatus(obj *unstructured.Unstructured, options metav1.UpdateOptions) (*unstructured.Unstructured, error) + Delete(name string, options *metav1.DeleteOptions, subresources ...string) error + DeleteCollection(options *metav1.DeleteOptions, listOptions metav1.ListOptions) error + Get(name string, options metav1.GetOptions, subresources ...string) (*unstructured.Unstructured, error) + List(opts metav1.ListOptions) (*unstructured.UnstructuredList, error) + Watch(opts metav1.ListOptions) (watch.Interface, error) + Patch(name string, pt types.PatchType, data []byte, options metav1.UpdateOptions, subresources ...string) (*unstructured.Unstructured, error) +} + +type NamespaceableResourceInterface interface { + Namespace(string) ResourceInterface + ResourceInterface +} + +// APIPathResolverFunc knows how to convert a groupVersion to its API path. The Kind field is optional. +// TODO find a better place to move this for existing callers +type APIPathResolverFunc func(kind schema.GroupVersionKind) string + +// LegacyAPIPathResolverFunc can resolve paths properly with the legacy API. +// TODO find a better place to move this for existing callers +func LegacyAPIPathResolverFunc(kind schema.GroupVersionKind) string { + if len(kind.Group) == 0 { + return "/api" + } + return "/apis" +} diff --git a/vendor/k8s.io/client-go/dynamic/scheme.go b/vendor/k8s.io/client-go/dynamic/scheme.go new file mode 100644 index 00000000000..c4aa081f91f --- /dev/null +++ b/vendor/k8s.io/client-go/dynamic/scheme.go @@ -0,0 +1,98 @@ +/* +Copyright 2018 The Kubernetes Authors. + +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 dynamic + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apimachinery/pkg/runtime/serializer" + "k8s.io/apimachinery/pkg/runtime/serializer/json" + "k8s.io/apimachinery/pkg/runtime/serializer/versioning" +) + +var watchScheme = runtime.NewScheme() +var basicScheme = runtime.NewScheme() +var deleteScheme = runtime.NewScheme() +var parameterScheme = runtime.NewScheme() +var deleteOptionsCodec = serializer.NewCodecFactory(deleteScheme) +var dynamicParameterCodec = runtime.NewParameterCodec(parameterScheme) + +var versionV1 = schema.GroupVersion{Version: "v1"} + +func init() { + metav1.AddToGroupVersion(watchScheme, versionV1) + metav1.AddToGroupVersion(basicScheme, versionV1) + metav1.AddToGroupVersion(parameterScheme, versionV1) + metav1.AddToGroupVersion(deleteScheme, versionV1) +} + +var watchJsonSerializerInfo = runtime.SerializerInfo{ + MediaType: "application/json", + EncodesAsText: true, + Serializer: json.NewSerializer(json.DefaultMetaFactory, watchScheme, watchScheme, false), + PrettySerializer: json.NewSerializer(json.DefaultMetaFactory, watchScheme, watchScheme, true), + StreamSerializer: &runtime.StreamSerializerInfo{ + EncodesAsText: true, + Serializer: json.NewSerializer(json.DefaultMetaFactory, watchScheme, watchScheme, false), + Framer: json.Framer, + }, +} + +// watchNegotiatedSerializer is used to read the wrapper of the watch stream +type watchNegotiatedSerializer struct{} + +var watchNegotiatedSerializerInstance = watchNegotiatedSerializer{} + +func (s watchNegotiatedSerializer) SupportedMediaTypes() []runtime.SerializerInfo { + return []runtime.SerializerInfo{watchJsonSerializerInfo} +} + +func (s watchNegotiatedSerializer) EncoderForVersion(encoder runtime.Encoder, gv runtime.GroupVersioner) runtime.Encoder { + return versioning.NewDefaultingCodecForScheme(watchScheme, encoder, nil, gv, nil) +} + +func (s watchNegotiatedSerializer) DecoderToVersion(decoder runtime.Decoder, gv runtime.GroupVersioner) runtime.Decoder { + return versioning.NewDefaultingCodecForScheme(watchScheme, nil, decoder, nil, gv) +} + +// basicNegotiatedSerializer is used to handle discovery and error handling serialization +type basicNegotiatedSerializer struct{} + +func (s basicNegotiatedSerializer) SupportedMediaTypes() []runtime.SerializerInfo { + return []runtime.SerializerInfo{ + { + MediaType: "application/json", + EncodesAsText: true, + Serializer: json.NewSerializer(json.DefaultMetaFactory, basicScheme, basicScheme, false), + PrettySerializer: json.NewSerializer(json.DefaultMetaFactory, basicScheme, basicScheme, true), + StreamSerializer: &runtime.StreamSerializerInfo{ + EncodesAsText: true, + Serializer: json.NewSerializer(json.DefaultMetaFactory, basicScheme, basicScheme, false), + Framer: json.Framer, + }, + }, + } +} + +func (s basicNegotiatedSerializer) EncoderForVersion(encoder runtime.Encoder, gv runtime.GroupVersioner) runtime.Encoder { + return versioning.NewDefaultingCodecForScheme(watchScheme, encoder, nil, gv, nil) +} + +func (s basicNegotiatedSerializer) DecoderToVersion(decoder runtime.Decoder, gv runtime.GroupVersioner) runtime.Decoder { + return versioning.NewDefaultingCodecForScheme(watchScheme, nil, decoder, nil, gv) +} diff --git a/vendor/k8s.io/client-go/dynamic/simple.go b/vendor/k8s.io/client-go/dynamic/simple.go new file mode 100644 index 00000000000..9e21cda6e37 --- /dev/null +++ b/vendor/k8s.io/client-go/dynamic/simple.go @@ -0,0 +1,326 @@ +/* +Copyright 2018 The Kubernetes Authors. + +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 dynamic + +import ( + "io" + + "k8s.io/apimachinery/pkg/api/meta" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apimachinery/pkg/runtime/serializer/streaming" + "k8s.io/apimachinery/pkg/types" + "k8s.io/apimachinery/pkg/watch" + "k8s.io/client-go/rest" +) + +type dynamicClient struct { + client *rest.RESTClient +} + +var _ Interface = &dynamicClient{} + +// NewForConfigOrDie creates a new Interface for the given config and +// panics if there is an error in the config. +func NewForConfigOrDie(c *rest.Config) Interface { + ret, err := NewForConfig(c) + if err != nil { + panic(err) + } + return ret +} + +func NewForConfig(inConfig *rest.Config) (Interface, error) { + config := rest.CopyConfig(inConfig) + // for serializing the options + config.GroupVersion = &schema.GroupVersion{} + config.APIPath = "/if-you-see-this-search-for-the-break" + config.AcceptContentTypes = "application/json" + config.ContentType = "application/json" + config.NegotiatedSerializer = basicNegotiatedSerializer{} // this gets used for discovery and error handling types + if config.UserAgent == "" { + config.UserAgent = rest.DefaultKubernetesUserAgent() + } + + restClient, err := rest.RESTClientFor(config) + if err != nil { + return nil, err + } + + return &dynamicClient{client: restClient}, nil +} + +type dynamicResourceClient struct { + client *dynamicClient + namespace string + resource schema.GroupVersionResource +} + +func (c *dynamicClient) Resource(resource schema.GroupVersionResource) NamespaceableResourceInterface { + return &dynamicResourceClient{client: c, resource: resource} +} + +func (c *dynamicResourceClient) Namespace(ns string) ResourceInterface { + ret := *c + ret.namespace = ns + return &ret +} + +func (c *dynamicResourceClient) Create(obj *unstructured.Unstructured, opts metav1.CreateOptions, subresources ...string) (*unstructured.Unstructured, error) { + outBytes, err := runtime.Encode(unstructured.UnstructuredJSONScheme, obj) + if err != nil { + return nil, err + } + name := "" + if len(subresources) > 0 { + accessor, err := meta.Accessor(obj) + if err != nil { + return nil, err + } + name = accessor.GetName() + } + + result := c.client.client. + Post(). + AbsPath(append(c.makeURLSegments(name), subresources...)...). + Body(outBytes). + SpecificallyVersionedParams(&opts, dynamicParameterCodec, versionV1). + Do() + if err := result.Error(); err != nil { + return nil, err + } + + retBytes, err := result.Raw() + if err != nil { + return nil, err + } + uncastObj, err := runtime.Decode(unstructured.UnstructuredJSONScheme, retBytes) + if err != nil { + return nil, err + } + return uncastObj.(*unstructured.Unstructured), nil +} + +func (c *dynamicResourceClient) Update(obj *unstructured.Unstructured, opts metav1.UpdateOptions, subresources ...string) (*unstructured.Unstructured, error) { + accessor, err := meta.Accessor(obj) + if err != nil { + return nil, err + } + outBytes, err := runtime.Encode(unstructured.UnstructuredJSONScheme, obj) + if err != nil { + return nil, err + } + + result := c.client.client. + Put(). + AbsPath(append(c.makeURLSegments(accessor.GetName()), subresources...)...). + Body(outBytes). + SpecificallyVersionedParams(&opts, dynamicParameterCodec, versionV1). + Do() + if err := result.Error(); err != nil { + return nil, err + } + + retBytes, err := result.Raw() + if err != nil { + return nil, err + } + uncastObj, err := runtime.Decode(unstructured.UnstructuredJSONScheme, retBytes) + if err != nil { + return nil, err + } + return uncastObj.(*unstructured.Unstructured), nil +} + +func (c *dynamicResourceClient) UpdateStatus(obj *unstructured.Unstructured, opts metav1.UpdateOptions) (*unstructured.Unstructured, error) { + accessor, err := meta.Accessor(obj) + if err != nil { + return nil, err + } + + outBytes, err := runtime.Encode(unstructured.UnstructuredJSONScheme, obj) + if err != nil { + return nil, err + } + + result := c.client.client. + Put(). + AbsPath(append(c.makeURLSegments(accessor.GetName()), "status")...). + Body(outBytes). + SpecificallyVersionedParams(&opts, dynamicParameterCodec, versionV1). + Do() + if err := result.Error(); err != nil { + return nil, err + } + + retBytes, err := result.Raw() + if err != nil { + return nil, err + } + uncastObj, err := runtime.Decode(unstructured.UnstructuredJSONScheme, retBytes) + if err != nil { + return nil, err + } + return uncastObj.(*unstructured.Unstructured), nil +} + +func (c *dynamicResourceClient) Delete(name string, opts *metav1.DeleteOptions, subresources ...string) error { + if opts == nil { + opts = &metav1.DeleteOptions{} + } + deleteOptionsByte, err := runtime.Encode(deleteOptionsCodec.LegacyCodec(schema.GroupVersion{Version: "v1"}), opts) + if err != nil { + return err + } + + result := c.client.client. + Delete(). + AbsPath(append(c.makeURLSegments(name), subresources...)...). + Body(deleteOptionsByte). + Do() + return result.Error() +} + +func (c *dynamicResourceClient) DeleteCollection(opts *metav1.DeleteOptions, listOptions metav1.ListOptions) error { + if opts == nil { + opts = &metav1.DeleteOptions{} + } + deleteOptionsByte, err := runtime.Encode(deleteOptionsCodec.LegacyCodec(schema.GroupVersion{Version: "v1"}), opts) + if err != nil { + return err + } + + result := c.client.client. + Delete(). + AbsPath(c.makeURLSegments("")...). + Body(deleteOptionsByte). + SpecificallyVersionedParams(&listOptions, dynamicParameterCodec, versionV1). + Do() + return result.Error() +} + +func (c *dynamicResourceClient) Get(name string, opts metav1.GetOptions, subresources ...string) (*unstructured.Unstructured, error) { + result := c.client.client.Get().AbsPath(append(c.makeURLSegments(name), subresources...)...).SpecificallyVersionedParams(&opts, dynamicParameterCodec, versionV1).Do() + if err := result.Error(); err != nil { + return nil, err + } + retBytes, err := result.Raw() + if err != nil { + return nil, err + } + uncastObj, err := runtime.Decode(unstructured.UnstructuredJSONScheme, retBytes) + if err != nil { + return nil, err + } + return uncastObj.(*unstructured.Unstructured), nil +} + +func (c *dynamicResourceClient) List(opts metav1.ListOptions) (*unstructured.UnstructuredList, error) { + result := c.client.client.Get().AbsPath(c.makeURLSegments("")...).SpecificallyVersionedParams(&opts, dynamicParameterCodec, versionV1).Do() + if err := result.Error(); err != nil { + return nil, err + } + retBytes, err := result.Raw() + if err != nil { + return nil, err + } + uncastObj, err := runtime.Decode(unstructured.UnstructuredJSONScheme, retBytes) + if err != nil { + return nil, err + } + if list, ok := uncastObj.(*unstructured.UnstructuredList); ok { + return list, nil + } + + list, err := uncastObj.(*unstructured.Unstructured).ToList() + if err != nil { + return nil, err + } + return list, nil +} + +func (c *dynamicResourceClient) Watch(opts metav1.ListOptions) (watch.Interface, error) { + internalGV := schema.GroupVersions{ + {Group: c.resource.Group, Version: runtime.APIVersionInternal}, + // always include the legacy group as a decoding target to handle non-error `Status` return types + {Group: "", Version: runtime.APIVersionInternal}, + } + s := &rest.Serializers{ + Encoder: watchNegotiatedSerializerInstance.EncoderForVersion(watchJsonSerializerInfo.Serializer, c.resource.GroupVersion()), + Decoder: watchNegotiatedSerializerInstance.DecoderToVersion(watchJsonSerializerInfo.Serializer, internalGV), + + RenegotiatedDecoder: func(contentType string, params map[string]string) (runtime.Decoder, error) { + return watchNegotiatedSerializerInstance.DecoderToVersion(watchJsonSerializerInfo.Serializer, internalGV), nil + }, + StreamingSerializer: watchJsonSerializerInfo.StreamSerializer.Serializer, + Framer: watchJsonSerializerInfo.StreamSerializer.Framer, + } + + wrappedDecoderFn := func(body io.ReadCloser) streaming.Decoder { + framer := s.Framer.NewFrameReader(body) + return streaming.NewDecoder(framer, s.StreamingSerializer) + } + + opts.Watch = true + return c.client.client.Get().AbsPath(c.makeURLSegments("")...). + SpecificallyVersionedParams(&opts, dynamicParameterCodec, versionV1). + WatchWithSpecificDecoders(wrappedDecoderFn, unstructured.UnstructuredJSONScheme) +} + +func (c *dynamicResourceClient) Patch(name string, pt types.PatchType, data []byte, opts metav1.UpdateOptions, subresources ...string) (*unstructured.Unstructured, error) { + result := c.client.client. + Patch(pt). + AbsPath(append(c.makeURLSegments(name), subresources...)...). + Body(data). + SpecificallyVersionedParams(&opts, dynamicParameterCodec, versionV1). + Do() + if err := result.Error(); err != nil { + return nil, err + } + retBytes, err := result.Raw() + if err != nil { + return nil, err + } + uncastObj, err := runtime.Decode(unstructured.UnstructuredJSONScheme, retBytes) + if err != nil { + return nil, err + } + return uncastObj.(*unstructured.Unstructured), nil +} + +func (c *dynamicResourceClient) makeURLSegments(name string) []string { + url := []string{} + if len(c.resource.Group) == 0 { + url = append(url, "api") + } else { + url = append(url, "apis", c.resource.Group) + } + url = append(url, c.resource.Version) + + if len(c.namespace) > 0 { + url = append(url, "namespaces", c.namespace) + } + url = append(url, c.resource.Resource) + + if len(name) > 0 { + url = append(url, name) + } + + return url +} diff --git a/vendor/k8s.io/client-go/restmapper/category_expansion.go b/vendor/k8s.io/client-go/restmapper/category_expansion.go new file mode 100644 index 00000000000..1620bbcf810 --- /dev/null +++ b/vendor/k8s.io/client-go/restmapper/category_expansion.go @@ -0,0 +1,119 @@ +/* +Copyright 2017 The Kubernetes Authors. + +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 restmapper + +import ( + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/client-go/discovery" +) + +// CategoryExpander maps category strings to GroupResouces. +// Categories are classification or 'tag' of a group of resources. +type CategoryExpander interface { + Expand(category string) ([]schema.GroupResource, bool) +} + +// SimpleCategoryExpander implements CategoryExpander interface +// using a static mapping of categories to GroupResource mapping. +type SimpleCategoryExpander struct { + Expansions map[string][]schema.GroupResource +} + +// Expand fulfills CategoryExpander +func (e SimpleCategoryExpander) Expand(category string) ([]schema.GroupResource, bool) { + ret, ok := e.Expansions[category] + return ret, ok +} + +// discoveryCategoryExpander struct lets a REST Client wrapper (discoveryClient) to retrieve list of APIResourceList, +// and then convert to fallbackExpander +type discoveryCategoryExpander struct { + discoveryClient discovery.DiscoveryInterface +} + +// NewDiscoveryCategoryExpander returns a category expander that makes use of the "categories" fields from +// the API, found through the discovery client. In case of any error or no category found (which likely +// means we're at a cluster prior to categories support, fallback to the expander provided. +func NewDiscoveryCategoryExpander(client discovery.DiscoveryInterface) CategoryExpander { + if client == nil { + panic("Please provide discovery client to shortcut expander") + } + return discoveryCategoryExpander{discoveryClient: client} +} + +// Expand fulfills CategoryExpander +func (e discoveryCategoryExpander) Expand(category string) ([]schema.GroupResource, bool) { + // Get all supported resources for groups and versions from server, if no resource found, fallback anyway. + apiResourceLists, _ := e.discoveryClient.ServerResources() + if len(apiResourceLists) == 0 { + return nil, false + } + + discoveredExpansions := map[string][]schema.GroupResource{} + for _, apiResourceList := range apiResourceLists { + gv, err := schema.ParseGroupVersion(apiResourceList.GroupVersion) + if err != nil { + continue + } + // Collect GroupVersions by categories + for _, apiResource := range apiResourceList.APIResources { + if categories := apiResource.Categories; len(categories) > 0 { + for _, category := range categories { + groupResource := schema.GroupResource{ + Group: gv.Group, + Resource: apiResource.Name, + } + discoveredExpansions[category] = append(discoveredExpansions[category], groupResource) + } + } + } + } + + ret, ok := discoveredExpansions[category] + return ret, ok +} + +// UnionCategoryExpander implements CategoryExpander interface. +// It maps given category string to union of expansions returned by all the CategoryExpanders in the list. +type UnionCategoryExpander []CategoryExpander + +// Expand fulfills CategoryExpander +func (u UnionCategoryExpander) Expand(category string) ([]schema.GroupResource, bool) { + ret := []schema.GroupResource{} + ok := false + + // Expand the category for each CategoryExpander in the list and merge/combine the results. + for _, expansion := range u { + curr, currOk := expansion.Expand(category) + + for _, currGR := range curr { + found := false + for _, existing := range ret { + if existing == currGR { + found = true + break + } + } + if !found { + ret = append(ret, currGR) + } + } + ok = ok || currOk + } + + return ret, ok +} diff --git a/vendor/k8s.io/client-go/restmapper/discovery.go b/vendor/k8s.io/client-go/restmapper/discovery.go new file mode 100644 index 00000000000..aa158626af4 --- /dev/null +++ b/vendor/k8s.io/client-go/restmapper/discovery.go @@ -0,0 +1,339 @@ +/* +Copyright 2016 The Kubernetes Authors. + +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 restmapper + +import ( + "fmt" + "strings" + "sync" + + "k8s.io/apimachinery/pkg/api/meta" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/client-go/discovery" + + "github.com/golang/glog" +) + +// APIGroupResources is an API group with a mapping of versions to +// resources. +type APIGroupResources struct { + Group metav1.APIGroup + // A mapping of version string to a slice of APIResources for + // that version. + VersionedResources map[string][]metav1.APIResource +} + +// NewDiscoveryRESTMapper returns a PriorityRESTMapper based on the discovered +// groups and resources passed in. +func NewDiscoveryRESTMapper(groupResources []*APIGroupResources) meta.RESTMapper { + unionMapper := meta.MultiRESTMapper{} + + var groupPriority []string + // /v1 is special. It should always come first + resourcePriority := []schema.GroupVersionResource{{Group: "", Version: "v1", Resource: meta.AnyResource}} + kindPriority := []schema.GroupVersionKind{{Group: "", Version: "v1", Kind: meta.AnyKind}} + + for _, group := range groupResources { + groupPriority = append(groupPriority, group.Group.Name) + + // Make sure the preferred version comes first + if len(group.Group.PreferredVersion.Version) != 0 { + preferred := group.Group.PreferredVersion.Version + if _, ok := group.VersionedResources[preferred]; ok { + resourcePriority = append(resourcePriority, schema.GroupVersionResource{ + Group: group.Group.Name, + Version: group.Group.PreferredVersion.Version, + Resource: meta.AnyResource, + }) + + kindPriority = append(kindPriority, schema.GroupVersionKind{ + Group: group.Group.Name, + Version: group.Group.PreferredVersion.Version, + Kind: meta.AnyKind, + }) + } + } + + for _, discoveryVersion := range group.Group.Versions { + resources, ok := group.VersionedResources[discoveryVersion.Version] + if !ok { + continue + } + + // Add non-preferred versions after the preferred version, in case there are resources that only exist in those versions + if discoveryVersion.Version != group.Group.PreferredVersion.Version { + resourcePriority = append(resourcePriority, schema.GroupVersionResource{ + Group: group.Group.Name, + Version: discoveryVersion.Version, + Resource: meta.AnyResource, + }) + + kindPriority = append(kindPriority, schema.GroupVersionKind{ + Group: group.Group.Name, + Version: discoveryVersion.Version, + Kind: meta.AnyKind, + }) + } + + gv := schema.GroupVersion{Group: group.Group.Name, Version: discoveryVersion.Version} + versionMapper := meta.NewDefaultRESTMapper([]schema.GroupVersion{gv}) + + for _, resource := range resources { + scope := meta.RESTScopeNamespace + if !resource.Namespaced { + scope = meta.RESTScopeRoot + } + + // if we have a slash, then this is a subresource and we shouldn't create mappings for those. + if strings.Contains(resource.Name, "/") { + continue + } + + plural := gv.WithResource(resource.Name) + singular := gv.WithResource(resource.SingularName) + // this is for legacy resources and servers which don't list singular forms. For those we must still guess. + if len(resource.SingularName) == 0 { + _, singular = meta.UnsafeGuessKindToResource(gv.WithKind(resource.Kind)) + } + + versionMapper.AddSpecific(gv.WithKind(strings.ToLower(resource.Kind)), plural, singular, scope) + versionMapper.AddSpecific(gv.WithKind(resource.Kind), plural, singular, scope) + // TODO this is producing unsafe guesses that don't actually work, but it matches previous behavior + versionMapper.Add(gv.WithKind(resource.Kind+"List"), scope) + } + // TODO why is this type not in discovery (at least for "v1") + versionMapper.Add(gv.WithKind("List"), meta.RESTScopeRoot) + unionMapper = append(unionMapper, versionMapper) + } + } + + for _, group := range groupPriority { + resourcePriority = append(resourcePriority, schema.GroupVersionResource{ + Group: group, + Version: meta.AnyVersion, + Resource: meta.AnyResource, + }) + kindPriority = append(kindPriority, schema.GroupVersionKind{ + Group: group, + Version: meta.AnyVersion, + Kind: meta.AnyKind, + }) + } + + return meta.PriorityRESTMapper{ + Delegate: unionMapper, + ResourcePriority: resourcePriority, + KindPriority: kindPriority, + } +} + +// GetAPIGroupResources uses the provided discovery client to gather +// discovery information and populate a slice of APIGroupResources. +func GetAPIGroupResources(cl discovery.DiscoveryInterface) ([]*APIGroupResources, error) { + apiGroups, err := cl.ServerGroups() + if err != nil { + if apiGroups == nil || len(apiGroups.Groups) == 0 { + return nil, err + } + // TODO track the errors and update callers to handle partial errors. + } + var result []*APIGroupResources + for _, group := range apiGroups.Groups { + groupResources := &APIGroupResources{ + Group: group, + VersionedResources: make(map[string][]metav1.APIResource), + } + for _, version := range group.Versions { + resources, err := cl.ServerResourcesForGroupVersion(version.GroupVersion) + if err != nil { + // continue as best we can + // TODO track the errors and update callers to handle partial errors. + if resources == nil || len(resources.APIResources) == 0 { + continue + } + } + groupResources.VersionedResources[version.Version] = resources.APIResources + } + result = append(result, groupResources) + } + return result, nil +} + +// DeferredDiscoveryRESTMapper is a RESTMapper that will defer +// initialization of the RESTMapper until the first mapping is +// requested. +type DeferredDiscoveryRESTMapper struct { + initMu sync.Mutex + delegate meta.RESTMapper + cl discovery.CachedDiscoveryInterface +} + +// NewDeferredDiscoveryRESTMapper returns a +// DeferredDiscoveryRESTMapper that will lazily query the provided +// client for discovery information to do REST mappings. +func NewDeferredDiscoveryRESTMapper(cl discovery.CachedDiscoveryInterface) *DeferredDiscoveryRESTMapper { + return &DeferredDiscoveryRESTMapper{ + cl: cl, + } +} + +func (d *DeferredDiscoveryRESTMapper) getDelegate() (meta.RESTMapper, error) { + d.initMu.Lock() + defer d.initMu.Unlock() + + if d.delegate != nil { + return d.delegate, nil + } + + groupResources, err := GetAPIGroupResources(d.cl) + if err != nil { + return nil, err + } + + d.delegate = NewDiscoveryRESTMapper(groupResources) + return d.delegate, err +} + +// Reset resets the internally cached Discovery information and will +// cause the next mapping request to re-discover. +func (d *DeferredDiscoveryRESTMapper) Reset() { + glog.V(5).Info("Invalidating discovery information") + + d.initMu.Lock() + defer d.initMu.Unlock() + + d.cl.Invalidate() + d.delegate = nil +} + +// KindFor takes a partial resource and returns back the single match. +// It returns an error if there are multiple matches. +func (d *DeferredDiscoveryRESTMapper) KindFor(resource schema.GroupVersionResource) (gvk schema.GroupVersionKind, err error) { + del, err := d.getDelegate() + if err != nil { + return schema.GroupVersionKind{}, err + } + gvk, err = del.KindFor(resource) + if err != nil && !d.cl.Fresh() { + d.Reset() + gvk, err = d.KindFor(resource) + } + return +} + +// KindsFor takes a partial resource and returns back the list of +// potential kinds in priority order. +func (d *DeferredDiscoveryRESTMapper) KindsFor(resource schema.GroupVersionResource) (gvks []schema.GroupVersionKind, err error) { + del, err := d.getDelegate() + if err != nil { + return nil, err + } + gvks, err = del.KindsFor(resource) + if len(gvks) == 0 && !d.cl.Fresh() { + d.Reset() + gvks, err = d.KindsFor(resource) + } + return +} + +// ResourceFor takes a partial resource and returns back the single +// match. It returns an error if there are multiple matches. +func (d *DeferredDiscoveryRESTMapper) ResourceFor(input schema.GroupVersionResource) (gvr schema.GroupVersionResource, err error) { + del, err := d.getDelegate() + if err != nil { + return schema.GroupVersionResource{}, err + } + gvr, err = del.ResourceFor(input) + if err != nil && !d.cl.Fresh() { + d.Reset() + gvr, err = d.ResourceFor(input) + } + return +} + +// ResourcesFor takes a partial resource and returns back the list of +// potential resource in priority order. +func (d *DeferredDiscoveryRESTMapper) ResourcesFor(input schema.GroupVersionResource) (gvrs []schema.GroupVersionResource, err error) { + del, err := d.getDelegate() + if err != nil { + return nil, err + } + gvrs, err = del.ResourcesFor(input) + if len(gvrs) == 0 && !d.cl.Fresh() { + d.Reset() + gvrs, err = d.ResourcesFor(input) + } + return +} + +// RESTMapping identifies a preferred resource mapping for the +// provided group kind. +func (d *DeferredDiscoveryRESTMapper) RESTMapping(gk schema.GroupKind, versions ...string) (m *meta.RESTMapping, err error) { + del, err := d.getDelegate() + if err != nil { + return nil, err + } + m, err = del.RESTMapping(gk, versions...) + if err != nil && !d.cl.Fresh() { + d.Reset() + m, err = d.RESTMapping(gk, versions...) + } + return +} + +// RESTMappings returns the RESTMappings for the provided group kind +// in a rough internal preferred order. If no kind is found, it will +// return a NoResourceMatchError. +func (d *DeferredDiscoveryRESTMapper) RESTMappings(gk schema.GroupKind, versions ...string) (ms []*meta.RESTMapping, err error) { + del, err := d.getDelegate() + if err != nil { + return nil, err + } + ms, err = del.RESTMappings(gk, versions...) + if len(ms) == 0 && !d.cl.Fresh() { + d.Reset() + ms, err = d.RESTMappings(gk, versions...) + } + return +} + +// ResourceSingularizer converts a resource name from plural to +// singular (e.g., from pods to pod). +func (d *DeferredDiscoveryRESTMapper) ResourceSingularizer(resource string) (singular string, err error) { + del, err := d.getDelegate() + if err != nil { + return resource, err + } + singular, err = del.ResourceSingularizer(resource) + if err != nil && !d.cl.Fresh() { + d.Reset() + singular, err = d.ResourceSingularizer(resource) + } + return +} + +func (d *DeferredDiscoveryRESTMapper) String() string { + del, err := d.getDelegate() + if err != nil { + return fmt.Sprintf("DeferredDiscoveryRESTMapper{%v}", err) + } + return fmt.Sprintf("DeferredDiscoveryRESTMapper{\n\t%v\n}", del) +} + +// Make sure it satisfies the interface +var _ meta.RESTMapper = &DeferredDiscoveryRESTMapper{} diff --git a/vendor/k8s.io/client-go/restmapper/shortcut.go b/vendor/k8s.io/client-go/restmapper/shortcut.go new file mode 100644 index 00000000000..d9f4be0b6b1 --- /dev/null +++ b/vendor/k8s.io/client-go/restmapper/shortcut.go @@ -0,0 +1,172 @@ +/* +Copyright 2016 The Kubernetes Authors. + +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 restmapper + +import ( + "strings" + + "github.com/golang/glog" + + "k8s.io/apimachinery/pkg/api/meta" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/client-go/discovery" +) + +// shortcutExpander is a RESTMapper that can be used for Kubernetes resources. It expands the resource first, then invokes the wrapped +type shortcutExpander struct { + RESTMapper meta.RESTMapper + + discoveryClient discovery.DiscoveryInterface +} + +var _ meta.RESTMapper = &shortcutExpander{} + +// NewShortcutExpander wraps a restmapper in a layer that expands shortcuts found via discovery +func NewShortcutExpander(delegate meta.RESTMapper, client discovery.DiscoveryInterface) meta.RESTMapper { + return shortcutExpander{RESTMapper: delegate, discoveryClient: client} +} + +// KindFor fulfills meta.RESTMapper +func (e shortcutExpander) KindFor(resource schema.GroupVersionResource) (schema.GroupVersionKind, error) { + return e.RESTMapper.KindFor(e.expandResourceShortcut(resource)) +} + +// KindsFor fulfills meta.RESTMapper +func (e shortcutExpander) KindsFor(resource schema.GroupVersionResource) ([]schema.GroupVersionKind, error) { + return e.RESTMapper.KindsFor(e.expandResourceShortcut(resource)) +} + +// ResourcesFor fulfills meta.RESTMapper +func (e shortcutExpander) ResourcesFor(resource schema.GroupVersionResource) ([]schema.GroupVersionResource, error) { + return e.RESTMapper.ResourcesFor(e.expandResourceShortcut(resource)) +} + +// ResourceFor fulfills meta.RESTMapper +func (e shortcutExpander) ResourceFor(resource schema.GroupVersionResource) (schema.GroupVersionResource, error) { + return e.RESTMapper.ResourceFor(e.expandResourceShortcut(resource)) +} + +// ResourceSingularizer fulfills meta.RESTMapper +func (e shortcutExpander) ResourceSingularizer(resource string) (string, error) { + return e.RESTMapper.ResourceSingularizer(e.expandResourceShortcut(schema.GroupVersionResource{Resource: resource}).Resource) +} + +// RESTMapping fulfills meta.RESTMapper +func (e shortcutExpander) RESTMapping(gk schema.GroupKind, versions ...string) (*meta.RESTMapping, error) { + return e.RESTMapper.RESTMapping(gk, versions...) +} + +// RESTMappings fulfills meta.RESTMapper +func (e shortcutExpander) RESTMappings(gk schema.GroupKind, versions ...string) ([]*meta.RESTMapping, error) { + return e.RESTMapper.RESTMappings(gk, versions...) +} + +// getShortcutMappings returns a set of tuples which holds short names for resources. +// First the list of potential resources will be taken from the API server. +// Next we will append the hardcoded list of resources - to be backward compatible with old servers. +// NOTE that the list is ordered by group priority. +func (e shortcutExpander) getShortcutMappings() ([]*metav1.APIResourceList, []resourceShortcuts, error) { + res := []resourceShortcuts{} + // get server resources + // This can return an error *and* the results it was able to find. We don't need to fail on the error. + apiResList, err := e.discoveryClient.ServerResources() + if err != nil { + glog.V(1).Infof("Error loading discovery information: %v", err) + } + for _, apiResources := range apiResList { + gv, err := schema.ParseGroupVersion(apiResources.GroupVersion) + if err != nil { + glog.V(1).Infof("Unable to parse groupversion = %s due to = %s", apiResources.GroupVersion, err.Error()) + continue + } + for _, apiRes := range apiResources.APIResources { + for _, shortName := range apiRes.ShortNames { + rs := resourceShortcuts{ + ShortForm: schema.GroupResource{Group: gv.Group, Resource: shortName}, + LongForm: schema.GroupResource{Group: gv.Group, Resource: apiRes.Name}, + } + res = append(res, rs) + } + } + } + + return apiResList, res, nil +} + +// expandResourceShortcut will return the expanded version of resource +// (something that a pkg/api/meta.RESTMapper can understand), if it is +// indeed a shortcut. If no match has been found, we will match on group prefixing. +// Lastly we will return resource unmodified. +func (e shortcutExpander) expandResourceShortcut(resource schema.GroupVersionResource) schema.GroupVersionResource { + // get the shortcut mappings and return on first match. + if allResources, shortcutResources, err := e.getShortcutMappings(); err == nil { + // avoid expanding if there's an exact match to a full resource name + for _, apiResources := range allResources { + gv, err := schema.ParseGroupVersion(apiResources.GroupVersion) + if err != nil { + continue + } + if len(resource.Group) != 0 && resource.Group != gv.Group { + continue + } + for _, apiRes := range apiResources.APIResources { + if resource.Resource == apiRes.Name { + return resource + } + if resource.Resource == apiRes.SingularName { + return resource + } + } + } + + for _, item := range shortcutResources { + if len(resource.Group) != 0 && resource.Group != item.ShortForm.Group { + continue + } + if resource.Resource == item.ShortForm.Resource { + resource.Resource = item.LongForm.Resource + resource.Group = item.LongForm.Group + return resource + } + } + + // we didn't find exact match so match on group prefixing. This allows autoscal to match autoscaling + if len(resource.Group) == 0 { + return resource + } + for _, item := range shortcutResources { + if !strings.HasPrefix(item.ShortForm.Group, resource.Group) { + continue + } + if resource.Resource == item.ShortForm.Resource { + resource.Resource = item.LongForm.Resource + resource.Group = item.LongForm.Group + return resource + } + } + } + + return resource +} + +// ResourceShortcuts represents a structure that holds the information how to +// transition from resource's shortcut to its full name. +type resourceShortcuts struct { + ShortForm schema.GroupResource + LongForm schema.GroupResource +} diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/client/apiutil/apimachinery.go b/vendor/sigs.k8s.io/controller-runtime/pkg/client/apiutil/apimachinery.go new file mode 100644 index 00000000000..614d454f1fb --- /dev/null +++ b/vendor/sigs.k8s.io/controller-runtime/pkg/client/apiutil/apimachinery.go @@ -0,0 +1,88 @@ +/* +Copyright 2018 The Kubernetes Authors. + +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 apiutil + +import ( + "fmt" + + "k8s.io/apimachinery/pkg/api/meta" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apimachinery/pkg/runtime/serializer" + "k8s.io/client-go/discovery" + "k8s.io/client-go/rest" + "k8s.io/client-go/restmapper" +) + +// NewDiscoveryRESTMapper constructs a new RESTMapper based on discovery +// information fetched by a new client with the given config. +func NewDiscoveryRESTMapper(c *rest.Config) (meta.RESTMapper, error) { + // Get a mapper + dc := discovery.NewDiscoveryClientForConfigOrDie(c) + gr, err := restmapper.GetAPIGroupResources(dc) + if err != nil { + return nil, err + } + return restmapper.NewDiscoveryRESTMapper(gr), nil +} + +// GVKForObject finds the GroupVersionKind associated with the given object, if there is only a single such GVK. +func GVKForObject(obj runtime.Object, scheme *runtime.Scheme) (schema.GroupVersionKind, error) { + gvks, isUnversioned, err := scheme.ObjectKinds(obj) + if err != nil { + return schema.GroupVersionKind{}, err + } + if isUnversioned { + return schema.GroupVersionKind{}, fmt.Errorf("cannot create a new informer for the unversioned type %T", obj) + } + + if len(gvks) < 1 { + return schema.GroupVersionKind{}, fmt.Errorf("no group-version-kinds associated with type %T", obj) + } + if len(gvks) > 1 { + // this should only trigger for things like metav1.XYZ -- + // normal versioned types should be fine + return schema.GroupVersionKind{}, fmt.Errorf( + "multiple group-version-kinds associated with type %T, refusing to guess at one", obj) + } + return gvks[0], nil +} + +// RESTClientForGVK constructs a new rest.Interface capable of accessing the resource associated +// with the given GroupVersionKind. +func RESTClientForGVK(gvk schema.GroupVersionKind, baseConfig *rest.Config, codecs serializer.CodecFactory) (rest.Interface, error) { + cfg := createRestConfig(gvk, baseConfig) + cfg.NegotiatedSerializer = serializer.DirectCodecFactory{CodecFactory: codecs} + return rest.RESTClientFor(cfg) +} + +//createRestConfig copies the base config and updates needed fields for a new rest config +func createRestConfig(gvk schema.GroupVersionKind, baseConfig *rest.Config) *rest.Config { + gv := gvk.GroupVersion() + + cfg := rest.CopyConfig(baseConfig) + cfg.GroupVersion = &gv + if gvk.Group == "" { + cfg.APIPath = "/api" + } else { + cfg.APIPath = "/apis" + } + if cfg.UserAgent == "" { + cfg.UserAgent = rest.DefaultKubernetesUserAgent() + } + return cfg +} diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/client/client.go b/vendor/sigs.k8s.io/controller-runtime/pkg/client/client.go new file mode 100644 index 00000000000..05b9eba2b4c --- /dev/null +++ b/vendor/sigs.k8s.io/controller-runtime/pkg/client/client.go @@ -0,0 +1,162 @@ +/* +Copyright 2018 The Kubernetes Authors. + +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 client + +import ( + "context" + "fmt" + "reflect" + + "k8s.io/apimachinery/pkg/api/meta" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/serializer" + "k8s.io/client-go/dynamic" + "k8s.io/client-go/kubernetes/scheme" + "k8s.io/client-go/rest" + "sigs.k8s.io/controller-runtime/pkg/client/apiutil" +) + +// Options are creation options for a Client +type Options struct { + // Scheme, if provided, will be used to map go structs to GroupVersionKinds + Scheme *runtime.Scheme + + // Mapper, if provided, will be used to map GroupVersionKinds to Resources + Mapper meta.RESTMapper +} + +// New returns a new Client using the provided config and Options. +func New(config *rest.Config, options Options) (Client, error) { + if config == nil { + return nil, fmt.Errorf("must provide non-nil rest.Config to client.New") + } + + // Init a scheme if none provided + if options.Scheme == nil { + options.Scheme = scheme.Scheme + } + + // Init a Mapper if none provided + if options.Mapper == nil { + var err error + options.Mapper, err = apiutil.NewDiscoveryRESTMapper(config) + if err != nil { + return nil, err + } + } + + dynamicClient, err := dynamic.NewForConfig(config) + if err != nil { + return nil, err + } + + c := &client{ + typedClient: typedClient{ + cache: clientCache{ + config: config, + scheme: options.Scheme, + mapper: options.Mapper, + codecs: serializer.NewCodecFactory(options.Scheme), + resourceByType: make(map[reflect.Type]*resourceMeta), + }, + paramCodec: runtime.NewParameterCodec(options.Scheme), + }, + unstructuredClient: unstructuredClient{ + client: dynamicClient, + restMapper: options.Mapper, + }, + } + + return c, nil +} + +var _ Client = &client{} + +// client is a client.Client that reads and writes directly from/to an API server. It lazily initializes +// new clients at the time they are used, and caches the client. +type client struct { + typedClient typedClient + unstructuredClient unstructuredClient +} + +// Create implements client.Client +func (c *client) Create(ctx context.Context, obj runtime.Object) error { + _, ok := obj.(*unstructured.Unstructured) + if ok { + return c.unstructuredClient.Create(ctx, obj) + } + return c.typedClient.Create(ctx, obj) +} + +// Update implements client.Client +func (c *client) Update(ctx context.Context, obj runtime.Object) error { + _, ok := obj.(*unstructured.Unstructured) + if ok { + return c.unstructuredClient.Update(ctx, obj) + } + return c.typedClient.Update(ctx, obj) +} + +// Delete implements client.Client +func (c *client) Delete(ctx context.Context, obj runtime.Object, opts ...DeleteOptionFunc) error { + _, ok := obj.(*unstructured.Unstructured) + if ok { + return c.unstructuredClient.Delete(ctx, obj, opts...) + } + return c.typedClient.Delete(ctx, obj, opts...) +} + +// Get implements client.Client +func (c *client) Get(ctx context.Context, key ObjectKey, obj runtime.Object) error { + _, ok := obj.(*unstructured.Unstructured) + if ok { + return c.unstructuredClient.Get(ctx, key, obj) + } + return c.typedClient.Get(ctx, key, obj) +} + +// List implements client.Client +func (c *client) List(ctx context.Context, opts *ListOptions, obj runtime.Object) error { + _, ok := obj.(*unstructured.UnstructuredList) + if ok { + return c.unstructuredClient.List(ctx, opts, obj) + } + return c.typedClient.List(ctx, opts, obj) +} + +// Status implements client.StatusClient +func (c *client) Status() StatusWriter { + return &statusWriter{client: c} +} + +// statusWriter is client.StatusWriter that writes status subresource +type statusWriter struct { + client *client +} + +// ensure statusWriter implements client.StatusWriter +var _ StatusWriter = &statusWriter{} + +// Update implements client.StatusWriter +func (sw *statusWriter) Update(ctx context.Context, obj runtime.Object) error { + _, ok := obj.(*unstructured.Unstructured) + if ok { + return sw.client.unstructuredClient.UpdateStatus(ctx, obj) + } + return sw.client.typedClient.UpdateStatus(ctx, obj) +} diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/client/client_cache.go b/vendor/sigs.k8s.io/controller-runtime/pkg/client/client_cache.go new file mode 100644 index 00000000000..d6452ab62e7 --- /dev/null +++ b/vendor/sigs.k8s.io/controller-runtime/pkg/client/client_cache.go @@ -0,0 +1,145 @@ +/* +Copyright 2018 The Kubernetes Authors. + +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 client + +import ( + "reflect" + "strings" + "sync" + + "k8s.io/apimachinery/pkg/api/meta" + "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apimachinery/pkg/runtime/serializer" + "k8s.io/client-go/rest" + "sigs.k8s.io/controller-runtime/pkg/client/apiutil" +) + +// clientCache creates and caches rest clients and metadata for Kubernetes types +type clientCache struct { + // config is the rest.Config to talk to an apiserver + config *rest.Config + + // scheme maps go structs to GroupVersionKinds + scheme *runtime.Scheme + + // mapper maps GroupVersionKinds to Resources + mapper meta.RESTMapper + + // codecs are used to create a REST client for a gvk + codecs serializer.CodecFactory + + // resourceByType caches type metadata + resourceByType map[reflect.Type]*resourceMeta + mu sync.RWMutex +} + +// newResource maps obj to a Kubernetes Resource and constructs a client for that Resource. +// If the object is a list, the resource represents the item's type instead. +func (c *clientCache) newResource(obj runtime.Object) (*resourceMeta, error) { + gvk, err := apiutil.GVKForObject(obj, c.scheme) + if err != nil { + return nil, err + } + + if strings.HasSuffix(gvk.Kind, "List") && meta.IsListType(obj) { + // if this was a list, treat it as a request for the item's resource + gvk.Kind = gvk.Kind[:len(gvk.Kind)-4] + } + + client, err := apiutil.RESTClientForGVK(gvk, c.config, c.codecs) + if err != nil { + return nil, err + } + mapping, err := c.mapper.RESTMapping(gvk.GroupKind(), gvk.Version) + if err != nil { + return nil, err + } + return &resourceMeta{Interface: client, mapping: mapping, gvk: gvk}, nil +} + +// getResource returns the resource meta information for the given type of object. +// If the object is a list, the resource represents the item's type instead. +func (c *clientCache) getResource(obj runtime.Object) (*resourceMeta, error) { + typ := reflect.TypeOf(obj) + + // It's better to do creation work twice than to not let multiple + // people make requests at once + c.mu.RLock() + r, known := c.resourceByType[typ] + c.mu.RUnlock() + + if known { + return r, nil + } + + // Initialize a new Client + c.mu.Lock() + defer c.mu.Unlock() + r, err := c.newResource(obj) + if err != nil { + return nil, err + } + c.resourceByType[typ] = r + return r, err +} + +// getObjMeta returns objMeta containing both type and object metadata and state +func (c *clientCache) getObjMeta(obj runtime.Object) (*objMeta, error) { + r, err := c.getResource(obj) + if err != nil { + return nil, err + } + m, err := meta.Accessor(obj) + if err != nil { + return nil, err + } + return &objMeta{resourceMeta: r, Object: m}, err +} + +// resourceMeta caches state for a Kubernetes type. +type resourceMeta struct { + // client is the rest client used to talk to the apiserver + rest.Interface + // gvk is the GroupVersionKind of the resourceMeta + gvk schema.GroupVersionKind + // mapping is the rest mapping + mapping *meta.RESTMapping +} + +// isNamespaced returns true if the type is namespaced +func (r *resourceMeta) isNamespaced() bool { + if r.mapping.Scope.Name() == meta.RESTScopeNameRoot { + return false + } + return true +} + +// resource returns the resource name of the type +func (r *resourceMeta) resource() string { + return r.mapping.Resource.Resource +} + +// objMeta stores type and object information about a Kubernetes type +type objMeta struct { + // resourceMeta contains type information for the object + *resourceMeta + + // Object contains meta data for the object instance + v1.Object +} diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/client/interfaces.go b/vendor/sigs.k8s.io/controller-runtime/pkg/client/interfaces.go new file mode 100644 index 00000000000..36d0fce6208 --- /dev/null +++ b/vendor/sigs.k8s.io/controller-runtime/pkg/client/interfaces.go @@ -0,0 +1,292 @@ +/* +Copyright 2018 The Kubernetes Authors. + +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 client + +import ( + "context" + + "k8s.io/apimachinery/pkg/api/meta" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/fields" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/types" +) + +// ObjectKey identifies a Kubernetes Object. +type ObjectKey = types.NamespacedName + +// ObjectKeyFromObject returns the ObjectKey given a runtime.Object +func ObjectKeyFromObject(obj runtime.Object) (ObjectKey, error) { + accessor, err := meta.Accessor(obj) + if err != nil { + return ObjectKey{}, err + } + return ObjectKey{Namespace: accessor.GetNamespace(), Name: accessor.GetName()}, nil +} + +// TODO(directxman12): is there a sane way to deal with get/delete options? + +// Reader knows how to read and list Kubernetes objects. +type Reader interface { + // Get retrieves an obj for the given object key from the Kubernetes Cluster. + // obj must be a struct pointer so that obj can be updated with the response + // returned by the Server. + Get(ctx context.Context, key ObjectKey, obj runtime.Object) error + + // List retrieves list of objects for a given namespace and list options. On a + // successful call, Items field in the list will be populated with the + // result returned from the server. + List(ctx context.Context, opts *ListOptions, list runtime.Object) error +} + +// Writer knows how to create, delete, and update Kubernetes objects. +type Writer interface { + // Create saves the object obj in the Kubernetes cluster. + Create(ctx context.Context, obj runtime.Object) error + + // Delete deletes the given obj from Kubernetes cluster. + Delete(ctx context.Context, obj runtime.Object, opts ...DeleteOptionFunc) error + + // Update updates the given obj in the Kubernetes cluster. obj must be a + // struct pointer so that obj can be updated with the content returned by the Server. + Update(ctx context.Context, obj runtime.Object) error +} + +// StatusClient knows how to create a client which can update status subresource +// for kubernetes objects. +type StatusClient interface { + Status() StatusWriter +} + +// StatusWriter knows how to update status subresource of a Kubernetes object. +type StatusWriter interface { + // Update updates the fields corresponding to the status subresource for the + // given obj. obj must be a struct pointer so that obj can be updated + // with the content returned by the Server. + Update(ctx context.Context, obj runtime.Object) error +} + +// Client knows how to perform CRUD operations on Kubernetes objects. +type Client interface { + Reader + Writer + StatusClient +} + +// IndexerFunc knows how to take an object and turn it into a series +// of (non-namespaced) keys for that object. +type IndexerFunc func(runtime.Object) []string + +// FieldIndexer knows how to index over a particular "field" such that it +// can later be used by a field selector. +type FieldIndexer interface { + // IndexFields adds an index with the given field name on the given object type + // by using the given function to extract the value for that field. If you want + // compatibility with the Kubernetes API server, only return one key, and only use + // fields that the API server supports. Otherwise, you can return multiple keys, + // and "equality" in the field selector means that at least one key matches the value. + IndexField(obj runtime.Object, field string, extractValue IndexerFunc) error +} + +// DeleteOptions contains options for delete requests. It's generally a subset +// of metav1.DeleteOptions. +type DeleteOptions struct { + // GracePeriodSeconds is the duration in seconds before the object should be + // deleted. Value must be non-negative integer. The value zero indicates + // delete immediately. If this value is nil, the default grace period for the + // specified type will be used. + GracePeriodSeconds *int64 + + // Preconditions must be fulfilled before a deletion is carried out. If not + // possible, a 409 Conflict status will be returned. + Preconditions *metav1.Preconditions + + // PropagationPolicy determined whether and how garbage collection will be + // performed. Either this field or OrphanDependents may be set, but not both. + // The default policy is decided by the existing finalizer set in the + // metadata.finalizers and the resource-specific default policy. + // Acceptable values are: 'Orphan' - orphan the dependents; 'Background' - + // allow the garbage collector to delete the dependents in the background; + // 'Foreground' - a cascading policy that deletes all dependents in the + // foreground. + PropagationPolicy *metav1.DeletionPropagation + + // Raw represents raw DeleteOptions, as passed to the API server. + Raw *metav1.DeleteOptions +} + +// AsDeleteOptions returns these options as a metav1.DeleteOptions. +// This may mutate the Raw field. +func (o *DeleteOptions) AsDeleteOptions() *metav1.DeleteOptions { + + if o == nil { + return &metav1.DeleteOptions{} + } + if o.Raw == nil { + o.Raw = &metav1.DeleteOptions{} + } + + o.Raw.GracePeriodSeconds = o.GracePeriodSeconds + o.Raw.Preconditions = o.Preconditions + o.Raw.PropagationPolicy = o.PropagationPolicy + return o.Raw +} + +// ApplyOptions executes the given DeleteOptionFuncs and returns the mutated +// DeleteOptions. +func (o *DeleteOptions) ApplyOptions(optFuncs []DeleteOptionFunc) *DeleteOptions { + for _, optFunc := range optFuncs { + optFunc(o) + } + return o +} + +// DeleteOptionFunc is a function that mutates a DeleteOptions struct. It implements +// the functional options pattern. See +// https://github.com/tmrts/go-patterns/blob/master/idiom/functional-options.md. +type DeleteOptionFunc func(*DeleteOptions) + +// GracePeriodSeconds is a functional option that sets the GracePeriodSeconds +// field of a DeleteOptions struct. +func GracePeriodSeconds(gp int64) DeleteOptionFunc { + return func(opts *DeleteOptions) { + opts.GracePeriodSeconds = &gp + } +} + +// Preconditions is a functional option that sets the Preconditions field of a +// DeleteOptions struct. +func Preconditions(p *metav1.Preconditions) DeleteOptionFunc { + return func(opts *DeleteOptions) { + opts.Preconditions = p + } +} + +// PropagationPolicy is a functional option that sets the PropagationPolicy +// field of a DeleteOptions struct. +func PropagationPolicy(p metav1.DeletionPropagation) DeleteOptionFunc { + return func(opts *DeleteOptions) { + opts.PropagationPolicy = &p + } +} + +// ListOptions contains options for limitting or filtering results. +// It's generally a subset of metav1.ListOptions, with support for +// pre-parsed selectors (since generally, selectors will be executed +// against the cache). +type ListOptions struct { + // LabelSelector filters results by label. Use SetLabelSelector to + // set from raw string form. + LabelSelector labels.Selector + // FieldSelector filters results by a particular field. In order + // to use this with cache-based implementations, restrict usage to + // a single field-value pair that's been added to the indexers. + FieldSelector fields.Selector + + // Namespace represents the namespace to list for, or empty for + // non-namespaced objects, or to list across all namespaces. + Namespace string + + // Raw represents raw ListOptions, as passed to the API server. Note + // that these may not be respected by all implementations of interface, + // and the LabelSelector and FieldSelector fields are ignored. + Raw *metav1.ListOptions +} + +// SetLabelSelector sets this the label selector of these options +// from a string form of the selector. +func (o *ListOptions) SetLabelSelector(selRaw string) error { + sel, err := labels.Parse(selRaw) + if err != nil { + return err + } + o.LabelSelector = sel + return nil +} + +// SetFieldSelector sets this the label selector of these options +// from a string form of the selector. +func (o *ListOptions) SetFieldSelector(selRaw string) error { + sel, err := fields.ParseSelector(selRaw) + if err != nil { + return err + } + o.FieldSelector = sel + return nil +} + +// AsListOptions returns these options as a flattened metav1.ListOptions. +// This may mutate the Raw field. +func (o *ListOptions) AsListOptions() *metav1.ListOptions { + if o == nil { + return &metav1.ListOptions{} + } + if o.Raw == nil { + o.Raw = &metav1.ListOptions{} + } + if o.LabelSelector != nil { + o.Raw.LabelSelector = o.LabelSelector.String() + } + if o.FieldSelector != nil { + o.Raw.FieldSelector = o.FieldSelector.String() + } + return o.Raw +} + +// MatchingLabels is a convenience function that sets the label selector +// to match the given labels, and then returns the options. +// It mutates the list options. +func (o *ListOptions) MatchingLabels(lbls map[string]string) *ListOptions { + sel := labels.SelectorFromSet(lbls) + o.LabelSelector = sel + return o +} + +// MatchingField is a convenience function that sets the field selector +// to match the given field, and then returns the options. +// It mutates the list options. +func (o *ListOptions) MatchingField(name, val string) *ListOptions { + sel := fields.SelectorFromSet(fields.Set{name: val}) + o.FieldSelector = sel + return o +} + +// InNamespace is a convenience function that sets the namespace, +// and then returns the options. It mutates the list options. +func (o *ListOptions) InNamespace(ns string) *ListOptions { + o.Namespace = ns + return o +} + +// MatchingLabels is a convenience function that constructs list options +// to match the given labels. +func MatchingLabels(lbls map[string]string) *ListOptions { + return (&ListOptions{}).MatchingLabels(lbls) +} + +// MatchingField is a convenience function that constructs list options +// to match the given field. +func MatchingField(name, val string) *ListOptions { + return (&ListOptions{}).MatchingField(name, val) +} + +// InNamespace is a convenience function that constructs list +// options to list in the given namespace. +func InNamespace(ns string) *ListOptions { + return (&ListOptions{}).InNamespace(ns) +} diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/client/split.go b/vendor/sigs.k8s.io/controller-runtime/pkg/client/split.go new file mode 100644 index 00000000000..efcf6d4c315 --- /dev/null +++ b/vendor/sigs.k8s.io/controller-runtime/pkg/client/split.go @@ -0,0 +1,59 @@ +/* +Copyright 2018 The Kubernetes Authors. + +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 client + +import ( + "context" + + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/runtime" +) + +// DelegatingClient forms an interface Client by composing separate +// reader, writer and statusclient interfaces. This way, you can have an Client that +// reads from a cache and writes to the API server. +type DelegatingClient struct { + Reader + Writer + StatusClient +} + +// DelegatingReader forms a interface Reader that will cause Get and List +// requests for unstructured types to use the ClientReader while +// requests for any other type of object with use the CacheReader. +type DelegatingReader struct { + CacheReader Reader + ClientReader Reader +} + +// Get retrieves an obj for a given object key from the Kubernetes Cluster. +func (d *DelegatingReader) Get(ctx context.Context, key ObjectKey, obj runtime.Object) error { + _, isUnstructured := obj.(*unstructured.Unstructured) + if isUnstructured { + return d.ClientReader.Get(ctx, key, obj) + } + return d.CacheReader.Get(ctx, key, obj) +} + +// List retrieves list of objects for a given namespace and list options. +func (d *DelegatingReader) List(ctx context.Context, opts *ListOptions, list runtime.Object) error { + _, isUnstructured := list.(*unstructured.UnstructuredList) + if isUnstructured { + return d.ClientReader.List(ctx, opts, list) + } + return d.CacheReader.List(ctx, opts, list) +} diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/client/typed_client.go b/vendor/sigs.k8s.io/controller-runtime/pkg/client/typed_client.go new file mode 100644 index 00000000000..26cb81d8ba3 --- /dev/null +++ b/vendor/sigs.k8s.io/controller-runtime/pkg/client/typed_client.go @@ -0,0 +1,133 @@ +/* +Copyright 2018 The Kubernetes Authors. + +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 client + +import ( + "context" + + "k8s.io/apimachinery/pkg/runtime" +) + +// client is a client.Client that reads and writes directly from/to an API server. It lazily initializes +// new clients at the time they are used, and caches the client. +type typedClient struct { + cache clientCache + paramCodec runtime.ParameterCodec +} + +// Create implements client.Client +func (c *typedClient) Create(ctx context.Context, obj runtime.Object) error { + o, err := c.cache.getObjMeta(obj) + if err != nil { + return err + } + return o.Post(). + NamespaceIfScoped(o.GetNamespace(), o.isNamespaced()). + Resource(o.resource()). + Body(obj). + Context(ctx). + Do(). + Into(obj) +} + +// Update implements client.Client +func (c *typedClient) Update(ctx context.Context, obj runtime.Object) error { + o, err := c.cache.getObjMeta(obj) + if err != nil { + return err + } + return o.Put(). + NamespaceIfScoped(o.GetNamespace(), o.isNamespaced()). + Resource(o.resource()). + Name(o.GetName()). + Body(obj). + Context(ctx). + Do(). + Into(obj) +} + +// Delete implements client.Client +func (c *typedClient) Delete(ctx context.Context, obj runtime.Object, opts ...DeleteOptionFunc) error { + o, err := c.cache.getObjMeta(obj) + if err != nil { + return err + } + + deleteOpts := DeleteOptions{} + return o.Delete(). + NamespaceIfScoped(o.GetNamespace(), o.isNamespaced()). + Resource(o.resource()). + Name(o.GetName()). + Body(deleteOpts.ApplyOptions(opts).AsDeleteOptions()). + Context(ctx). + Do(). + Error() +} + +// Get implements client.Client +func (c *typedClient) Get(ctx context.Context, key ObjectKey, obj runtime.Object) error { + r, err := c.cache.getResource(obj) + if err != nil { + return err + } + return r.Get(). + NamespaceIfScoped(key.Namespace, r.isNamespaced()). + Resource(r.resource()). + Context(ctx). + Name(key.Name).Do().Into(obj) +} + +// List implements client.Client +func (c *typedClient) List(ctx context.Context, opts *ListOptions, obj runtime.Object) error { + r, err := c.cache.getResource(obj) + if err != nil { + return err + } + namespace := "" + if opts != nil { + namespace = opts.Namespace + } + return r.Get(). + NamespaceIfScoped(namespace, r.isNamespaced()). + Resource(r.resource()). + Body(obj). + VersionedParams(opts.AsListOptions(), c.paramCodec). + Context(ctx). + Do(). + Into(obj) +} + +// UpdateStatus used by StatusWriter to write status. +func (c *typedClient) UpdateStatus(ctx context.Context, obj runtime.Object) error { + o, err := c.cache.getObjMeta(obj) + if err != nil { + return err + } + // TODO(droot): examine the returned error and check if it error needs to be + // wrapped to improve the UX ? + // It will be nice to receive an error saying the object doesn't implement + // status subresource and check CRD definition + return o.Put(). + NamespaceIfScoped(o.GetNamespace(), o.isNamespaced()). + Resource(o.resource()). + Name(o.GetName()). + SubResource("status"). + Body(obj). + Context(ctx). + Do(). + Into(obj) +} diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/client/unstructured_client.go b/vendor/sigs.k8s.io/controller-runtime/pkg/client/unstructured_client.go new file mode 100644 index 00000000000..2ce0b19eb88 --- /dev/null +++ b/vendor/sigs.k8s.io/controller-runtime/pkg/client/unstructured_client.go @@ -0,0 +1,162 @@ +/* +Copyright 2018 The Kubernetes Authors. + +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 client + +import ( + "context" + "fmt" + "strings" + + "k8s.io/apimachinery/pkg/api/meta" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/client-go/dynamic" +) + +// client is a client.Client that reads and writes directly from/to an API server. It lazily initializes +// new clients at the time they are used, and caches the client. +type unstructuredClient struct { + client dynamic.Interface + restMapper meta.RESTMapper +} + +// Create implements client.Client +func (uc *unstructuredClient) Create(_ context.Context, obj runtime.Object) error { + u, ok := obj.(*unstructured.Unstructured) + if !ok { + return fmt.Errorf("unstructured client did not understand object: %T", obj) + } + r, err := uc.getResourceInterface(u.GroupVersionKind(), u.GetNamespace()) + if err != nil { + return err + } + i, err := r.Create(u, metav1.CreateOptions{}) + if err != nil { + return err + } + u.Object = i.Object + return nil +} + +// Update implements client.Client +func (uc *unstructuredClient) Update(_ context.Context, obj runtime.Object) error { + u, ok := obj.(*unstructured.Unstructured) + if !ok { + return fmt.Errorf("unstructured client did not understand object: %T", obj) + } + r, err := uc.getResourceInterface(u.GroupVersionKind(), u.GetNamespace()) + if err != nil { + return err + } + i, err := r.Update(u, metav1.UpdateOptions{}) + if err != nil { + return err + } + u.Object = i.Object + return nil +} + +// Delete implements client.Client +func (uc *unstructuredClient) Delete(_ context.Context, obj runtime.Object, opts ...DeleteOptionFunc) error { + u, ok := obj.(*unstructured.Unstructured) + if !ok { + return fmt.Errorf("unstructured client did not understand object: %T", obj) + } + r, err := uc.getResourceInterface(u.GroupVersionKind(), u.GetNamespace()) + if err != nil { + return err + } + deleteOpts := DeleteOptions{} + err = r.Delete(u.GetName(), deleteOpts.ApplyOptions(opts).AsDeleteOptions()) + return err +} + +// Get implements client.Client +func (uc *unstructuredClient) Get(_ context.Context, key ObjectKey, obj runtime.Object) error { + u, ok := obj.(*unstructured.Unstructured) + if !ok { + return fmt.Errorf("unstructured client did not understand object: %T", obj) + } + r, err := uc.getResourceInterface(u.GroupVersionKind(), key.Namespace) + if err != nil { + return err + } + i, err := r.Get(key.Name, metav1.GetOptions{}) + if err != nil { + return err + } + u.Object = i.Object + return nil +} + +// List implements client.Client +func (uc *unstructuredClient) List(_ context.Context, opts *ListOptions, obj runtime.Object) error { + u, ok := obj.(*unstructured.UnstructuredList) + if !ok { + return fmt.Errorf("unstructured client did not understand object: %T", obj) + } + gvk := u.GroupVersionKind() + if strings.HasSuffix(gvk.Kind, "List") { + gvk.Kind = gvk.Kind[:len(gvk.Kind)-4] + } + namespace := "" + if opts != nil { + namespace = opts.Namespace + } + r, err := uc.getResourceInterface(gvk, namespace) + if err != nil { + return err + } + + i, err := r.List(*opts.AsListOptions()) + if err != nil { + return err + } + u.Items = i.Items + u.Object = i.Object + return nil +} + +func (uc *unstructuredClient) UpdateStatus(_ context.Context, obj runtime.Object) error { + u, ok := obj.(*unstructured.Unstructured) + if !ok { + return fmt.Errorf("unstructured client did not understand object: %T", obj) + } + r, err := uc.getResourceInterface(u.GroupVersionKind(), u.GetNamespace()) + if err != nil { + return err + } + i, err := r.UpdateStatus(u, metav1.UpdateOptions{}) + if err != nil { + return err + } + u.Object = i.Object + return nil +} + +func (uc *unstructuredClient) getResourceInterface(gvk schema.GroupVersionKind, ns string) (dynamic.ResourceInterface, error) { + mapping, err := uc.restMapper.RESTMapping(gvk.GroupKind(), gvk.Version) + if err != nil { + return nil, err + } + if mapping.Scope.Name() == meta.RESTScopeNameRoot { + return uc.client.Resource(mapping.Resource), nil + } + return uc.client.Resource(mapping.Resource).Namespace(ns), nil +}