Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for updating instances #27

Merged
merged 12 commits into from
May 19, 2022
Merged

Support for updating instances #27

merged 12 commits into from
May 19, 2022

Conversation

nvnyale
Copy link
Contributor

@nvnyale nvnyale commented May 9, 2022

No description provided.

nvnyale added 3 commits May 7, 2022 12:24
PUT "/{account}/instances/{id}"
PUT "/{account}/instances/{id}/power"
PUT "/{account}/instances/{id}/ssm/association"
PUT "/{account}/instances/{id}/tags"
PUT "/{account}/instances/{id}/attribute"
@nvnyale nvnyale requested a review from tenyo May 10, 2022 15:19
Copy link
Contributor

@tenyo tenyo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall looks good, I just think we should combine some of those routes to use the same InstanceUpdateHandler.

api/routes.go Outdated
api.HandleFunc("/{account}/instances/{id}/ssm/association", s.ProxyRequestHandler).Methods(http.MethodPut)
api.HandleFunc("/{account}/instances/{id}/tags", s.ProxyRequestHandler).Methods(http.MethodPut)
api.HandleFunc("/{account}/instances/{id}/attribute", s.ProxyRequestHandler).Methods(http.MethodPut)
api.HandleFunc("/{account}/instances/{id}/ssm/association", s.CreateAssociationHandler).Methods(http.MethodPut)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

InstanceSSMAssociationHandler

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

api/routes.go Outdated
@@ -65,12 +65,12 @@ func (s *server) routes() {
api.HandleFunc("/{account}/images", s.ProxyRequestHandler).Methods(http.MethodPost)

api.HandleFunc("/{account}/images/{id}/tags", s.ImageUpdateHandler).Methods(http.MethodPut)
api.HandleFunc("/{account}/instances/{id}", s.ProxyRequestHandler).Methods(http.MethodPut)
api.HandleFunc("/{account}/instances/{id}", s.InstanceIDHandler).Methods(http.MethodPut)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

InstanceUpdateHandler

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For ID's route, handler is not implemented, so I didn't generalize this handler.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok, then let's just call it NotImplementedHandler, so it's clearer and it can be used by other routes that are not implemented

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Renamed.

api/types.go Outdated
@@ -728,6 +732,10 @@ type Ec2InstanceStateChangeRequest struct {
State string
}

type SSMCreateRequest struct {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SSMAssociationRequest

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

s.session.ExternalID,
role,
"",
"arn:aws:iam::aws:policy/AmazonSSMReadOnlyAccess",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmm, does this work? you're not passing any IAM policy besides the read-only access

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a good point, I missed it. I am not familiar with the AWS policies and can you please help me to choose the correct policy.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this case you're working with SSM (Systems Manager) so you can take a look here first: https://docs.aws.amazon.com/systems-manager/latest/userguide/security_iam_service-with-iam.html
Try to find which IAM permissions are required to do the work (in this case CreateAssociation).
For example, here you can see all the different IAM permissions: https://aws.permissions.cloud/iam/ssm
In some cases it may be a bit of trial-and-error until you get all the permissions right, but in this case should be pretty straightforward.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

api/types.go Outdated
@@ -728,6 +732,10 @@ type Ec2InstanceStateChangeRequest struct {
State string
}

type SSMCreateRequest struct {
Document string
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you need `json:"document"`

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

api/routes.go Outdated
api.HandleFunc("/{account}/instances/{id}/attribute", s.ProxyRequestHandler).Methods(http.MethodPut)
api.HandleFunc("/{account}/instances/{id}/ssm/association", s.CreateAssociationHandler).Methods(http.MethodPut)
api.HandleFunc("/{account}/instances/{id}/tags", s.InstancesTagsHandler).Methods(http.MethodPut)
api.HandleFunc("/{account}/instances/{id}/attribute", s.InstancesAttributeHandler).Methods(http.MethodPut)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's try to use the same InstanceUpdateHandler for both tags and attributes (and {id})
In that handler you can check the request and if they passed Tags - update the tags, if they passed InstanceType - update the attributes.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have generalized the Instance Tags and Instance Attributes update handlers, with the assumption that the input payload doesn't have both (tags & attributes) sent at the same time. Let me know if there are any changes required.

account := s.mapAccountNumber(vars["account"])
instanceId := vars["id"]

req := &Ec2ImageUpdateRequest{}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When we move this to the InstanceUpdateHandler, this can become just Ec2InstanceUpdateRequest

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

account := s.mapAccountNumber(vars["account"])
instanceId := vars["id"]

req := &Ec2InstancesAttributeUpdateRequest{}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ec2InstanceUpdateRequest

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

if len(req.Tags) == 0 {
handleError(w, apierror.New(apierror.ErrBadRequest, "missing required field: tags", nil))
if len(req.Tags) == 0 && len(req.InstanceType) == 0 {
handleError(w, apierror.New(apierror.ErrBadRequest, "missing required fields", nil))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

missing required fields: tags or instance_type

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

if len(req.Tags) == 0 {
handleError(w, apierror.New(apierror.ErrBadRequest, "missing required field: tags", nil))
if len(req.Tags) == 0 && len(req.InstanceType) == 0 {
handleError(w, apierror.New(apierror.ErrBadRequest, "missing required fields", nil))
return
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you should create and use a separate instanceUpdatePolicy here (since you need more permissions than just tags)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

updated code.

api/routes.go Outdated
@@ -65,12 +65,12 @@ func (s *server) routes() {
api.HandleFunc("/{account}/images", s.ProxyRequestHandler).Methods(http.MethodPost)

api.HandleFunc("/{account}/images/{id}/tags", s.ImageUpdateHandler).Methods(http.MethodPut)
api.HandleFunc("/{account}/instances/{id}", s.ProxyRequestHandler).Methods(http.MethodPut)
api.HandleFunc("/{account}/instances/{id}", s.InstanceIDHandler).Methods(http.MethodPut)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok, then let's just call it NotImplementedHandler, so it's clearer and it can be used by other routes that are not implemented

if err := json.NewDecoder(r.Body).Decode(req); err != nil {
msg := fmt.Sprintf("cannot decode body into update image input: %s", err)
handleError(w, apierror.New(apierror.ErrBadRequest, msg, err))
return
}

if len(req.Tags) == 0 {
handleError(w, apierror.New(apierror.ErrBadRequest, "missing required field: tags", nil))
if len(req.Tags) == 0 && len(req.InstanceType) == 0 {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we should also check that both are not > 0 and return an error only one of these is expected: tags or instance_type

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

api/types.go Outdated
@@ -693,27 +693,37 @@ type AssociationTarget struct {

func toSSMAssociationDescription(rawDesc *ssm.DescribeAssociationOutput) *AssociationDescription {
const dateLayout = "2006-01-02 15:04:05 +0000"
formatDate := func(t *time.Time) string {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We already have timeFormat and tzTimeFormat functions defined, you should use one of those

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In ruby response, for GET SSMAssociation, we are getting the time format as above ex: "2022-03-14 16:19:34 +0000". Please let me know if you want me to use timeFormat or tzTimeFormat

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tzTimeFormat should be fine

@@ -498,7 +498,7 @@ func (s *server) InstanceSSMAssociationHandler(w http.ResponseWriter, r *http.Re
return
}

handleResponseOk(w, struct{ AssociationId string }{AssociationId: *out.AssociationDescription.AssociationId})
handleResponseOk(w, aws.StringValue(out.AssociationDescription.AssociationId))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think your function should only return the AssociationId in out so we don't need to parse this in the handler.
That's what we've done for all the other functions.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

@nvnyale nvnyale merged commit 1a3d9d3 into master May 19, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants