Git Product home page Git Product logo

rack's People

Contributors

annegentle avatar carolynvs avatar dolph avatar ebeeson avatar flazz avatar hdansou avatar jnoller avatar jrperritt avatar kenperkins avatar lvh avatar meker12 avatar pratikmallya avatar rgbkrk avatar robb-romans avatar smashwilson avatar stephenbrown2 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

rack's Issues

Replace ref with ID.

We have an inconsistency in naming, in that we force users to use --image-ref (previously --imageRef) when we call it an ID in the table:

$ rack servers image list
ID                  Name                                                Status  MinDisk MinRAM
c199db85-c6f9-4284-b9ec-16327ee2fc84    OnMetal - Ubuntu 14.04 LTS (Trusty Tahr)                            ACTIVE  20  512
41e85e59-dea0-410f-a5f6-0ca92c3b3322    OnMetal - CoreOS (Stable)                                   ACTIVE  20  512

and in the get:

$ rack servers image get --id c199db85-c6f9-4284-b9ec-16327ee2fc84
PROPERTYVALUE
ID  c199db85-c6f9-4284-b9ec-16327ee2fc84
Name    OnMetal - Ubuntu 14.04 LTS (Trusty Tahr)
Status  ACTIVE
Progress100
MinDisk 20
MinRAM  512
Created 2015-06-16T03:02:41Z
Updated 2015-06-16T14:33:18Z

Should contradictory flags work or error?

Given the following call:

rack servers instances delete --id 12345 --name foo

What should happen?

Options

  1. Delete based on provided id
  2. Delete based on provided name
  3. Delete based on provided name and id
  4. Error with a useful error message

Thoughts?

Need contributor guide

How does someone add a new service? How do we make this self-service for command additions, features? How much is upstream gophercloud?

providing multiple id or name values

Should this be possible (providing multiple id values to the id flag) ?:
rack servers get --id 12345,5678,12395

Should this be possible (providing multiple id values to a new ids flag) ?:
rack servers get --ids 12345,5678,12395

Or should multiple values of anything have to be piped in on STDIN?

The question arises because the logic for handling the piping of multiple values necessitates looping over multiple values. Processing the requests for multiple values from STDIN is logically very similar to the above commands. The question is do we want to offer that to users and, if so, via which format.

tabular format output

I'm not sure there's a way to generalize the tabular output for the different commands. Tables are tricky because they have different headers, different value types, sometimes we'll want a nested value, etc. We'll be able to extract the shell of the table, but the headers and values may have to be command-specific.

Download semantics for Files

Currently, Swift is the only API that when given a GET request, I.e. /mycontainer/myfile.txt it returns the contents of the file, not the metadata.

Should we follow this discrepancy in the CLI? or should we provide consistency.

For example:

rack files object get --container mycontainer --file myfile.txt could return the metadata and
rack files object download --container mycontainer --file myfile.txt would then return the contents?

Pros: Consistent calling convention across all services.
Cons: Most likely use of files will involve getting the file, not the metadata, leading to more typing in the default case.

Thoughts?

command format

Currently, the format is:
<cliName> <service> <subservice> <action> <flags>
Example: rackcli compute servers list --name server1

Personally, I prefer being explicit like above. However, I know some people prefer terse commands:

<cliName> <subservice> <action> <flags>
Example: rackcli servers list --name server1

Though it's true that in the above example removing the service leaves no ambiguity, there are services like load balancers where you'd have rackcli members list <lbID>. It's not obvious that the command is for listing members of a load balancer and though we could have something like rackcli lb-members list <lbID>, that seems to lack consistency.

With bash completion for commands (and in time, flags), I don't think being explicit is much of an inconvenience, but I'd like to hear what others think.

Do not use spaces in JSON keys

I think we should seriously consider not using spaces in JSON keys. When people are parsing/selecting on JSON keys, any spaces in the key can require annoying escaping. It becomes a papercut.

For example, if you were to try to get the private IP address of 2 servers that are named the same ("rum") using jq.

$ rack --json servers instance list | jq -r '.[] | select(.Name == "rum").Private IPv4'
error: syntax error, unexpected IDENT, expecting $end
.[] | select(.Name == "rum").Private IPv4                                     1 compile error

$ rack --json servers instance list | jq -r '.[] | select(.Name == "rum").Private\ IPv4'
error: syntax error, unexpected INVALID_CHARACTER, expecting $end
.[] | select(.Name == "rum").Private\ IPv4                                    1 compile error

I'm sure there's some escaping I can do to fix this or use some other tool that maybe handles spaces in keys better but it feels like there will always be some amount of having to work around spaces in key names.

Errors should exit with non zero exit code

For example, if I run this command with invalid credentials, it won't show anything, and will run grep because the previous command exited with 0.

/data/src/rack [design] $ rack servers image list | grep ubuntu

Improve the output message when no config/flags/env variables specified

Currently if I don't use a profile or export env variables, we get a generic error:

"PROPERTYVALUE
error Error creating ProviderClient: You must supply a Username in your AuthOptions."

I think at a minimum the error should be more friendly. In the bigger picture, this ties into whether a "default' profile (and/or the only defined profile if there is one) should be consumed by default when a profile isn't specified. It feels a little weird to use configure to make a config file, but then have to specify it all of the time with the --profile flag if it's the only one you're using. We could either hint in the configure process about using Default, or make it dummy proof by automatically consuming the profile if there is only a single profile saved. Actually both are probably good ideas. (Says the guy who suggested them.)

cloud compute

servers:

  • create
  • get
  • update
  • delete
  • list
  • reboot
  • rebuild
  • resize

flavors:

  • get
  • list

images:

  • get
  • list

keypairs:

  • create
  • get
  • list
  • delete

Command flavor get is missing extra_specs property

One important feature from the Nova CLI, used in PerfKitBenchmarker, is the ability to view the extra_specs from a flavor. This property lists number_of_data_disks included, the class of the flavor, etc.

e.g.

$ nova flavor-show io1-15
+-----------------------------------+---------------------------------------------------------------------------------------------------+
| Property                          | Value                                                                                             |
+-----------------------------------+---------------------------------------------------------------------------------------------------+
| OS-FLV-EXT-DATA:ephemeral         | 150                                                                                               |
| OS-FLV-WITH-EXT-SPECS:extra_specs | {"number_of_data_disks": "1", "class": "io1", "disk_io_index": "40", "policy_class": "io_flavor"} |
| disk                              | 40                                                                                                |
| extra_specs                       | {"number_of_data_disks": "1", "class": "io1", "disk_io_index": "40", "policy_class": "io_flavor"} |
| id                                | io1-15                                                                                            |
| name                              | 15 GB I/O v1                                                                                      |
| ram                               | 15360                                                                                             |
| rxtx_factor                       | 1250.0                                                                                            |
| swap                              |                                                                                                   |
| vcpus                             | 4                                                                                                 |
+-----------------------------------+---------------------------------------------------------------------------------------------------+

The rack CLI as of today, doesn't output this data, neither in the table format nor the json format outputs.

$ rack servers flavor get io1-15 --json
{"ID":"io1-15","Disk":40,"RAM":15360,"Name":"15 GB I/O v1","RxTxFactor":1250,"Swap":0,"VCPUs":4}
$ rack servers flavor get io1-15
PROPERTY        VALUE
ID              io1-15
Name            15 GB I/O v1
Disk            40
RAM             15360
RxTxFactor      1250
Swap            0
VCPUs           4

One proposal, is to include the extra_specs on the JSON output as a nested JSON object, something like:

{
    "ID": "io1-15",
    "Disk": 40,
    "RAM": 15360,
    "Name": "15 GB I/O v1",
    "RxTxFactor": 1250,
    "Swap": 0,
    "VCPUs": 4,
    "ExtraSpecs": {
        "number_of_data_disks": "1",
        "class": "io1",
        "disk_io_index": "40", 
        "policy_class": "io_flavor"
     }
}

and for table output, perhaps unpack the values, perhaps something like:

PROPERTY        VALUE
ID              io1-15
Name            15 GB I/O v1
Disk            40
RAM             15360
RxTxFactor      1250
Swap            0
VCPUs           4
DataDisks       1
FlavorClass     io1
DiskIOIndex     40 
PolicyClass     io_flavor

or print the JSON object in the table as Nova does (ugly, IMHO), or just simply not show them on the table output.

command aliases

We can provide aliases for commands like ls for list easily enough. The question is if we want to or not. Off the top of my head, the only reason I can think not to would be that when using bash completion, the options available could be large. For example, with aliases, if I typed rackcli compute servers [tab], I might see something like:
mk create update get ls list delete rm
as opposed to
create update get delete list.

Not really a big difference, but users may wonder if there's a difference between, say, ls and list.

Options for consistent approach to piping across services

@jrperritt and I have spent some time ideating on possible strategies for piping. We've got a proposal that we want to try out with everyone.

All commands that allow piped inputs require an explicit --stdin flag.
All commands that allow piped inputs require the caller to explicitly declare what flag is coming in on stdin.

These are all examples where we'd use stdin and a combination of required flags.

cat ids.txt | rack servers instance delete --id --stdin
cat names.txt | rack servers instance delete --name --stdin
cat foo.txt | rack files object create --container mycontainer name foo.txt --contents --stdin
cat ~/.ssh/id_rsa.pub | rack servers keys create --name my-key --public-key --stdin

This approach maintains consistency on functions like upload on keys or object when not using --stdin:

rack files object create --container mycontainer name foo.txt --contents "{\"data\":\"asdf1234\"}"
rack servers keys create --name my-key --public-key ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDOltMjiD35ZteXKGIqkSVDLwnj8n5ZCuoB9Lb7yf23/nCfdUsp1Yw1sjsaWege7969bRWMSx0nB7r9b3rbJAISKfaA4wSSswKI4eaU1fKAN6JSf3kvCI8y12cqC2bsFY0FIakiVrO4gewBzo/JH5f0QqwKIsj2QDg2m8d/jZkHxAcY0jrIa1PHbP51B35KrgV1+ga6kzVmYMqzR/jhURJzRhlb3yn0oLhBOLpC2dsnS2cnTTqsdgaHFV8927bWJA0sYnkv2vJqetqAu/9E4WJZQD36IjWoNKT+4uOIU58PefOhhttUu5NPa0vVruADSlVH+N5ULoIZb0oYqvZjX3Wj [email protected]

To provide the capability to use local files as inputs, but not being piped, we'll use explicit flags to differentiate inline content from local files:

rack files object create --container mycontainer --name foo.txt --file ./foo.txt
rack servers keys create --name my-key --file ~/.ssh/id_rsa.pub

What do ya'll think?

cloud files

containers:

  • create
  • get
  • update
  • delete

objects:

  • create
  • get
  • update
  • delete
  • copy
  • download

Should specifying an invalid profile error?

$ rack --profile does-not-exist servers instance list

This successfully used environment variables I had specified, but it seems contrary to a users expectation.

Thoughts?

Global configuration

Should we be able to specify global defaults in the config?

[Global]
no-cache=true
output=json
debug=true

[Default]
region=iad
username=asdf
api-key=asdf1234

[Test]
region=iad
username=asdf
api-key=asdf1234
output=table

A couple of other thoughts? Should there be a default profile? or should [Global] be able to be overriden?

buffering output

Right now in order to build the output we buffer all of the response payload in memory before outputting to the user. This means for command chains or just lots of output the memory usage could get ghastly for end users and potentially trigger the oom killer on the CLI process itself (or fall into swap). We should consider using a streaming interface for output when possible.

ImageName flag in servers/create ambiguity

Issue to be researched: To date, it has been best practice with Cloud Servers and Cloud Images to not have customers building images by specifying (or fuzzy matching) the image name. Often the images are changed or updated silently, and the name stays the same, which has led to customer confusion and breakage in more than a couple of instances. This might need to be deprecated; should follow up with Ari Liberman, Amanda Clark on Servers/Images team when builds are more widely distributed.

Output current config/options during calls?

Proposal: display some relevant information about your request:

$ rack --region syd servers instance list
Profile: Default        Username: kpraxtest       Region: SYD
ID  Name    Status  Public IPv4 Private IPv4    Image   Flavor

I've found when using lots of profiles and overriding values like region that it gets confusing looking at the output without some feedback of which account I'm actually using.

Maybe this would be best as a config option that could be globally set?

Thoughts?

Semantics

This is pretty awesome. There are some issues I'm taking with the current verbage when reading left to right.

Compute reads as a verb

rack compute flavors

Read directly, I see compute as a verb which is a cognitive disconnect for me.

screenshot 2015-06-07 19 35 06

For non-server sections, it would flow as a resource with server at the front:

rack server flavors list
rack server images list
rack server keypairs list

I'll come back to this. The weird thing is that Rackspace mycloud lists "Servers" under "Servers".

Pipable outputs

It's really great to see that json dump is available. Some kind of planar tab delimited format would be great as well, so that I can chain it together with other *nix commands (or even PowerShell). --plain?

name and id flags

We may want to consider name and id flags for most of the commands (get, update, delete) so that users can provide, for example, a server name rather than a server ID. I'm not sure how people feel about flags vs arguments. With arguments, we'd have something like:

rackcli compute servers get <serverID>

and with flags it'd look like:

rackcli compute servers get --id <serverID>
or
rackcli compute servers get --name <serverName>

Another option is to combine the 2 and assume that if an argument is provided that it's an ID. If not provided, look for flags. I know that using arguments for IDs is customary, but I suspect people more often than not would prefer to provide a name.

setup file

Though the binary will be all-inclusive, bash completion, at least at the moment, has to be activated manually. We may want to write a script that will do it.

Enable people to easily get the specific info they need out of rack

Returning info in a machine readable format is a great start but typically people need to get some very specific piece of information out of a result return by rack.

For example, I need to get the ID of 2 servers that are named the same ("rum").

$ rack --json servers instance list
[
  {
    "Flavor": "general1-1",
    "ID": "2f9657df-68aa-4b26-b779-fb6e3c1fbe52",
    "Image": "055143e8-2da9-439a-a52d-8063f845dec6",
    "Name": "rum",
    "Private IPv4": "10.176.213.132",
    "Public IPv4": "104.249.230.215",
    "Status": "ACTIVE"
  },
  {
    "Flavor": "performance1-8",
    "ID": "c2e791b2-2e1d-4df8-b66c-bcf8c7e8bc96",
    "Image": "c11e2d37-bd93-44f0-b17e-bb87d1022975",
    "Name": "devstack-juno",
    "Private IPv4": "10.229.128.42",
    "Public IPv4": "104.130.165.90",
    "Status": "ACTIVE"
  },
  {
    "Flavor": "general1-2",
    "ID": "3b0c83f9-5cb3-4891-805c-30007a213db3",
    "Image": "6f29d6a6-9972-4ae0-aa80-040fa2d6a9cf",
    "Name": "rum",
    "Private IPv4": "10.172.161.82",
    "Public IPv4": "192.252.228.165",
    "Status": "ACTIVE"
  }
]

One option is to provide the ability to do this within rack itself. It could be done using go templates (ala docker inspect) or some other mechanism.

Another option is to simply document the solution using a favoured third party tool. My preference is jq.

For example.

$ rack --json servers instance list | jq -r '.[] | select(.Name == "rum").ID'
2f9657df-68aa-4b26-b779-fb6e3c1fbe52
3b0c83f9-5cb3-4891-805c-30007a213db3

Output formatting for `image get`

rack servers image get 00341bad-631f-42b6-bc3c-7a861f9cd637:

PROPERTYVALUE
ID      00341bad-631f-42b6-bc3c-7a861f9cd637
Name    CentOS 6 (PVHVM)
Status  ACTIVE
Progress100
MinDisk 20
MinRAM  512
Created 2015-06-01T00:50:37Z
Updated 2015-06-10T21:02:10Z

rack servers instance rebuild broken

11:46:51 (master=) kyle6475@puter ~/go/src/github.com/jrperritt/rack$ go build -o $GOPATH/bin/rack && rack servers instance rebuild
rebuild flag redefined: name
panic: rebuild flag redefined: name

goroutine 1 [running]:
flag.(*FlagSet).Var(0xc20805c5a0, 0x67e010, 0xc20802d8b0, 0x3d5b50, 0x4, 0x45df50, 0x4d)
    /usr/local/Cellar/go/1.4.2/libexec/src/flag/flag.go:679 +0x494
flag.(*FlagSet).StringVar(0xc20805c5a0, 0xc20802d8b0, 0x3d5b50, 0x4, 0x0, 0x0, 0x45df50, 0x4d)
    /usr/local/Cellar/go/1.4.2/libexec/src/flag/flag.go:582 +0xcf
flag.(*FlagSet).String(0xc20805c5a0, 0x3d5b50, 0x4, 0x0, 0x0, 0x45df50, 0x4d, 0x4)
    /usr/local/Cellar/go/1.4.2/libexec/src/flag/flag.go:595 +0x86
github.com/codegangsta/cli.funcยท013(0x3d5b50, 0x4)
    /Users/kyle6475/go/src/github.com/codegangsta/cli/flag.go:348 +0x62
github.com/codegangsta/cli.eachName(0x3d5b50, 0x4, 0xc208092838)
    /Users/kyle6475/go/src/github.com/codegangsta/cli/flag.go:54 +0x11e
github.com/codegangsta/cli.StringFlag.Apply(0x3d5b50, 0x4, 0x0, 0x0, 0x45df50, 0x4d, 0x0, 0x0, 0xc20805c5a0)
    /Users/kyle6475/go/src/github.com/codegangsta/cli/flag.go:349 +0x18f
github.com/codegangsta/cli.(*StringFlag).Apply(0xc20800a6c0, 0xc20805c5a0)
    <autogenerated>:33 +0xaa
github.com/codegangsta/cli.flagSet(0x3d76b0, 0x7, 0xc20807a280, 0xc, 0x14, 0xc20803fa70)
    /Users/kyle6475/go/src/github.com/codegangsta/cli/flag.go:45 +0x133
github.com/codegangsta/cli.Command.Run(0x3d76b0, 0x7, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc208064120, 0x86, 0x4182d0, ...)
    /Users/kyle6475/go/src/github.com/codegangsta/cli/command.go:60 +0x3d2
github.com/codegangsta/cli.(*App).RunAsSubcommand(0xc2080821e0, 0xc2080880e0, 0x0, 0x0)
    /Users/kyle6475/go/src/github.com/codegangsta/cli/app.go:255 +0xc2a
github.com/codegangsta/cli.Command.startApp(0x3ebdb0, 0x8, 0x0, 0x0, 0x0, 0x0, 0x0, 0x42d390, 0x23, 0x0, ...)
    /Users/kyle6475/go/src/github.com/codegangsta/cli/command.go:183 +0x505
github.com/codegangsta/cli.Command.Run(0x3ebdb0, 0x8, 0x0, 0x0, 0x0, 0x0, 0x0, 0x42d390, 0x23, 0x0, ...)
    /Users/kyle6475/go/src/github.com/codegangsta/cli/command.go:45 +0x14ee
github.com/codegangsta/cli.(*App).RunAsSubcommand(0xc2080820f0, 0xc208088000, 0x0, 0x0)
    /Users/kyle6475/go/src/github.com/codegangsta/cli/app.go:255 +0xc2a
github.com/codegangsta/cli.Command.startApp(0x3d80b0, 0x7, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4186d0, 0x1c, 0x0, ...)
    /Users/kyle6475/go/src/github.com/codegangsta/cli/command.go:183 +0x505
github.com/codegangsta/cli.Command.Run(0x3d80b0, 0x7, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4186d0, 0x1c, 0x0, ...)
    /Users/kyle6475/go/src/github.com/codegangsta/cli/command.go:45 +0x14ee
github.com/codegangsta/cli.(*App).Run(0xc208082000, 0xc20800a000, 0x4, 0x4, 0x0, 0x0)
    /Users/kyle6475/go/src/github.com/codegangsta/cli/app.go:158 +0xd0c
main.main()
    /Users/kyle6475/go/src/github.com/jrperritt/rack/main.go:23 +0x16c

goroutine 2 [runnable]:
runtime.forcegchelper()
    /usr/local/Cellar/go/1.4.2/libexec/src/runtime/proc.go:90
runtime.goexit()
    /usr/local/Cellar/go/1.4.2/libexec/src/runtime/asm_amd64.s:2232 +0x1

goroutine 3 [runnable]:
runtime.bgsweep()
    /usr/local/Cellar/go/1.4.2/libexec/src/runtime/mgc0.go:82
runtime.goexit()
    /usr/local/Cellar/go/1.4.2/libexec/src/runtime/asm_amd64.s:2232 +0x1

goroutine 4 [runnable]:
runtime.runfinq()
    /usr/local/Cellar/go/1.4.2/libexec/src/runtime/malloc.go:712
runtime.goexit()
    /usr/local/Cellar/go/1.4.2/libexec/src/runtime/asm_amd64.s:2232 +0x1

Typo suggestions

Not all systems have bash (e.g. Windows) and not everyone uses bash completion. One helpful thing a lot of client bindings do is provide suggestions. Example for us:

$ rack server instance list
rack: 'server' is not a rack command. Did you mean "rack servers instance list"?

paginate long output

Assuming users could get LOTS of results back from a given call, do we add a --paginate or default to pagination and offer a --no-paginate?

`go get` with repo name change

Make sure go get github.com/jrperritt/rack works across operating systems. It seems to work on Linux, but Maverick may be having issues with the repo name change.

different authentication methods

Methods to support:

  • environment variables
  • command-line parameters
  • config/ini file
  • keyring

Also, token caching:

  • caching the auth token to prevent re-authing for every command

create error types

We should create error types for the errors that can be encountered. It'll reduce lines of code and make it easier for writing unit tests.

global flags

I want to open this up to discussion as well. There are some flags that every command can provide (such as output format and auth credentials. Currently, those flags exist with all the others in a command (namely, anywhere after the last subcommand). I did it this way originally so that users wouldn't have to know exactly where to put certain flags within the command, but I can understand how some may like the idea of global flags.

rack configure

rack configure would provide an interactive environment from the command-line that walks a user through creating authentication credentials.

Feature request: Pretty print JSON output

if I run:

rack servers image list --json

I get:

[{"Created":"2015-06-11T14:57:28Z","ID":"41e85e59-dea0-410f-a5f6-0ca92c3b3322","MinDisk":20,"MinRAM":512,"Name":"OnMetal - CoreOS (Stable)","Progress":100,"Status":"ACTIVE","Updated":"2015-06-11T17:33:54Z"},{"Created":"2015-06-11T14:51:59Z","ID":"cfb643d5-f48d-4988-9ca8-8689c1fc877b","MinDisk":20,"MinRAM":512,"Name":"CoreOS (Stable)","Progress":100,"Status":"ACTIVE","Updated":"2015-06-11T17:23:35Z"},{"Created":"2015-06-11T14:50:04Z","ID":"359123c7-3610-499c-9e7d-3d8ba4b38856","MinDisk":20,"MinRAM":512,"Name":"OnMetal - CoreOS (Beta)","Progress":100,"Status":"ACTIVE","Updated":"2015-06-11T17:29:12Z"},{"Created":"2015-06-11T14:44:39Z","ID":"de7ec65d-51c6-4c4f-b47a-72ec9806bcb1","MinDisk":20,"MinRAM":512,"Name":"CoreOS (Beta)","Progress":100,"Status":"ACTIVE","Updated":"2015-06-11T17:18:52Z"},{"Created":"2015-06-09T12:42:22Z","ID":"58daf745-3146-45fb-b6b1-938aa8240eaa","MinDisk":20,"MinRAM":512,"Name":"OnMetal - Ubuntu 15.04 (Vivid Vervet)","Progress":100,"Status":"ACTIVE","Updated":"2015-06-10T22:44:54Z"},{"Created":"2015-06-05T22:26:38Z","ID":"03f6b840-7d5e-4c31-b961-afb55dd4e598","MinDisk":20,"MinRAM":512,"Name":"OnMetal - CentOS 6","Progress":100,"Status":"ACTIVE","Updated":"2015-06-10T21:55:30Z"},{"Created":"2015-06-05T13:43:10Z","ID":"a3e7066e-18fa-4cdd-bc53-7eb9f90e66a7","MinDisk":20,"MinRAM":512,"Name":"Fedora 22 (PVHVM)","Progress":100,"Status":"ACTIVE","Updated":"2015-06-10T21:39:55Z"},{"Created":"2015-06-04T14:50:02Z","ID":"24971b77-0192-46b6-bfe7-5b51d1f5713d","MinDisk":20,"MinRAM":512,"Name":"OnMetal - CoreOS (Alpha)","Progress":100,"Status":"ACTIVE","Updated":"2015-06-04T19:41:58Z"},{"Created":"2015-06-04T14:44:43Z","ID":"587ee022-8dfe-43e8-ad8b-b4efb1fc1d71","MinDisk":20,"MinRAM":512,"Name":"CoreOS (Alpha)","Progress":100,"Status":"ACTIVE","Updated":"2015-06-04T19:33:11Z"},{"Created":"2015-06-04T09:00:36Z","ID":"2b0ebb8f-c3fd-4677-8abe-583fae74778a","MinDisk":40,"MinRAM":2048,"Name":"Windows Server 2012 + SQL Server 2012 SP1 Web","Progress":100,"Status":"ACTIVE","Updated":"2015-06-10T18:20:20Z"},{"Created":"2015-06-03T20:27:35Z","ID":"4b4beb50-fea5-43b1-9609-deda8cf8aae2","MinDisk":20,"MinRAM":512,"Name":"OnMetal - Ubuntu 12.04 LTS (Precise Pangolin)","Progress":100,"Status":"ACTIVE","Updated":"2015-06-10T22:34:24Z"},{"Created":"2015-06-03T14:14:20Z","ID":"4d6707f0-abed-4a25-b900-47ebaed69f24","MinDisk":40,"MinRAM":2048,"Name":"Windows Server 2012 + SQL Server 2012 SP1 Standard","Progress":100,"Status":"ACTIVE","Updated":"2015-06-10T18:18:57Z"},{"Created":"2015-06-01T19:14:08Z","ID":"a0642156-1491-48e3-95f1-27a0873bd5a5","MinDisk":20,"MinRAM":512,"Name":"Arch 2015.6 (PVHVM)","Progress":100,"Status":"ACTIVE","Updated":"2015-06-10T20:50:58Z"},{"Created":"2015-06-01T15:40:13Z","ID":"bf73f877-c24d-4288-bba2-14dcd13c5e02","MinDisk":20,"MinRAM":512,"Name":"Ubuntu 15.04 (Vivid Vervet) (PVHVM)","Progress":100,"Status":"ACTIVE","Updated":"2015-06-10T23:41:28Z"},{"Created":"2015-06-01T15:25:39Z","ID":"4d421e39-c0de-4b2d-bcee-3ebd6b66c01f","MinDisk":20,"MinRAM":512,"Name":"Debian Unstable (Sid) (PVHVM)","Progress":100,"Status":"ACTIVE","Updated":"2015-06-10T21:28:27Z"},{"Created":"2015-06-01T14:31:09Z","ID":"a41b3d62-5f7b-4697-a4a7-ca2bbf965a06","MinDisk":20,"MinRAM":512,"Name":"Ubuntu 14.04 LTS (Trusty Tahr) (PVHVM)","Progress":100,"Status":"ACTIVE","Updated":"2015-06-10T23:36:13Z"},{"Created":"2015-06-01T08:16:49Z","ID":"54885939-c176-48b1-bf7b-6d4039ab6696","MinDisk":20,"MinRAM":512,"Name":"OnMetal - Fedora 22","Progress":100,"Status":"ACTIVE","Updated":"2015-06-10T22:29:09Z"},{"Created":"2015-06-01T08:09:54Z","ID":"6042c5be-00ec-476b-9f6a-729996eaba49","MinDisk":20,"MinRAM":512,"Name":"OnMetal - Fedora 21","Progress":100,"Status":"ACTIVE","Updated":"2015-06-10T22:22:00Z"},{"Created":"2015-06-01T08:02:17Z","ID":"f45e963e-2707-4658-b042-fbb72a294aed","MinDisk":20,"MinRAM":512,"Name":"OnMetal - Debian Unstable (Sid)","Progress":100,"Status":"ACTIVE","Updated":"2015-06-10T22:16:45Z"},{"Created":"2015-06-01T07:49:04Z","ID":"5684389d-eaab-4e8e-9ce9-e042ff4ef9f8","MinDisk":20,"MinRAM":512,"Name":"OnMetal - Debian Testing (Stretch)","Progress":100,"Status":"ACTIVE","Updated":"2015-06-10T22:11:30Z"},{"Created":"2015-06-01T07:38:02Z","ID":"4410a770-0c5a-4336-aa28-5348d13de669","MinDisk":20,"MinRAM":512,"Name":"OnMetal - Debian 8 (Jessie)","Progress":100,"Status":"ACTIVE","Updated":"2015-06-10T22:06:15Z"},{"Created":"2015-06-01T07:12:17Z","ID":"1774d5b0-7452-408f-bba9-721e5cdf5e5d","MinDisk":20,"MinRAM":512,"Name":"OnMetal - Debian 7 (Wheezy)","Progress":100,"Status":"ACTIVE","Updated":"2015-06-10T22:01:01Z"},{"Created":"2015-06-01T06:52:04Z","ID":"d7c7c7c9-2c31-4a09-950a-3876ae5eedf4","MinDisk":20,"MinRAM":512,"Name":"OnMetal - Ubuntu 14.04 LTS (Trusty Tahr)","Progress":100,"Status":"ACTIVE","Updated":"2015-06-10T22:39:39Z"},{"Created":"2015-06-01T06:22:59Z","ID":"83959dc5-d75c-45be-a096-f938ea382b93","MinDisk":20,"MinRAM":512,"Name":"OnMetal - CentOS 7","Progress":100,"Status":"ACTIVE","Updated":"2015-06-10T21:55:45Z"},{"Created":"2015-06-01T05:55:50Z","ID":"7f78d71e-52a1-474b-a70f-c8d41734f743","MinDisk":20,"MinRAM":512,"Name":"Scientific Linux 7 (PVHVM)","Progress":100,"Status":"ACTIVE","Updated":"2015-06-10T23:20:13Z"},{"Created":"2015-06-01T05:47:54Z","ID":"51cdc9aa-803b-4bdf-9478-b5f27d21107f","MinDisk":20,"MinRAM":512,"Name":"Scientific Linux 6 (PVHVM)","Progress":100,"Status":"ACTIVE","Updated":"2015-06-10T23:11:34Z"},{"Created":"2015-06-01T05:21:41Z","ID":"bdc7f23b-83bc-4bb6-b1e7-4a42a1b91cbf","MinDisk":20,"MinRAM":512,"Name":"Gentoo 15.2 (PVHVM)","Progress":100,"Status":"ACTIVE","Updated":"2015-06-10T21:50:25Z"},{"Created":"2015-06-01T05:07:17Z","ID":"bb50954a-d069-4b32-8dc7-706618a28588","MinDisk":20,"MinRAM":512,"Name":"OpenSUSE 13.2 (PVHVM)","Progress":100,"Status":"ACTIVE","Updated":"2015-06-10T22:50:19Z"},{"Created":"2015-06-01T04:46:20Z","ID":"c4f76fa3-6f22-429a-a9e8-d5b0a06bcc98","MinDisk":20,"MinRAM":512,"Name":"FreeBSD 10 (PVHVM)","Progress":100,"Status":"ACTIVE","Updated":"2015-06-10T21:45:12Z"},{"Created":"2015-06-01T03:26:29Z","ID":"62e10fca-7a2f-48fc-8eb6-dda1595de7f7","MinDisk":20,"MinRAM":512,"Name":"Red Hat Enterprise Linux 7 (PVHVM)","Progress":100,"Status":"ACTIVE","Updated":"2015-06-10T23:06:19Z"},{"Created":"2015-06-01T03:25:23Z","ID":"ec3389c8-b2e2-46e0-9b33-c4938d2795ae","MinDisk":20,"MinRAM":512,"Name":"Red Hat Enterprise Linux 6 (PVHVM)","Progress":100,"Status":"ACTIVE","Updated":"2015-06-10T23:01:03Z"},{"Created":"2015-06-01T03:05:03Z","ID":"3017ebae-ecfc-4c0d-8042-5fd3485aa90d","MinDisk":20,"MinRAM":512,"Name":"Red Hat Enterprise Linux 6 (PV)","Progress":100,"Status":"ACTIVE","Updated":"2015-06-10T23:00:48Z"},{"Created":"2015-06-01T03:01:27Z","ID":"103e1ab4-4749-4da2-a373-7df2376714c6","MinDisk":20,"MinRAM":512,"Name":"Red Hat Enterprise Linux 5 (PV)","Progress":100,"Status":"ACTIVE","Updated":"2015-06-10T22:55:34Z"},{"Created":"2015-06-01T02:39:42Z","ID":"6a6b878e-c6a2-4a72-a096-bd388800c45a","MinDisk":20,"MinRAM":512,"Name":"Fedora 21 (PVHVM)","Progress":100,"Status":"ACTIVE","Updated":"2015-06-10T21:33:41Z"},{"Created":"2015-06-01T02:14:43Z","ID":"a0a71b6a-55e9-4f49-a053-f398337c9a9b","MinDisk":20,"MinRAM":512,"Name":"Debian Testing (Stretch) (PVHVM)","Progress":100,"Status":"ACTIVE","Updated":"2015-06-10T21:23:11Z"},{"Created":"2015-06-01T02:08:32Z","ID":"40982f53-c731-4227-8215-bd5afda8a2fe","MinDisk":20,"MinRAM":512,"Name":"Debian 8 (Jessie) (PVHVM)","Progress":100,"Status":"ACTIVE","Updated":"2015-06-10T21:17:56Z"},{"Created":"2015-06-01T01:43:37Z","ID":"0f7838c3-5b27-4950-81b3-53baaf84c9ce","MinDisk":20,"MinRAM":512,"Name":"Debian 7 (Wheezy) (PVHVM)","Progress":100,"Status":"ACTIVE","Updated":"2015-06-10T21:12:41Z"},{"Created":"2015-06-01T01:41:53Z","ID":"a743dd3b-e409-4833-be55-d85f6192817e","MinDisk":20,"MinRAM":512,"Name":"Ubuntu 12.04 LTS (Precise Pangolin) (PVHVM)","Progress":100,"Status":"ACTIVE","Updated":"2015-06-10T23:30:43Z"},{"Created":"2015-06-01T01:41:44Z","ID":"c9659075-d425-4823-b9ab-a3b9761ac030","MinDisk":20,"MinRAM":512,"Name":"Ubuntu 12.04 LTS (Precise Pangolin) (PV)","Progress":100,"Status":"ACTIVE","Updated":"2015-06-10T23:25:29Z"},{"Created":"2015-06-01T01:23:50Z","ID":"296e3de7-8e75-45ca-8e43-3b46a668576a","MinDisk":20,"MinRAM":512,"Name":"Ubuntu 14.04 LTS (Trusty Tahr) (PV)","Progress":100,"Status":"ACTIVE","Updated":"2015-06-10T23:30:58Z"},{"Created":"2015-06-01T00:56:33Z","ID":"7dc47eb8-5b4a-4ce4-9b1d-744d93b92c89","MinDisk":20,"MinRAM":512,"Name":"CentOS 7 (PVHVM)","Progress":100,"Status":"ACTIVE","Updated":"2015-06-10T21:07:26Z"},{"Created":"2015-06-01T00:50:38Z","ID":"4b0c4c69-5d5a-4140-8d22-3813eef9292f","MinDisk":20,"MinRAM":512,"Name":"CentOS 5 (PV)","Progress":100,"Status":"ACTIVE","Updated":"2015-06-10T20:56:10Z"},{"Created":"2015-06-01T00:50:38Z","ID":"1dc14b15-707b-4a93-af23-2ef1fd57828c","MinDisk":20,"MinRAM":512,"Name":"CentOS 6 (PV)","Progress":100,"Status":"ACTIVE","Updated":"2015-06-10T21:01:56Z"},{"Created":"2015-06-01T00:50:38Z","ID":"00341bad-631f-42b6-bc3c-7a861f9cd637","MinDisk":20,"MinRAM":512,"Name":"CentOS 6 (PVHVM)","Progress":100,"Status":"ACTIVE","Updated":"2015-06-10T21:02:10Z"},{"Created":"2015-05-23T00:14:28Z","ID":"abb67d66-94b6-4a91-a234-6b1a952fd60b","MinDisk":40,"MinRAM":2048,"Name":"Windows Server 2008 R2 SP1 + SQL Server 2008 R2 SP2 Web","Progress":100,"Status":"ACTIVE","Updated":"2015-06-10T12:15:20Z"},{"Created":"2015-05-22T10:17:32Z","ID":"a6fc998a-f4ba-4613-8bf1-5afa51d4474d","MinDisk":40,"MinRAM":2048,"Name":"Windows Server 2008 R2 SP1 + SQL Server 2008 R2 SP2 Standard","Progress":100,"Status":"ACTIVE","Updated":"2015-06-10T12:09:59Z"},{"Created":"2015-05-21T08:16:07Z","ID":"cbb2aff3-77d9-448e-9c63-157aaef5a28e","MinDisk":40,"MinRAM":1024,"Name":"Windows Server 2012","Progress":100,"Status":"ACTIVE","Updated":"2015-06-10T15:41:06Z"},{"Created":"2015-05-21T05:23:36Z","ID":"ce1fa266-3914-4ffd-83f3-97d0e34fc9cb","MinDisk":40,"MinRAM":1024,"Name":"Windows Server 2008 R2 SP1","Progress":100,"Status":"ACTIVE","Updated":"2015-06-10T02:48:20Z"},{"Created":"2015-04-16T06:19:22Z","ID":"e788cfc4-a2ec-4f0d-bce2-6dd961dc7899","MinDisk":40,"MinRAM":2048,"Name":"Windows Server 2012 R2 + SQL Server 2014 Standard","Progress":100,"Status":"ACTIVE","Updated":"2015-04-22T15:59:19Z"},{"Created":"2015-04-16T05:49:48Z","ID":"5109f615-adcc-44ac-9a8e-7697d07d7d28","MinDisk":40,"MinRAM":2048,"Name":"Windows Server 2012 R2 + SQL Server 2014 Web","Progress":100,"Status":"ACTIVE","Updated":"2015-04-22T16:04:35Z"},{"Created":"2015-04-15T02:16:42Z","ID":"e3caa20a-ab9a-48ee-a0c6-02561806616d","MinDisk":40,"MinRAM":1024,"Name":"Windows Server 2012 R2","Progress":100,"Status":"ACTIVE","Updated":"2015-04-22T15:43:30Z"},{"Created":"2015-03-05T15:06:54Z","ID":"07c16842-db34-449a-90ac-e8f05dd8564e","MinDisk":20,"MinRAM":1024,"Name":"Vyatta Network OS 6.7R6","Progress":100,"Status":"ACTIVE","Updated":"2015-04-21T13:58:14Z"},{"Created":"2015-01-27T16:36:14Z","ID":"811ffa1f-97f8-46f6-9893-6fc36c09a0b6","MinDisk":40,"MinRAM":512,"Name":"Daily-minecraft-1422376573","Progress":100,"Status":"ACTIVE","Updated":"2015-01-27T17:07:49Z"},{"Created":"2015-01-26T16:36:15Z","ID":"2ed99d72-96c6-4aab-9a4c-cf9f8210ae26","MinDisk":40,"MinRAM":512,"Name":"Daily-minecraft-1422290174","Progress":100,"Status":"ACTIVE","Updated":"2015-01-26T16:48:09Z"},{"Created":"2015-01-25T16:36:12Z","ID":"e877987a-6145-4d2b-a14d-d3f9b03f08a6","MinDisk":40,"MinRAM":512,"Name":"Daily-minecraft-1422203771","Progress":100,"Status":"ACTIVE","Updated":"2015-01-25T16:40:25Z"},{"Created":"2015-01-24T16:36:15Z","ID":"a7721b21-0435-4a7f-a46f-d3797504ddc6","MinDisk":40,"MinRAM":512,"Name":"Daily-minecraft-1422117374","Progress":100,"Status":"ACTIVE","Updated":"2015-01-24T16:44:49Z"},{"Created":"2015-01-23T16:36:10Z","ID":"a113bada-bf84-430a-80b8-baa653ca776d","MinDisk":40,"MinRAM":512,"Name":"Daily-minecraft-1422030969","Progress":100,"Status":"ACTIVE","Updated":"2015-01-23T16:48:09Z"},{"Created":"2015-01-22T16:53:08Z","ID":"4378750e-6bb6-490f-950c-012007396fc1","MinDisk":40,"MinRAM":512,"Name":"Daily-minecraft-1421945587","Progress":100,"Status":"ACTIVE","Updated":"2015-01-22T16:57:53Z"},{"Created":"2015-01-21T16:36:14Z","ID":"4927bcb0-4c38-46ef-b765-09b93c898519","MinDisk":40,"MinRAM":512,"Name":"Daily-minecraft-1421858173","Progress":100,"Status":"ACTIVE","Updated":"2015-01-21T16:39:57Z"},{"Created":"2014-12-23T16:45:24Z","ID":"07cef8c2-1f49-4eb9-b98f-ebe47d778f4c","MinDisk":40,"MinRAM":512,"Name":"minecraft","Progress":100,"Status":"ACTIVE","Updated":"2014-12-23T16:48:35Z"},{"Created":"2014-10-17T04:11:30Z","ID":"959aee20-e0b8-42a7-9201-10057c2b7e05","MinDisk":40,"MinRAM":8192,"Name":"Windows Server 2008 R2 SP1 + SharePoint 2010 Foundation with SQL Server 2008 R2 SP1 Standard","Progress":100,"Status":"ACTIVE","Updated":"2014-10-25T01:57:40Z"},{"Created":"2014-10-17T00:30:25Z","ID":"b28d7079-c4e8-41cf-94ce-9c4b57cf6f23","MinDisk":40,"MinRAM":4096,"Name":"Windows Server 2008 R2 SP1 + SharePoint 2010 Foundation with SQL Server 2008 R2 Express","Progress":100,"Status":"ACTIVE","Updated":"2014-10-28T23:08:40Z"},{"Created":"2014-10-16T19:16:21Z","ID":"fe486888-6890-47ac-a02d-b740868f143b","MinDisk":40,"MinRAM":1024,"Name":"Windows Server 2012 R2 (base install without updates)","Progress":100,"Status":"ACTIVE","Updated":"2014-10-16T22:50:44Z"},{"Created":"2014-10-16T18:14:38Z","ID":"c81a65a3-8217-4520-96de-1d9313ae3094","MinDisk":40,"MinRAM":1024,"Name":"Windows Server 2012 (base install without updates)","Progress":100,"Status":"ACTIVE","Updated":"2014-10-16T23:12:05Z"},{"Created":"2014-10-16T16:04:28Z","ID":"b41c2705-f820-4b6f-8d32-d04b5f57a4f7","MinDisk":40,"MinRAM":2048,"Name":"Windows Server 2008 R2 SP1 + SQL Server 2012 SP1 Standard","Progress":100,"Status":"ACTIVE","Updated":"2014-10-16T22:55:55Z"},{"Created":"2014-10-16T15:58:17Z","ID":"c6301f02-1388-4a4a-ba7c-b52e1bff7813","MinDisk":40,"MinRAM":2048,"Name":"Windows Server 2008 R2 SP1 + SQL Server 2012 SP1 Web","Progress":100,"Status":"ACTIVE","Updated":"2014-10-16T23:06:12Z"},{"Created":"2014-10-16T15:27:20Z","ID":"f46e9237-9971-44b1-b92f-3a5a03592d3e","MinDisk":40,"MinRAM":1024,"Name":"Windows Server 2008 R2 SP1 (base install without updates)","Progress":100,"Status":"ACTIVE","Updated":"2014-10-21T22:30:00Z"},{"Created":"2014-06-18T05:01:13Z","ID":"d69d55ef-cb4c-4787-9f1b-2de41ecac9a1","MinDisk":40,"MinRAM":8192,"Name":"Windows Server 2012 + SharePoint 2013 with SQL Server 2012 SP1 Standard","Progress":100,"Status":"ACTIVE","Updated":"2014-07-18T14:00:24Z"},{"Created":"2014-02-01T18:22:30Z","ID":"49e7c8db-8923-4356-89c7-2e2d84dbf90d","MinDisk":40,"MinRAM":512,"Name":"perf30GB-PVHVM","Progress":100,"Status":"ACTIVE","Updated":"2014-02-01T18:25:00Z"},{"Created":"2014-02-01T18:22:21Z","ID":"3669d670-cb74-449b-9795-e7fa8d267bf0","MinDisk":40,"MinRAM":512,"Name":"perf30GB-PV","Progress":100,"Status":"ACTIVE","Updated":"2014-02-01T18:24:02Z"},{"Created":"2014-02-01T18:22:05Z","ID":"03051d2e-ce2a-458f-8166-0b1256a6f552","MinDisk":1200,"MinRAM":512,"Name":"nextgen30GB-PV","Progress":100,"Status":"ACTIVE","Updated":"2014-02-01T18:32:30Z"},{"Created":"2013-07-19T21:37:17Z","ID":"9aa0d346-c06f-4652-bbb1-4342a7d2d017","MinDisk":0,"MinRAM":0,"Name":"iPXE Boot (boot.rackspace.com)","Progress":100,"Status":"ACTIVE","Updated":"2014-07-07T17:51:33Z"}]

A good feature request: pretty print the JSON output

Streamline installation for OSX and Linux

I think we should be able to reduce installation on OSX and Linux to 2 commands.

$ curl -L https://rack.developer.rackspace.com/rack-`uname -s`-`uname -m` > /usr/local/bin/rack
$ chmod +x /usr/local/bin/rack

This assumes a few things:

  • We have a proper domain name to replace the Cloud Files CDN domain name
  • The binaries are saved with capitalized Darwin and Linux to account of the output of uname -s
  • We provide 32 and 64 bit binaries. If not, we can just drop the uname -m

I also see we mkdir -p /usr/local/bin/ and export PATH=$PATH:/usr/local/bin. What OSX and Linux distros don't come with /usr/local/bin/ already?

I picked this stuff up from the installation instructions for docker-compose.

region verification

Should we verify regions in the interactive rack configure command? rack configure walks users through setting up a config file to be used for authentication. Currently, for users to authenticate against the production Rackspace endpoint, they only have 6 options: "DFW", "IAD", "ORD", "LON", "SYD", "HKG".

It is possible though that internal users may want to test against other regions. Because of that, we wouldn't want to force one of the above regions on all users (doing region verification during client creation, for instance). However, I'd expect the users using rack configure to be Rackspace customers who would only be able to use one of the above regions.

One possible downside of region verification is that if/when Rackspace does add another public region, we'd have to update this repo with the new region, and users would have to re-download the CLI in order to authenticate against the new region.

flag naming convention

Currently the flags are named like Go varaibles: flavorID, publicKey. We should probably move to a more conventional naming method like kebab-case: flavor-id, public-key.

bash completion for flags

Currently, only bash completion for commands and subcommands is supported. We should add it for flags as well.

Rename to rack

The current name rackcli is quite redundant. Imagine typing "rackcli" on the CLI over and over and over, thousands of times in your careers as an operator or support floor admin. Sooner than later the redundancy of typing "cli" on the CLI will become painful. It's a papercut we can avoid.

Also note how no other CLI app ever has appended "cli" to the actual command name.

The package name also appears to be available!

http://packages.ubuntu.com/search?keywords=rack&searchon=names&suite=trusty&section=all

and

$ brew install rack
Error: No available formula for rack
Searching formulae...
aircrack-ng   cracklib-words    git-tracker       lcrack        nutcracker    pdfcrack      tcptrack
cracklib      fcrackzip     httrack       ncrack        ophcrack      plt-racket        truecrack
Searching taps...
Caskroom/cask/8tracksradiohelper        Caskroom/cask/klystrack             Caskroom/cask/racket
Caskroom/cask/actotracker           Caskroom/cask/loadmytracks          Caskroom/cask/rubitrack
Caskroom/cask/brackets              Caskroom/cask/mactracker            Caskroom/cask/time-tracker
Caskroom/cask/charlessoft-timetracker       Caskroom/cask/milkytracker          Caskroom/cask/track-o-bot
Caskroom/cask/kensington-trackball-works    Caskroom/cask/pokertracker          Caskroom/cask/youtrack-workflow

We are the rack. Let's name our kickass CLI "rack".

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.