Updated at Feb 2, 2017

The prototype is open sourced on GitHub.

What is Aliyun?

Aliyun is a cloud service provider rooted in mainland China.

Currently, it provides numerous kinds of cloud service, such as:

  • ECS: Elastic Compute Service
  • RDS: Relational Database Service
  • OSS: Object Storage Service
  • SLB: Server Load Balancer
  • CDN: Content Delivery Network

Motivation

All APIs of Aliyun are based on the HTTP/HTTPS protocol. But handcrafting the query string can be boring and difficult. So you need some libraries to help you get a native, convenient API. Beside that, some visualization, user information management etc., are also part of the SDK’s functionalities.

By developing a SDK in Haskell, I can combine the cloud service into my Haskell-driven application. For the sake of itself, I hope for:

  • Safety and soundness, easy to refactor
  • Generality, easy to extend
  • Less code, easy to read

Hacking

Up to now, I finished some interfacing code with ECS, OSS and RDS services. It took me two days to build everything from scratch to commit ac8f645.

There are mainly two ways of calling:

  • URL parameters
  • HTTP Header

And it requires a lot of

  • Encoding, such as UTF-8, base64, URL encode etc.
  • Canonicalization: uniquely map a structure into string
  • Hashing & Encrypting, mostly using MD5 and HMAC-SHA1

However, beyond that, due to the fact that industry Haskell is basically built on top of a lot of user-contributed packages, so a lot of gluing work are necessary. And again due to the strong typing, so a lot of explicit castings are driving me crazy. Look at this and feel it yourself:

base64 :: [Word8] -> String
base64 = BC.unpack . BB.encode . B.pack

And a lot of packages, for example, the Data.HMAC, is actually type-unsafe. It leaves the typing duty to user, so I have to create Message and Secret wrappers myself. Actually, just due to this fact, I wasted two hours debugging my code and finally spotted that I encrypted the secret with message!

And another bad thing is that, the Network.HTTP is not providing any HTTPS functionality. So you have to use the Network.HTTP.Conduit package. However, a lot of stuff, such as the header format, are not mutually compatible.

Architecture

Currently, its architecture is simple:

Aliyun.Auth gives you safe type Secret, Message and AkId, also re-exports some specific encryption/encoding functions.

Aliyun.API is the general logic on composing a URL. Any query-specific parameters are passed in, so other common parameters can be added here.

Aliyun.Action exposes a typeclass Action, representing a functionality. For example, in Aliyun.RDS, we have RDSAction type, so it can implement the Action typeclass, and other supporting code can be written in a more general style.

Aliyun.Config is about all related user configuration in order to construct API query string.

Aliyun.HTTP is a very hack-ish thing. I mainly re-export the different HTTP/HTTPS simple request APIs.

Finally, Aliyun.ECS, Aliyun.OSS, Aliyun.RDS are some service implementations. It is not a complete implementation, but considerably easier to extend.

Future work

  • Full support for all available APIs. My idea is to parse the official documentation and generate Haskell bindings automatically
  • Better configuration setup. The actual user information can be rather complex, for example, user has several services, different services have different plans, different plans can be in different regions, having different URLs etc.
  • Unify the HTTP interface