func GetExistingRole(reqLogger logr.Logger, byocRole string, byocAWSClient awsclient.Client) (*iam.GetRoleOutput, error) {
	existingRole, err := byocAWSClient.GetRole(&iam.GetRoleInput{
		RoleName: aws.String(byocRole),
	})
	if err != nil {
		if aerr, ok := err.(awserr.Error); ok {
			switch aerr.Code() {
			case iam.ErrCodeNoSuchEntityException:
				reqLogger.Info(fmt.Sprintf("%s role does not yet exist", byocRole))
				return &iam.GetRoleOutput{}, nil
			case iam.ErrCodeServiceFailureException:
				reqLogger.Error(
					aerr,
					fmt.Sprintf("AWS Internal Server Error (%s) checking for %s role existence: %s", aerr.Code(), byocRole, aerr.Message()),
				)
				return &iam.GetRoleOutput{}, err
			default:
				reqLogger.Error(
					aerr,
					fmt.Sprintf("Unknown error (%s) checking for %s role existence: %s", aerr.Code(), byocRole, aerr.Message()),
				)
				return &iam.GetRoleOutput{}, err
			}
		} else {
			return &iam.GetRoleOutput{}, err
		}
	}
	return existingRole, err
}
GetExistingRole checks to see if a given role exists in the AWS account already.  If it does not, we return an empty response and nil for an error.  If it does, we return the existing role.  Otherwise, we return any error we get.
package account
import (
	"context"
	"encoding/json"
	"fmt"
	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/awserr"
	"github.com/aws/aws-sdk-go/service/iam"
	"github.com/aws/aws-sdk-go/service/sts"
	"github.com/go-logr/logr"
	corev1 "k8s.io/api/core/v1"
	"k8s.io/apimachinery/pkg/types"
	"sigs.k8s.io/controller-runtime/pkg/reconcile"
	awsv1alpha1 "github.com/openshift/aws-account-operator/pkg/apis/aws/v1alpha1"
	"github.com/openshift/aws-account-operator/pkg/awsclient"
	"github.com/openshift/aws-account-operator/pkg/controller/utils"
)
func newBYOCAccount(currentAcctInstance *awsv1alpha1.Account) bool {
	if currentAcctInstance.IsBYOC() {
		if !currentAcctInstance.HasState() || !currentAcctInstance.IsClaimed() {
			return true
		}
	}
	return false
}
func claimBYOCAccount(r *ReconcileAccount, reqLogger logr.Logger, currentAcctInstance *awsv1alpha1.Account) error {
	if !currentAcctInstance.IsClaimed() {
		reqLogger.Info("Marking BYOC account claimed")
		currentAcctInstance.Status.Claimed = true
		return r.statusUpdate(currentAcctInstance)
	}
	return nil
}
func (r *ReconcileAccount) initializeNewCCSAccount(reqLogger logr.Logger, account *awsv1alpha1.Account) (reconcile.Result, error) {
	accountClaim, acctClaimErr := r.getAccountClaim(account)
	if acctClaimErr != nil {
		if accountClaim != nil {
			utils.SetAccountClaimStatus(
				accountClaim,
				"Failed to get AccountClaim for CSS account",
				"FailedRetrievingAccountClaim",
				awsv1alpha1.ClientError,
				awsv1alpha1.ClaimStatusError,
			)
			err := r.Client.Status().Update(context.TODO(), accountClaim)
			if err != nil {
				reqLogger.Error(err, "failed to update accountclaim status")
			}
		} else {
			reqLogger.Error(acctClaimErr, "accountclaim is nil")
		}
		return reconcile.Result{}, acctClaimErr
	}
	validateErr := accountClaim.Validate()
	if validateErr != nil {
		errReason := validateErr.Error()
		utils.SetAccountClaimStatus(
			accountClaim,
			"Invalid AccountClaim",
			errReason,
			awsv1alpha1.InvalidAccountClaim,
			awsv1alpha1.ClaimStatusError,
		)
		err := r.Client.Status().Update(context.TODO(), accountClaim)
		if err != nil {
			reqLogger.Error(err, "Failed to Update AccountClaim Status")
		}
		return reconcile.Result{}, validateErr
	}
	claimErr := claimBYOCAccount(r, reqLogger, account)
	if claimErr != nil {
		reqLogger.Error(claimErr, "Could not claim BYOC Account")
		claimStatusErr := r.setAccountClaimError(reqLogger, account, claimErr.Error())
		if claimStatusErr != nil {
			reqLogger.Error(claimStatusErr, "failed setting accountClaim error state")
		}
		return reconcile.Result{}, claimErr
	}
	return reconcile.Result{}, nil
}
func (r *ReconcileAccount) GetSREAccessARN(reqLogger logr.Logger, arnName string) (string, error) {
	configMap := &corev1.ConfigMap{}
	err := r.Client.Get(
		context.TODO(),
		types.NamespacedName{
			Namespace: awsv1alpha1.AccountCrNamespace,
			Name:      awsv1alpha1.DefaultConfigMap,
		},
		configMap,
	)
	if err != nil {
		reqLogger.Error(err, "There was an error getting the ConfigMap to get the SRE Access Role")
		return "", err
	}
	SREAccessARN := configMap.Data[arnName]
	if SREAccessARN == "" {
		reqLogger.Error(awsv1alpha1.ErrInvalidConfigMap, "configmap key missing", "keyName", arnName)
		return "", awsv1alpha1.ErrInvalidConfigMap
	}
	return SREAccessARN, nil
}
func (r *ReconcileAccount) createBYOCAdminAccessRole(reqLogger logr.Logger, awsSetupClient awsclient.Client, byocAWSClient awsclient.Client, policyArn string, instanceID string, tags []*iam.Tag) (roleID string, err error) {
	getUserOutput, err := awsSetupClient.GetUser(&iam.GetUserInput{})
	if err != nil {
		reqLogger.Error(err, "Failed to get non-BYOC IAM User info")
		return roleID, err
	}
	principalARN := *getUserOutput.User.Arn
	SREAccessARN, err := r.GetSREAccessARN(reqLogger, awsv1alpha1.CCSAccessARN)
	if err != nil {
		return roleID, err
	}
	accessArnList := []string{principalARN, SREAccessARN}
	byocInstanceIDRole := fmt.Sprintf("%s-%s", byocRole, instanceID)
	existingRole, err := GetExistingRole(reqLogger, byocInstanceIDRole, byocAWSClient)
	if err != nil {
		return roleID, err
	}
	if (*existingRole != iam.GetRoleOutput{}) {
		reqLogger.Info(fmt.Sprintf("Found pre-existing role: %s", byocInstanceIDRole))
		err := DeleteBYOCAdminAccessRole(reqLogger, byocAWSClient, byocInstanceIDRole)
		if err != nil {
			return roleID, err
		}
	}
	roleID, err = CreateRole(reqLogger, byocInstanceIDRole, accessArnList, byocAWSClient, tags)
	if err != nil {
		return roleID, err
	}
	reqLogger.Info(fmt.Sprintf("New RoleID created: %s", roleID))
	err = attachAndEnsureRolePolicies(reqLogger, byocAWSClient, byocInstanceIDRole, policyArn)
	return roleID, err
}
func DeleteBYOCAdminAccessRole(reqLogger logr.Logger, byocAWSClient awsclient.Client, byocInstanceIDRole string) (err error) {
	policyList, err := GetAttachedPolicies(reqLogger, byocInstanceIDRole, byocAWSClient)
	if err != nil {
		return err
	}
	for _, policy := range policyList.AttachedPolicies {
		err := DetachPolicyFromRole(reqLogger, policy, byocInstanceIDRole, byocAWSClient)
		if err != nil {
			return err
		}
	}
	return DeleteRole(reqLogger, byocInstanceIDRole, byocAWSClient)
}
func CreateRole(reqLogger logr.Logger, byocRole string, accessArnList []string, byocAWSClient awsclient.Client, tags []*iam.Tag) (string, error) {
	assumeRolePolicyDoc := struct {
		Version   string
		Statement []awsStatement
	}{
		Version: "2012-10-17",
		Statement: []awsStatement{{
			Effect: "Allow",
			Action: []string{"sts:AssumeRole"},
			Principal: &awsv1alpha1.Principal{
				AWS: accessArnList,
			},
		}},
	}
	jsonAssumeRolePolicyDoc, err := json.Marshal(&assumeRolePolicyDoc)
	if err != nil {
		return "", err
	}
	reqLogger.Info(fmt.Sprintf("Creating role: %s", byocRole))
	createRoleOutput, err := byocAWSClient.CreateRole(&iam.CreateRoleInput{
		Tags:                     tags,
		RoleName:                 aws.String(byocRole),
		Description:              aws.String("AdminAccess for BYOC"),
		AssumeRolePolicyDocument: aws.String(string(jsonAssumeRolePolicyDoc)),
	})
	if err != nil {
		return "", err
	}
	return *createRoleOutput.Role.RoleId, nil
}