-
Notifications
You must be signed in to change notification settings - Fork 925
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
Driver Implementation for the cloudscale.ch API #951
Conversation
--------------------- | ||
|
||
Simply visit `<https://control.cloudscale.ch/user/api-tokens>`_ and start | ||
having fun! |
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 you want to reword this. ;)
libcloud.DriverType.COMPUTE.CLOUDSCALE | ||
) | ||
|
||
driver = cls('3pjzjh3h3rfynqa4iemvtvc33pyfzss2') |
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'd store the token string in a variable token
to clarify what that string is. Or maybe add a comment.
''' | ||
return self._list_resources('/v1/images', self._to_image) | ||
|
||
def create_node(self, name, size, image, location=None, ex_create_attr={}): |
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.
What do you think about accepting the arguments in ex_create_attr
directly separate parameters instead? Compare with CloudStackNodeDriver.create_node()
: https://github.com/apache/libcloud/blob/trunk/libcloud/compute/drivers/cloudstack.py#L1528
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 would argue that some other drivers (e.g. digitalocean) are doing it the same way. Prefixing everything with ex_
feels clunky and having a dictionary makes it easy to be "future-compatible".
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'm ok with this, as long as the attributes are documented somewhere. You could also name the main ones and just merge them into the dictionary.
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 documented in docs/compute/drivers/cloudscale.rst
. Should I add it to the docstring?
- ``use_private_network``: ``boolean`` Attaching/Detaching the private network interface. | ||
- ``use_ipv6``: ``boolean`` Enabling/Disabling IPv6. | ||
- ``anti_affinity_with``: ``string``; Pass the UUID of another server. | ||
- ``user_data``: ``string``; Cloud-init configuration (cloud-config). Provide YAML. |
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'd use Python's standard names for the types here (i.e. bool
, str
, …).
Also, is there a standard convention for how to format such lists with type information, e.g. here the format <id> (<type>) – <description>
is used.
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 adapted that. I think it's nicer.
|
||
class CloudscaleConnection(ConnectionKey): | ||
""" | ||
Connection class for the Vultr driver. |
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.
You're not covering your tracks very well. :P
@@ -0,0 +1 @@ | |||
[{"slug":"ubuntu-16.10","name":"Ubuntu 16.10 (2016-10-17)","operating_system": "Ubuntu"}] |
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.
Why no pretty printing here? :(
If you want to keep it on a single line, if suggest adding spaces after :
and ,
.
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 actually removed the pretty printing because other drivers also don't use it (and this one is pretty short).
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.
Then at least remove that space after the last :
. :P
@Feuermurmel I have improved pretty much all the documentation that you complained about, except for the two places where I've commented. |
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 this is a great contribution, I had a concern about the way errors are handled if there is a cleaner way of achieving this?
|
||
|
||
class CloudscaleResponse(JsonResponse): | ||
valid_response_codes = [httplib.OK, httplib.ACCEPTED, httplib.CREATED, |
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.
this is overridden just because of the addition of httplib.NO_CONTENT
?
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, I don't see us overriding anything here, valid_response_codes
does not exist in JsonResponse
or Response
.
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.
correct, never mind https://github.com/apache/libcloud/blob/trunk/libcloud/common/base.py#L216
# but that doesn't really matter. It's nicer if the error is just | ||
# one error (because it's a Python API and there's only one | ||
# exception. | ||
return next(iter(body.values())) |
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.
wah, ok what's this about? This is unusual!
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.
It means "take the first/any element of the collection". There's no nicer way to express it if your collection is not a list.
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.
If it means that we change the base method then I'd be happier with that, you should have a bit more control over the meta in the exception. Assuming that the other errors in the response could provide context to the user about what they did wrong they shouldn't have to use a packet sniffer to get that data https://github.com/apache/libcloud/blob/trunk/libcloud/common/base.py#L178-L180
Change that to an instance method (self.exception_from_message
), which calls the top level function.
Override that method in your own class to raise a new exception class, inheriting from LibcloudException, adding a field for the list of errors. update __str__
with the first error, or a list joined with commas?
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'll do this another time. 👍 merging
''' | ||
return self._list_resources('/v1/images', self._to_image) | ||
|
||
def create_node(self, name, size, image, location=None, ex_create_attr={}): |
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'm ok with this, as long as the attributes are documented somewhere. You could also name the main ones and just merge them into the dictionary.
) | ||
return response.status == httplib.OK | ||
|
||
def _list_resources(self, url, tranform_func): |
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.
Nice pattern 👍
|
||
- ``driver.list_sizes()`` | ||
- ``driver.list_images()`` | ||
- ``driver.list_sizes()`` |
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.
It seems like this is a duplicate.
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, how is it a duplicate? Do you mean the autoclass listing?
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.
list_sizes
is twice
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.
Oh, how did I not see that after you pointed it out. Thank you!
It should be list_nodes
. I have changed it.
@tonybaloney How would you like me to modify error handling? Or what do you think is not clean enough? |
@davidhalter if you haven't already, I need you to sign the ASF ICLA (an agreement for individual contributors) https://libcloud.readthedocs.io/en/latest/development.html#contributing-bigger-changes |
I have signed it and I have also gotten confirmation:
|
merged. thanks @davidhalter @pquentin @Feuermurmel and @href for getting this over the line and thanks for contributing to the project. New drivers can take a little bit of time but it's important to get some consistency. |
@tonybaloney Thanks for reacting so quickly. Wish I could do that on my open source projects as well :) Keep up the good work! |
@tonybaloney The documentation doesn't seem like it's up-to-date. Did we break the builds with this PR? (AFAIK I was able to build the docs with this commit). |
@davidhalter It looks like that for some reasons docs builds haven't been automatically triggered for a while now. I manually triggered it for latest for now and I will look what is going on with automatically triggered builds. |
The manually triggered build has finished and the provider is listed there now - https://libcloud.readthedocs.io/en/latest/compute/supported_providers.html I believe there were two issues.
I believe both issues should be fixed now, but need to wait for the Travis and RTD build to finish :) |
It looks like automatic docs build triggering is working again - https://travis-ci.org/apache/libcloud/jobs/188560819#L855 and provider matrix is also back again https://libcloud.readthedocs.io/en/latest/supported_providers.html#provider-matrix :) /cc @tonybaloney |
@Kami Thanks! Is there any way to PR for the website as well? I wasn't able to find a repository of it. |
A Driver Implementation for the cloudscale.ch API
Description
It's pretty simple, I have added a new driver for the cloudscale.ch API (https://www.cloudscale.ch/en/api/v1). The cloudscale.ch API is very simple and doesn't offer a lot more than what libcloud's
compute
module by default offers. I have also tried to communicate this in the documentation.Status
The code feels mostly like it's done and ready for review. It passes 2.7, 3.3, 3.4, 3.5, lint and pylint. I have looked at other drivers in libcloud and tried to copy how they document/test. I haven't added tons of tests, but comparably to others the driver is also smaller and therefore the amount of tests seem to align.
Just let me know what you think. Happy to improve my code!
Checklist (tick everything that applies)