-
Notifications
You must be signed in to change notification settings - Fork 113
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #38 from yeya24/add-federaterole
Support updating federated role
- Loading branch information
Showing
11 changed files
with
862 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,197 @@ | ||
package federatedrole | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
"io" | ||
"net/http" | ||
"os" | ||
"path/filepath" | ||
|
||
awsv1alpha1 "github.com/openshift/aws-account-operator/pkg/apis/aws/v1alpha1" | ||
"github.com/pkg/errors" | ||
"github.com/spf13/cobra" | ||
|
||
"k8s.io/apimachinery/pkg/util/yaml" | ||
"k8s.io/cli-runtime/pkg/genericclioptions" | ||
cmdutil "k8s.io/kubectl/pkg/cmd/util" | ||
"sigs.k8s.io/controller-runtime/pkg/client" | ||
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" | ||
|
||
"github.com/openshift/osd-utils-cli/pkg/k8s" | ||
awsprovider "github.com/openshift/osd-utils-cli/pkg/provider/aws" | ||
) | ||
|
||
const ( | ||
awsAccountIDLabel = "awsAccountID" | ||
uidLabel = "uid" | ||
) | ||
|
||
// newCmdApply implements the apply command to apply federated role CR | ||
func newCmdApply(streams genericclioptions.IOStreams, flags *genericclioptions.ConfigFlags) *cobra.Command { | ||
ops := newApplyOptions(streams, flags) | ||
applyCmd := &cobra.Command{ | ||
Use: "apply", | ||
Short: "Apply federated role CR", | ||
Args: cobra.NoArgs, | ||
DisableAutoGenTag: true, | ||
Run: func(cmd *cobra.Command, args []string) { | ||
cmdutil.CheckErr(ops.complete(cmd, args)) | ||
cmdutil.CheckErr(ops.run()) | ||
}, | ||
} | ||
|
||
applyCmd.Flags().StringVarP(&ops.url, "url", "u", "", "The URL of federated role yaml file") | ||
applyCmd.Flags().StringVarP(&ops.file, "file", "f", "", "The path of federated role yaml file") | ||
applyCmd.Flags().BoolVarP(&ops.verbose, "verbose", "v", false, "Verbose output") | ||
|
||
return applyCmd | ||
} | ||
|
||
// applyOptions defines the struct for running list account command | ||
type applyOptions struct { | ||
url string | ||
file string | ||
|
||
verbose bool | ||
|
||
flags *genericclioptions.ConfigFlags | ||
genericclioptions.IOStreams | ||
kubeCli client.Client | ||
} | ||
|
||
func newApplyOptions(streams genericclioptions.IOStreams, flags *genericclioptions.ConfigFlags) *applyOptions { | ||
return &applyOptions{ | ||
flags: flags, | ||
IOStreams: streams, | ||
} | ||
} | ||
|
||
func (o *applyOptions) complete(cmd *cobra.Command, _ []string) error { | ||
if o.file == "" && o.url == "" { | ||
return cmdutil.UsageErrorf(cmd, "Flags file and url cannot be empty at the same time") | ||
} | ||
|
||
if o.file != "" && o.url != "" { | ||
return cmdutil.UsageErrorf(cmd, "Flags file and url cannot be set at the same time") | ||
} | ||
|
||
var err error | ||
o.kubeCli, err = k8s.NewClient(o.flags) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func (o *applyOptions) run() error { | ||
ctx := context.TODO() | ||
|
||
var ( | ||
input io.Reader | ||
accountID string | ||
uid string | ||
ok bool | ||
) | ||
if o.url != "" { | ||
resp, err := http.Get(o.url) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
if resp.StatusCode/100 != 2 { | ||
return errors.New(fmt.Sprintf("Failed to GET %s, status code %d", o.url, resp.StatusCode)) | ||
} | ||
|
||
defer resp.Body.Close() | ||
input = resp.Body | ||
|
||
} else { | ||
path, err := filepath.Abs(o.file) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
file, err := os.Open(path) | ||
if err != nil { | ||
return err | ||
} | ||
input = file | ||
} | ||
|
||
var federatedRole awsv1alpha1.AWSFederatedRole | ||
d := yaml.NewYAMLOrJSONDecoder(input, 4096) | ||
if err := d.Decode(&federatedRole); err != nil { | ||
return err | ||
} | ||
|
||
// apply federated role CR yaml | ||
desired := federatedRole.DeepCopy() | ||
if _, err := controllerutil.CreateOrUpdate(ctx, o.kubeCli, &federatedRole, func() error { | ||
federatedRole.Spec = desired.Spec | ||
return nil | ||
}); err != nil { | ||
return err | ||
} | ||
|
||
var federatedAccountAccesses awsv1alpha1.AWSFederatedAccountAccessList | ||
if err := o.kubeCli.List(ctx, &federatedAccountAccesses, &client.ListOptions{}); err != nil { | ||
return err | ||
} | ||
|
||
if len(federatedAccountAccesses.Items) == 0 { | ||
fmt.Fprintln(o.Out, "Cannot find associated AWS federated account accesses") | ||
return nil | ||
} | ||
|
||
awsClients := make(map[string]awsprovider.Client, 0) | ||
|
||
// find all associated federated account access CR and update them | ||
for _, federatedAccount := range federatedAccountAccesses.Items { | ||
if federatedAccount.Spec.AWSFederatedRole.Namespace == federatedRole.Namespace && | ||
federatedAccount.Spec.AWSFederatedRole.Name == federatedRole.Name { | ||
if accountID, ok = federatedAccount.Labels[awsAccountIDLabel]; !ok { | ||
return errors.New(fmt.Sprintf( | ||
"Unable to get AWS AccountID label for AWS federated account access CR %s/%s", | ||
federatedAccount.Namespace, federatedAccount.Name)) | ||
} | ||
|
||
if uid, ok = federatedAccount.Labels[uidLabel]; !ok { | ||
return errors.New(fmt.Sprintf( | ||
"Unable to get UID label for AWS federated account access CR %s/%s", | ||
federatedAccount.Namespace, federatedAccount.Name)) | ||
} | ||
|
||
var awsClient awsprovider.Client | ||
if awsClient, ok = awsClients[federatedAccount.Namespace]; !ok { | ||
creds, err := k8s.GetAWSAccountCredentials(ctx, o.kubeCli, | ||
federatedAccount.Spec.AWSCustomerCredentialSecret.Namespace, | ||
federatedAccount.Spec.AWSCustomerCredentialSecret.Name) | ||
if err != nil { | ||
return errors.Wrap(err, fmt.Sprintf( | ||
"Failed to get AWS credentials for AWS federated account access CR %s/%s", | ||
federatedAccount.Namespace, federatedAccount.Name)) | ||
} | ||
|
||
awsClient, err = awsprovider.NewAwsClientWithInput(creds) | ||
if err != nil { | ||
return errors.Wrap(err, fmt.Sprintf( | ||
"Failed to create AWS Setup Client for AWS federated account access CR %s/%s", | ||
federatedAccount.Namespace, federatedAccount.Name)) | ||
} | ||
awsClients[federatedAccount.Namespace] = awsClient | ||
} | ||
|
||
fmt.Fprintln(o.Out, fmt.Sprintf("Updating IAM policy for AWS federated account access CR %s/%s", | ||
federatedAccount.Namespace, federatedAccount.Name)) | ||
|
||
if err := awsprovider.RefreshIAMPolicy(awsClient, &federatedRole, accountID, uid); err != nil { | ||
return errors.Wrap(err, fmt.Sprintf("Failed to apply IAM policy for AWS federated account access CR %s/%s", | ||
federatedAccount.Namespace, federatedAccount.Name)) | ||
} | ||
} | ||
} | ||
|
||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
package federatedrole | ||
|
||
import ( | ||
"github.com/spf13/cobra" | ||
"k8s.io/cli-runtime/pkg/genericclioptions" | ||
) | ||
|
||
// NewCmdFederatedRole implements the basic federated role command | ||
func NewCmdFederatedRole(streams genericclioptions.IOStreams, flags *genericclioptions.ConfigFlags) *cobra.Command { | ||
getCmd := &cobra.Command{ | ||
Use: "federatedrole", | ||
Short: "federated role related commands", | ||
Args: cobra.NoArgs, | ||
DisableAutoGenTag: true, | ||
Run: help, | ||
} | ||
|
||
getCmd.AddCommand(newCmdApply(streams, flags)) | ||
|
||
return getCmd | ||
} | ||
|
||
func help(cmd *cobra.Command, _ []string) { | ||
cmd.Help() | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
## osdctl federatedrole | ||
|
||
federated role related commands | ||
|
||
### Synopsis | ||
|
||
federated role related commands | ||
|
||
``` | ||
osdctl federatedrole [flags] | ||
``` | ||
|
||
### Options | ||
|
||
``` | ||
-h, --help help for federatedrole | ||
``` | ||
|
||
### Options inherited from parent commands | ||
|
||
``` | ||
--cluster string The name of the kubeconfig cluster to use | ||
--context string The name of the kubeconfig context to use | ||
--insecure-skip-tls-verify If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure | ||
--kubeconfig string Path to the kubeconfig file to use for CLI requests. | ||
--request-timeout string The length of time to wait before giving up on a single server request. Non-zero values should contain a corresponding time unit (e.g. 1s, 2m, 3h). A value of zero means don't timeout requests. (default "0") | ||
-s, --server string The address and port of the Kubernetes API server | ||
``` | ||
|
||
### SEE ALSO | ||
|
||
* [osdctl](osdctl.md) - OSD CLI | ||
* [osdctl federatedrole apply](osdctl_federatedrole_apply.md) - Apply federated role CR | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
## osdctl federatedrole apply | ||
|
||
Apply federated role CR | ||
|
||
### Synopsis | ||
|
||
Apply federated role CR | ||
|
||
``` | ||
osdctl federatedrole apply [flags] | ||
``` | ||
|
||
### Options | ||
|
||
``` | ||
-f, --file string The path of federated role yaml file | ||
-h, --help help for apply | ||
-u, --url string The URL of federated role yaml file | ||
-v, --verbose Verbose output | ||
``` | ||
|
||
### Options inherited from parent commands | ||
|
||
``` | ||
--cluster string The name of the kubeconfig cluster to use | ||
--context string The name of the kubeconfig context to use | ||
--insecure-skip-tls-verify If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure | ||
--kubeconfig string Path to the kubeconfig file to use for CLI requests. | ||
--request-timeout string The length of time to wait before giving up on a single server request. Non-zero values should contain a corresponding time unit (e.g. 1s, 2m, 3h). A value of zero means don't timeout requests. (default "0") | ||
-s, --server string The address and port of the Kubernetes API server | ||
``` | ||
|
||
### SEE ALSO | ||
|
||
* [osdctl federatedrole](osdctl_federatedrole.md) - federated role related commands | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.