Skip to content

Add python client for FM API#153

Merged
thibaudio merged 38 commits intomasterfrom
task/fm-api
Sep 28, 2021
Merged

Add python client for FM API#153
thibaudio merged 38 commits intomasterfrom
task/fm-api

Conversation

@thibaudio
Copy link
Contributor

@thibaudio thibaudio commented Jun 3, 2021

[ch63940]

@thibaudio thibaudio self-assigned this Jun 3, 2021
@thibaudio thibaudio marked this pull request as ready for review June 3, 2021 15:54
@thibaudio thibaudio requested review from apichery, cstenac and duckie June 3, 2021 15:54
@mhoarau mhoarau added this to the 9.0.5 milestone Jul 19, 2021
@shortcut-integration
Copy link

This pull request has been linked to Clubhouse Story #67241: [DCS-FM] Enrich the python client for the FM APIs.

@shortcut-integration
Copy link

@mhoarau mhoarau modified the milestones: 9.0.5, 10.0 Aug 27, 2021
Copy link
Contributor

@FChataigner FChataigner left a comment

Choose a reason for hiding this comment

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

  • the create_xxx() calls are unusable, there are way too many args, and depending on the cloud only half of them are relevant. A new new_xxx() would be better, like the new_recipe() in the DSS api.
  • the FMCloudCredentials doesn't have any helper to get/set fields. Simple operations like setting the license or changing the credentials of the tenant are hard to do
  • cloud tags getting/setting isn't exposed
  • missing __init__.py in the fm module
  • the get_things() (plural) methods should be list_things() instead
  • no way to get the default vpc/subnet when creating networks, or to leave the values empty and let the backend fill them with the defaults
  • no helper on instance templates, not even to add setup actions (so the part to add setup actions isn't discoverable)
  • not all the setup actions have their wrapper
  • the instance has no helper to get/set fields, and should definitely have different classes depending on the cloud
  • no api to make snapshots of instances (but to be fair the call isn't in the backend either)


def get_cloud_credentials(self):
"""
Get Cloud Credential
Copy link
Contributor

Choose a reason for hiding this comment

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

pluralize credential ?

class FMClient(object):
"""Entry point for the FM API client"""

def __init__(self, host, api_key_id, api_key_secret, tenant_id, extra_headers = None):
Copy link
Contributor

Choose a reason for hiding this comment

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

the tenant_id could have a default value main since that's what MONOTENANT setups have

@thibaudio
Copy link
Contributor Author

I've updated the PR, but left the snapshots and getting the default vpc/subnet when creating networks out of the scope because the public api is lacking for now.

Copy link
Contributor

@FChataigner FChataigner left a comment

Choose a reason for hiding this comment

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

  • not too fond of the methods set_...() that do a save() internally. I'd rather have the method return self so that you can chain a save() if you want
  • no way to guess the image id for creation

self.api_key_id = api_key_id
self.api_key_secret = api_key_secret
self.host = host
self.__tenant_id = tenant_id
Copy link
Contributor

Choose a reason for hiding this comment

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

why the __ ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

An old habit, __ for private variables vs _ for protected variables.
I can update it to a single underscore if you prefer to

creds = self._perform_tenant_json("GET", "/cloud-credentials")
return FMCloudCredentials(self, creds)

def get_cloud_tags(self, tenant_id):
Copy link
Contributor

Choose a reason for hiding this comment

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

why pass another tenant_id here? and not the FMClient's one?

self.cloud_credentials["awsCMKId"] = cmk_key_id
self.save()

def set_static_license(self, license_file=None, license_string=None):
Copy link
Contributor

Choose a reason for hiding this comment

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

license_file is ambiguous. Use license_file_path instead, or do a type check to assess whether the object is a file-like or not

raise Exception("Key already exists")
self.cloud_tags[key] = value

def update_tag(self, key, new_key=None, new_value=None):
Copy link
Contributor

Choose a reason for hiding this comment

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

I'd move the "key renaming" part to another method, call the method set_tag() and not complain if the tag doesn't already exist

)


class FMCloudTags(object):
Copy link
Contributor

Choose a reason for hiding this comment

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

helpers for getting/setting the tags seem a bit overkill. A property to get the tag dict and let the user update it would suffice

self.data["awsAutoCreateSecurityGroups"] = True
return self

def with_aws_security_groups(self, aws_security_groups):
Copy link
Contributor

Choose a reason for hiding this comment

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

maybe a signature with_aws_security_groups(self, *aws_security_groups): would be friendlier

self.data["setupActions"] = setup_actions
return self

def with_license(self, license):
Copy link
Contributor

Choose a reason for hiding this comment

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

missing docstring

Copy link
Contributor

@FChataigner FChataigner left a comment

Choose a reason for hiding this comment

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

LGTM

self.host = host
if cloud not in ["AWS", "Azure"]:
raise ValueError("cloud should be either \"AWS\" or \"Azure\"")
self.cloud = cloud
Copy link
Contributor

Choose a reason for hiding this comment

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

Careful, I seem to remember that AZURE should be in capital here. Can you check ?

"""
self.data["cloudInstanceType"] = cloud_instance_type

def set_data_volume_options(self, data_volume_type=None, data_volume_size=None, data_volume_size_max=None, data_volume_IOPS=None, data_volume_encryption=None, data_volume_encryption_key=None):
Copy link
Contributor

Choose a reason for hiding this comment

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

Is it usable like this for both Azure and AWS, or should a different call be devised ?

@thibaudio thibaudio merged commit e98a709 into master Sep 28, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants

Comments