-
Notifications
You must be signed in to change notification settings - Fork 0
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
Conversation
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"
…UTSSMAssociation
There was a problem hiding this 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) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
InstanceSSMAssociationHandler
There was a problem hiding this comment.
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) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
InstanceUpdateHandler
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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 { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
SSMAssociationRequest
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
api/handlers_instances.go
Outdated
s.session.ExternalID, | ||
role, | ||
"", | ||
"arn:aws:iam::aws:policy/AmazonSSMReadOnlyAccess", |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
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"`
There was a problem hiding this comment.
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) |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
api/handlers_instances.go
Outdated
account := s.mapAccountNumber(vars["account"]) | ||
instanceId := vars["id"] | ||
|
||
req := &Ec2ImageUpdateRequest{} |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
api/handlers_instances.go
Outdated
account := s.mapAccountNumber(vars["account"]) | ||
instanceId := vars["id"] | ||
|
||
req := &Ec2InstancesAttributeUpdateRequest{} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ec2InstanceUpdateRequest
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
api/handlers_instances.go
Outdated
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)) |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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 | ||
} | ||
|
There was a problem hiding this comment.
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)
There was a problem hiding this comment.
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) |
There was a problem hiding this comment.
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 { |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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 { |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
tzTimeFormat
should be fine
api/handlers_instances.go
Outdated
@@ -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)) |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
No description provided.