Alex,
This commit in my fork of libcloud:
http://github.com/jedsmith/libcloud/commit/d9c9b513ffeaf44b550e662538ac012a3f7de0f5
...completes the entirety of Linode support in libcloud. It is tested
and works. This takes a different approach from Ryan Tucker -- which I
believe is what you had the issue with -- and implements Linode support
in a manner similar to your other providers (with no external dependencies).
We're extremely interested in getting on board with you, and changing
all those red Nos on your homepage to at least three Yeses. Does this
diff fit better with your vision for libcloud? Please let me know if it
does not, and I will work with you to get it in.
I'm also ready to commit create support when you decide upon an API. We
are more than willing to assist with that process.
Yours,
Jed Smith
Systems Developer
Linode, LLC
jsm...@linode.com
+1 (609) 593-7103 x1209
PGP: 0xA6611ED6
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.9 (Darwin)
iEYEARECAAYFAkp5FVMACgkQgNwvNaZhHtYubwCffoa1iT690jvstW5UuBADNK0k
q5UAni/v+nHROpCHq9aTx7qtLFGhhxRR
=7IQk
-----END PGP SIGNATURE-----
Jed, looking better! I'm going to push some interfaces ASAP, and
you'll probably need to take another look at writing a driver.
Take a lot at this slicehost implementation ... the new stuff will
look a lot more like this:
> I'm also ready to commit create support when you decide upon an API. We
> are more than willing to assist with that process.
... in the mean time, this would be awesome. Right now we're trying to
define the API -- the hard part about this is we need to send provider
specific details. Here is one approach, what do you think?
Essentially we are assuming that each provider needs a size and an
image in order to boot. Of course there are more details to this, but
this is the bare minimum.
Any feedback here would be awesome.
-Alex
--
co-founder, cloudkick.com
twitter.com/cloudkick
541 231 0624
This is really, really strange code. Why are the private methods of the
node driver (i.e., to_nodes) now mandated to be public in INodeDriver?
For that matter, why are functions like that -- which /work/ on response
objects -- members of INodeDriver and not IResponse? What the heck is
the purpose of IResponse::parse_error, and why does it fall through to
returning the body if there is no error...?
This design is probably the strangest object-oriented structure I have
ever seen in my programming career. I'm sorry, but it is. This is the
entirely wrong direction to pull libcloud in, and you'll suffer for it.
The assumption that every API works over HTTP is problematic. While all
the providers you work with today do, what's to stop a VPS company from
offering an entirely different protocol for transfer? You are then
looking at reimplementing your entire library to provide support for
them. Instead, you really need to let drivers abstract away their API
details from the rest of the library.
I would love to implement Linode support for this, but I am having
extreme difficulty grokking the new libcloud. In my opinion, in
LinodeNodeDriver I should be completely isolating all the details of my
API away from the rest of libcloud...Connection details, Response
details...why is this now no longer constrained to my driver? Why is
the rest of the library getting involved in API details -- something I
thought libcloud was designed to avoid?
This change has shot the complexity of libcloud through the roof, and
made it extremely difficult for outsiders to contribute code. Why have
we overcomplicated libcloud to fifteen separate interfaces?
I'd like to see something like this --
libcloud/
__init__.py
libcloud.py General package functionality
Node.py The Node object
Credential.py A general Credential object
IDriver.py The interface for drivers
drivers/
__init__.py Package-o-drivers
Linode.py Linode's IDriver
Slicehost.py Slicehost's IDriver
Amazon.py Amazon's EC2 IDriver and EU IDriver
import libcloud
lcreds = libcloud.Credential()
screds = libcloud.Credential()
lcreds["key"] = "abc123"
screds["key"] = "abc123"
screds["http"] = ("user, "pass")
linode = libcloud.driver("Linode", lcreds)
slhost = libcloud.driver("Slicehost", screds)
nodes = libcloud.enumerate([linode, slhost])
for node in nodes:
node.reboot()
lplan = {
"Plan": 360,
"OS": "Debian",
"PrivateIP": True,
"Linode:Datacenter": "Fremont",
"Linode:BillingCycle": 12
}
splan = {
"Plan": 256,
"OS": "Debian",
"PrivateIP": True,
"Slicehost:UniqueFeat": 5,
"Slicehost:ETC": True
}
lnode = linode.create(lplan)
snode = slhost.create(splan)
lnode.boot()
snode.boot()
I was hoping simplicity like this is the direction you were heading for,
and I'm really disappointed that it's not.
Obviously it'd be a conflict of interest for me to rewrite libcloud for
you, but ... Alex ... I need your help here. Are you strongly committed
to this direction? There are a million better ways to do what you're
trying to do, while minimizing overhead for both you and the providers
you're trying to support.
I'll try to implement Linode's support into your current schema, but I
really hope I'm not wasting effort again.
I agree, some of the things, specifically to_nodes likely should not
be in the INodeDriver, but almost all of the rest of them really do
work well, at least that is my opinion after seeing most of it for the
first time last night while implementing the Rackspace driver.
> For that matter, why are functions like that -- which /work/ on response
> objects -- members of INodeDriver and not IResponse? What the heck is
> the purpose of IResponse::parse_error, and why does it fall through to
> returning the body if there is no error...?
> This design is probably the strangest object-oriented structure I have
> ever seen in my programming career. I'm sorry, but it is. This is the
> entirely wrong direction to pull libcloud in, and you'll suffer for it.
>
> The assumption that every API works over HTTP is problematic.
I disagree, the API doesn't really mandate HTTP -- much more about
requests / response patterns, which even if your transport was
something else, is a pretty consistent programming pattern for
communication over the internet.
> While all
> the providers you work with today do, what's to stop a VPS company from
> offering an entirely different protocol for transfer? You are then
> looking at reimplementing your entire library to provide support for
> them. Instead, you really need to let drivers abstract away their API
> details from the rest of the library.
I disagree, that road takes you to just wrapping random APIs, and the
consistency between the different providers drops considerably, while
with this approach it is very easy to write full test cases for all
providers, and to drive them completely offline without credentials,
which if it was not done this way, would need to be implemented
completely from scratch for every provider.
> I would love to implement Linode support for this, but I am having
> extreme difficulty grokking the new libcloud. In my opinion, in
> LinodeNodeDriver I should be completely isolating all the details of my
> API away from the rest of libcloud...Connection details, Response
> details...why is this now no longer constrained to my driver? Why is
> the rest of the library getting involved in API details -- something I
> thought libcloud was designed to avoid?
>
> This change has shot the complexity of libcloud through the roof, and
> made it extremely difficult for outsiders to contribute code. Why have
> we overcomplicated libcloud to fifteen separate interfaces?
I don't agree with your conclusions, I hadn't done much in libcloud
before last night, and it only took me like 2 hours to knock out
Rackspace providers using the new interfaces, and they have full test
cases. Moving to a less centralized API, I doubt I could of gotten it
done nearly as quickly.
Thanks,
Paul
base.ConnectionKey disagrees with you. In fact, most of base.py does.
> I disagree, that road takes you to just wrapping random APIs, and the
> consistency between the different providers drops considerably,
How is that any different from what libcloud is doing today? A standard
is trying to be forged on how to communicate between providers --
wrapping each provider's API is a big part of that. That's essentially
what the design of libcloud mandates.
> I don't agree with your conclusions, I hadn't done much in libcloud
> before last night, and it only took me like 2 hours to knock out
> Rackspace providers using the new interfaces, and they have full test
> cases.
You had Slicehost to build upon. I banged out my first Linode plugin in
a shade under 3 hours, and that included familiarizing myself with the
code. That did not include test cases. With this new design,
everything is completely different, and I have been studying how to
tackle this all day.
There are larger strategic decisions at play in the design of our
plugin, as we've never forced a datacenter upon our customers before
(and we're weighing how best to do that). The new create_node system
does not give us any capability whatsoever to specify that.
Regards,
-Jed
For that matter, why are functions like that -- which /work/ on response objects -- members of INodeDriver and not IResponse?
What the heck is the purpose of IResponse::parse_error, and why does it fall through to returning the body if there is no error...?
The assumption that every API works over HTTP is problematic. While all the providers you work with today do, what's to stop a VPS company from offering an entirely different protocol for transfer? You are then looking at reimplementing your entire library to provide support for them.
...why is this now no longer constrained to my driver?
There are a million better ways to do what you're trying to do, while minimizing overhead for both you and the providers you're trying to support.
base.ConnectionKey disagrees with you. In fact, most of base.py does.
A standard is trying to be forged on how to communicate between providers -- wrapping each provider's API is a big part of that
With this new design, everything is completely different, and I have been studying how to tackle this all day.
The new create_node system does not give us any capability whatsoever to specify that.
Based on this feedback, I've removed to_nodes/to_images/to_sizes from
the interface. You guys are right, it does not really make sense
there.
I've also merged in tdavis's create_node kwargs commit -- I was
actually thinking about doing the exact same thing, and he beat me to
it!
>> This design is probably the strangest object-oriented structure I have
>> ever seen in my programming career. I'm sorry, but it is.
... and I'm sorry you're having a hard time with it. It's really good
to know, because linode is one of the first providers that has stepped
up with development resources to help be part of libcloud. It's
important to the project that you guys can figure it out! Like I
mentioned in my other email, my next top priority is writing a drivers
writers guide. Maybe wait for that to be complete, then would to be
willing to give it another shot? I think it will help a bunch. Another
option, if it would be helpful, is I would be willing to write the
base driver (or maybe someone else?) and let you take over
maintainer-ship. Not ideal, but would help move things along!
Like others have mentioned, the architecture is meant to remove
complexity, add consistency, and make things maintainable. I really
think it does satisfy those goals.
Thanks again for your feedback!
-Alex
Not if the driver tests itself. Why does the global library need to
know about my connection details in order to test it? Why can't I
provide a test framework and cases, using 'unittest' as the case may be,
that you then call from whatever code you like?
The fact that you've reimplemented all sorts of HTTP craziness -- and
then excuse that by saying "we need it to unit test you," is pure
hogwash and you know it. What sort of Wild West are you referring to?
That a driver knows how it works and provides a consistent interface to
the client code calling it?
Heavens, the thought of that.
> Libcloud needs to maintain drivers for myriad providers,
No, it does not. Linode has made a commitment -- to Alex Polvi -- to
maintain our driver. The only drivers you need to maintain are the ones
you write; Slicehost is really getting a free ride here. We will own
it, and you don't have to get your panties in a bunch maintaining
something we throw at you. That's what having git and github and e-mail
and mailing lists is all about.
Us. Working with you.
> When Linode updates their API to
> support some new feature or changes the name of some parameter or whatever
> the case, I know almost exactly where to go to fix that issue and (first)
> where to go to write a new failing test for it...
We'd update the libcloud support as soon as we change something. That's
part of us officially saying "we support libcloud," linking to libcloud
in our API documentation...and that's part of my job description. Work
with you on this.
I must say, though, I'm getting less motivated as I communicate more
with the people supposedly in charge.
> Your destroy_node() blocks for up to 3 minutes then just gives up.
> If anything, this is a failing on our part to not be strict enough -- we
> don't even demand that methods respond timely with a suitable status (such
> as "pending" -- to check again later)!
You don't have any sort of standard whatsoever. Or documentation for
what things do. This is completely undocumented library that seems to
think rewriting itself every now and then is A Good Move and then yells
at providers who try to bow before its every whim.
> This may be a semantic misunderstanding, but it seems like you want to wrap
> existing Python APIs with more Python to arrive at a unified API, which is
> synonymous with jamming whatever-sided peg you write into our square hole.
I do? That patch was rejected, so I supplied a new one that didn't have
any external dependencies at all, save for simplejson in < Python 2.6.
I reimplemented a lot of the work in our Python bindings, which I
expected is what Alex wanted, and completely took our prewritten Linode
Python bindings out of the picture.
I felt bad enough snubbing the fine gentlemen who have put weeks of
testing and work and documentation into those bindings, as they are
customers and good friends of ours, but I felt it was important to
demonstrate to the libcloud steering folks that we are committed to
offering official Linode support.
It's pretty obvious you -- and I mean only you, Tim -- don't want that
from us, though.
> With this
> solution, you can even use dictionaries to pass arguments... without that
> superfluous and odd "Provider:arg" notation.
The idea there was that you wouldn't be changing ABI every time you want
to provide a new feature. I provided Provider:blah so that you could
define what is standard, what won't change...and then providers are free
to add things to that.
Every provider must implement "image", "size", etc...but for those
drivers who have differing implementations than the standard, a
guaranteed way to not collide with other drivers is set in stone. By
the people who are supposed to be setting things in stone.
It's a move toward standardization, which I got the impression was a
main interest of libcloud. Apparently not?
> Thank you for the criticism, even if it was less-than constructive. And
> sorry for breaking your career-long streak of idyllic object-orientation.
Can't separate criticism of the work from criticism of yourself?
Personal attacks against those attempting to improve your product -- who
are interested in helping you and providing what Linode support we can
-- is a good way for all of us providers to lose complete interest in
your product here and leave you to implement it.
I must say that all of us in the Linode community who read your message
were quite surprised by your response, and you've gotten our attention.
This is a dealbreaker for us, and I'm glad I waited for Alex to respond
to my message before pushing send, because I was ready to drop the
"remove our trademarks from everything" stanza.
Hesitantly yours,
-Jed
Linode has made a commitment -- to Alex Polvi -- to maintain our driver.
The fact that you've reimplemented all sorts of HTTP craziness
We'd update the libcloud support as soon as we change something. That's part of us officially saying "we support libcloud," linking to libcloud in our API documentation...
It's pretty obvious you -- and I mean only you, Tim -- don't want that from us, though.
Every provider must implement "image", "size", etc...but for those
drivers who have differing implementations than the standard, a
guaranteed way to not collide with other drivers is set in stone.
Can't separate criticism of the work from criticism of yourself?