New provider arukas (#11171)

* Add a Arukas provider

* Add dependencies for the Arukas provider

* Add documents for the Arukas
This commit is contained in:
Kazumichi Yamamoto 2017-02-14 04:11:30 +09:00 committed by Paul Stack
parent d5d5cd017c
commit cd7f69ab11
40 changed files with 3490 additions and 0 deletions

View File

@ -0,0 +1,12 @@
package main
import (
"github.com/hashicorp/terraform/builtin/providers/arukas"
"github.com/hashicorp/terraform/plugin"
)
func main() {
plugin.Serve(&plugin.ServeOpts{
ProviderFunc: arukas.Provider,
})
}

View File

@ -0,0 +1 @@
package main

View File

@ -0,0 +1,52 @@
package arukas
import (
API "github.com/arukasio/cli"
"os"
"time"
)
const (
JSONTokenParamName = "ARUKAS_JSON_API_TOKEN"
JSONSecretParamName = "ARUKAS_JSON_API_SECRET"
JSONUrlParamName = "ARUKAS_JSON_API_URL"
JSONDebugParamName = "ARUKAS_DEBUG"
JSONTimeoutParamName = "ARUKAS_TIMEOUT"
)
type Config struct {
Token string
Secret string
URL string
Trace string
Timeout int
}
func (c *Config) NewClient() (*ArukasClient, error) {
os.Setenv(JSONTokenParamName, c.Token)
os.Setenv(JSONSecretParamName, c.Secret)
os.Setenv(JSONUrlParamName, c.URL)
os.Setenv(JSONDebugParamName, c.Trace)
client, err := API.NewClient()
if err != nil {
return nil, err
}
client.UserAgent = "Terraform for Arukas"
timeout := time.Duration(0)
if c.Timeout > 0 {
timeout = time.Duration(c.Timeout) * time.Second
}
return &ArukasClient{
Client: client,
Timeout: timeout,
}, nil
}
type ArukasClient struct {
*API.Client
Timeout time.Duration
}

View File

@ -0,0 +1,59 @@
package arukas
import (
"github.com/hashicorp/terraform/helper/schema"
"github.com/hashicorp/terraform/terraform"
)
// Provider returns a terraform.ResourceProvider.
func Provider() terraform.ResourceProvider {
return &schema.Provider{
Schema: map[string]*schema.Schema{
"token": &schema.Schema{
Type: schema.TypeString,
Required: true,
DefaultFunc: schema.EnvDefaultFunc(JSONTokenParamName, nil),
Description: "your Arukas APIKey(token)",
},
"secret": &schema.Schema{
Type: schema.TypeString,
Required: true,
DefaultFunc: schema.EnvDefaultFunc(JSONSecretParamName, nil),
Description: "your Arukas APIKey(secret)",
},
"api_url": &schema.Schema{
Type: schema.TypeString,
Optional: true,
DefaultFunc: schema.EnvDefaultFunc(JSONUrlParamName, "https://app.arukas.io/api/"),
Description: "default Arukas API url",
},
"trace": &schema.Schema{
Type: schema.TypeString,
Optional: true,
DefaultFunc: schema.EnvDefaultFunc(JSONDebugParamName, ""),
},
"timeout": &schema.Schema{
Type: schema.TypeInt,
Optional: true,
DefaultFunc: schema.EnvDefaultFunc(JSONTimeoutParamName, "600"),
},
},
ResourcesMap: map[string]*schema.Resource{
"arukas_container": resourceArukasContainer(),
},
ConfigureFunc: providerConfigure,
}
}
func providerConfigure(d *schema.ResourceData) (interface{}, error) {
config := Config{
Token: d.Get("token").(string),
Secret: d.Get("secret").(string),
URL: d.Get("api_url").(string),
Trace: d.Get("trace").(string),
Timeout: d.Get("timeout").(int),
}
return config.NewClient()
}

View File

@ -0,0 +1,38 @@
package arukas
import (
"os"
"testing"
"github.com/hashicorp/terraform/helper/schema"
"github.com/hashicorp/terraform/terraform"
)
var testAccProviders map[string]terraform.ResourceProvider
var testAccProvider *schema.Provider
func init() {
testAccProvider = Provider().(*schema.Provider)
testAccProviders = map[string]terraform.ResourceProvider{
"arukas": testAccProvider,
}
}
func TestProvider(t *testing.T) {
if err := Provider().(*schema.Provider).InternalValidate(); err != nil {
t.Fatalf("err: %s", err)
}
}
func TestProvider_impl(t *testing.T) {
var _ terraform.ResourceProvider = Provider()
}
func testAccPreCheck(t *testing.T) {
if v := os.Getenv("ARUKAS_JSON_API_TOKEN"); v == "" {
t.Fatal("ARUKAS_JSON_API_TOKEN must be set for acceptance tests")
}
if v := os.Getenv("ARUKAS_JSON_API_SECRET"); v == "" {
t.Fatal("ARUKAS_JSON_API_SECRET must be set for acceptance tests")
}
}

View File

@ -0,0 +1,293 @@
package arukas
import (
"fmt"
API "github.com/arukasio/cli"
"github.com/hashicorp/terraform/helper/schema"
"strings"
"time"
)
func resourceArukasContainer() *schema.Resource {
return &schema.Resource{
Create: resourceArukasContainerCreate,
Read: resourceArukasContainerRead,
Update: resourceArukasContainerUpdate,
Delete: resourceArukasContainerDelete,
Importer: &schema.ResourceImporter{
State: schema.ImportStatePassthrough,
},
Schema: map[string]*schema.Schema{
"name": &schema.Schema{
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
"image": &schema.Schema{
Type: schema.TypeString,
Required: true,
},
"instances": &schema.Schema{
Type: schema.TypeInt,
Optional: true,
Default: 1,
ValidateFunc: validateIntegerInRange(1, 10),
},
"memory": &schema.Schema{
Type: schema.TypeInt,
Optional: true,
Default: 256,
ValidateFunc: validateIntInWord([]string{"256", "512"}),
},
"endpoint": &schema.Schema{
Type: schema.TypeString,
Optional: true,
Computed: true,
},
"ports": &schema.Schema{
Type: schema.TypeList,
Required: true,
MaxItems: 20,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"protocol": &schema.Schema{
Type: schema.TypeString,
Optional: true,
Default: "tcp",
ValidateFunc: validateStringInWord([]string{"tcp", "udp"}),
},
"number": &schema.Schema{
Type: schema.TypeInt,
Optional: true,
Default: "80",
ValidateFunc: validateIntegerInRange(1, 65535),
},
},
},
},
"environments": &schema.Schema{
Type: schema.TypeList,
Optional: true,
MaxItems: 20,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"key": &schema.Schema{
Type: schema.TypeString,
Required: true,
},
"value": &schema.Schema{
Type: schema.TypeString,
Required: true,
},
},
},
},
"cmd": &schema.Schema{
Type: schema.TypeString,
Optional: true,
},
"port_mappings": &schema.Schema{
Type: schema.TypeList,
Computed: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"host": &schema.Schema{
Type: schema.TypeString,
Computed: true,
},
"ipaddress": &schema.Schema{
Type: schema.TypeString,
Computed: true,
},
"container_port": &schema.Schema{
Type: schema.TypeInt,
Computed: true,
},
"service_port": &schema.Schema{
Type: schema.TypeInt,
Computed: true,
},
},
},
},
"endpoint_full_hostname": &schema.Schema{
Type: schema.TypeString,
Computed: true,
},
"endpoint_full_url": &schema.Schema{
Type: schema.TypeString,
Computed: true,
},
"app_id": &schema.Schema{
Type: schema.TypeString,
Computed: true,
},
},
}
}
func resourceArukasContainerCreate(d *schema.ResourceData, meta interface{}) error {
client := meta.(*ArukasClient)
var appSet API.AppSet
// create an app
newApp := API.App{Name: d.Get("name").(string)}
var parsedEnvs API.Envs
var parsedPorts API.Ports
if rawEnvs, ok := d.GetOk("environments"); ok {
parsedEnvs = expandEnvs(rawEnvs)
}
if rawPorts, ok := d.GetOk("ports"); ok {
parsedPorts = expandPorts(rawPorts)
}
newContainer := API.Container{
Envs: parsedEnvs,
Ports: parsedPorts,
ImageName: d.Get("image").(string),
Mem: d.Get("memory").(int),
Instances: d.Get("instances").(int),
Cmd: d.Get("cmd").(string),
Name: d.Get("endpoint").(string),
}
newAppSet := API.AppSet{
App: newApp,
Container: newContainer,
}
// create
if err := client.Post(&appSet, "/app-sets", newAppSet); err != nil {
return err
}
// start container
if err := client.Post(nil, fmt.Sprintf("/containers/%s/power", appSet.Container.ID), nil); err != nil {
return err
}
if err := sleepUntilUp(client, appSet.Container.ID, client.Timeout); err != nil {
return err
}
d.SetId(appSet.Container.ID)
return resourceArukasContainerRead(d, meta)
}
func resourceArukasContainerRead(d *schema.ResourceData, meta interface{}) error {
client := meta.(*ArukasClient)
var container API.Container
var app API.App
if err := client.Get(&container, fmt.Sprintf("/containers/%s", d.Id())); err != nil {
return err
}
if err := client.Get(&app, fmt.Sprintf("/apps/%s", container.AppID)); err != nil {
return err
}
d.Set("app_id", container.AppID)
d.Set("name", app.Name)
d.Set("image", container.ImageName)
d.Set("instances", container.Instances)
d.Set("memory", container.Mem)
endpoint := container.Endpoint
if strings.HasSuffix(endpoint, ".arukascloud.io") {
endpoint = strings.Replace(endpoint, ".arukascloud.io", "", -1)
}
d.Set("endpoint", endpoint)
d.Set("endpoint_full_hostname", container.Endpoint)
d.Set("endpoint_full_url", fmt.Sprintf("https://%s", container.Endpoint))
d.Set("cmd", container.Cmd)
//ports
d.Set("ports", flattenPorts(container.Ports))
//port mappings
d.Set("port_mappings", flattenPortMappings(container.PortMappings))
//envs
d.Set("environments", flattenEnvs(container.Envs))
return nil
}
func resourceArukasContainerUpdate(d *schema.ResourceData, meta interface{}) error {
client := meta.(*ArukasClient)
var container API.Container
if err := client.Get(&container, fmt.Sprintf("/containers/%s", d.Id())); err != nil {
return err
}
var parsedEnvs API.Envs
var parsedPorts API.Ports
if rawEnvs, ok := d.GetOk("environments"); ok {
parsedEnvs = expandEnvs(rawEnvs)
}
if rawPorts, ok := d.GetOk("ports"); ok {
parsedPorts = expandPorts(rawPorts)
}
newContainer := API.Container{
Envs: parsedEnvs,
Ports: parsedPorts,
ImageName: d.Get("image").(string),
Mem: d.Get("memory").(int),
Instances: d.Get("instances").(int),
Cmd: d.Get("cmd").(string),
Name: d.Get("endpoint").(string),
}
// update
if err := client.Patch(nil, fmt.Sprintf("/containers/%s", d.Id()), newContainer); err != nil {
return err
}
return resourceArukasContainerRead(d, meta)
}
func resourceArukasContainerDelete(d *schema.ResourceData, meta interface{}) error {
client := meta.(*ArukasClient)
var container API.Container
if err := client.Get(&container, fmt.Sprintf("/containers/%s", d.Id())); err != nil {
return err
}
if err := client.Delete(fmt.Sprintf("/apps/%s", container.AppID)); err != nil {
return err
}
return nil
}
func sleepUntilUp(client *ArukasClient, containerID string, timeout time.Duration) error {
current := 0 * time.Second
interval := 5 * time.Second
for {
var container API.Container
if err := client.Get(&container, fmt.Sprintf("/containers/%s", containerID)); err != nil {
return err
}
if container.IsRunning {
return nil
}
time.Sleep(interval)
current += interval
if timeout > 0 && current > timeout {
return fmt.Errorf("Timeout: sleepUntilUp")
}
}
}

View File

@ -0,0 +1,279 @@
package arukas
import (
"fmt"
API "github.com/arukasio/cli"
"github.com/hashicorp/terraform/helper/resource"
"github.com/hashicorp/terraform/terraform"
"testing"
)
func TestAccArukasContainer_Basic(t *testing.T) {
var container API.Container
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckArukasContainerDestroy,
Steps: []resource.TestStep{
resource.TestStep{
Config: testAccCheckArukasContainerConfig_basic,
Check: resource.ComposeTestCheckFunc(
testAccCheckArukasContainerExists("arukas_container.foobar", &container),
resource.TestCheckResourceAttr(
"arukas_container.foobar", "name", "terraform_for_arukas_test_foobar"),
resource.TestCheckResourceAttr(
"arukas_container.foobar", "image", "nginx:latest"),
resource.TestCheckResourceAttr(
"arukas_container.foobar", "instances", "1"),
resource.TestCheckResourceAttr(
"arukas_container.foobar", "memory", "256"),
resource.TestCheckResourceAttr(
"arukas_container.foobar", "endpoint", "terraform-for-arukas-test-endpoint"),
resource.TestCheckResourceAttr(
"arukas_container.foobar", "ports.#", "1"),
resource.TestCheckResourceAttr(
"arukas_container.foobar", "ports.0.protocol", "tcp"),
resource.TestCheckResourceAttr(
"arukas_container.foobar", "ports.0.number", "80"),
resource.TestCheckResourceAttr(
"arukas_container.foobar", "environments.#", "1"),
resource.TestCheckResourceAttr(
"arukas_container.foobar", "environments.0.key", "key"),
resource.TestCheckResourceAttr(
"arukas_container.foobar", "environments.0.value", "value"),
resource.TestCheckResourceAttr(
"arukas_container.foobar", "port_mappings.#", "1"),
),
},
},
})
}
func TestAccArukasContainer_Update(t *testing.T) {
var container API.Container
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckArukasContainerDestroy,
Steps: []resource.TestStep{
resource.TestStep{
Config: testAccCheckArukasContainerConfig_basic,
Check: resource.ComposeTestCheckFunc(
testAccCheckArukasContainerExists("arukas_container.foobar", &container),
resource.TestCheckResourceAttr(
"arukas_container.foobar", "name", "terraform_for_arukas_test_foobar"),
resource.TestCheckResourceAttr(
"arukas_container.foobar", "image", "nginx:latest"),
resource.TestCheckResourceAttr(
"arukas_container.foobar", "instances", "1"),
resource.TestCheckResourceAttr(
"arukas_container.foobar", "memory", "256"),
resource.TestCheckResourceAttr(
"arukas_container.foobar", "endpoint", "terraform-for-arukas-test-endpoint"),
resource.TestCheckResourceAttr(
"arukas_container.foobar", "ports.#", "1"),
resource.TestCheckResourceAttr(
"arukas_container.foobar", "ports.0.protocol", "tcp"),
resource.TestCheckResourceAttr(
"arukas_container.foobar", "ports.0.number", "80"),
resource.TestCheckResourceAttr(
"arukas_container.foobar", "environments.#", "1"),
resource.TestCheckResourceAttr(
"arukas_container.foobar", "environments.0.key", "key"),
resource.TestCheckResourceAttr(
"arukas_container.foobar", "environments.0.value", "value"),
resource.TestCheckResourceAttr(
"arukas_container.foobar", "port_mappings.#", "1"),
),
},
resource.TestStep{
Config: testAccCheckArukasContainerConfig_update,
Check: resource.ComposeTestCheckFunc(
testAccCheckArukasContainerExists("arukas_container.foobar", &container),
resource.TestCheckResourceAttr(
"arukas_container.foobar", "name", "terraform_for_arukas_test_foobar_upd"),
resource.TestCheckResourceAttr(
"arukas_container.foobar", "image", "nginx:latest"),
resource.TestCheckResourceAttr(
"arukas_container.foobar", "instances", "2"),
resource.TestCheckResourceAttr(
"arukas_container.foobar", "memory", "512"),
resource.TestCheckResourceAttr(
"arukas_container.foobar", "endpoint", "terraform-for-arukas-test-endpoint-upd"),
resource.TestCheckResourceAttr(
"arukas_container.foobar", "ports.#", "2"),
resource.TestCheckResourceAttr(
"arukas_container.foobar", "ports.0.protocol", "tcp"),
resource.TestCheckResourceAttr(
"arukas_container.foobar", "ports.0.number", "80"),
resource.TestCheckResourceAttr(
"arukas_container.foobar", "ports.1.protocol", "tcp"),
resource.TestCheckResourceAttr(
"arukas_container.foobar", "ports.1.number", "443"),
resource.TestCheckResourceAttr(
"arukas_container.foobar", "environments.#", "2"),
resource.TestCheckResourceAttr(
"arukas_container.foobar", "environments.0.key", "key"),
resource.TestCheckResourceAttr(
"arukas_container.foobar", "environments.0.value", "value"),
resource.TestCheckResourceAttr(
"arukas_container.foobar", "environments.1.key", "key_upd"),
resource.TestCheckResourceAttr(
"arukas_container.foobar", "environments.1.value", "value_upd"),
resource.TestCheckResourceAttr(
"arukas_container.foobar", "port_mappings.#", "4"),
),
},
},
})
}
func TestAccArukasContainer_Minimum(t *testing.T) {
var container API.Container
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckArukasContainerDestroy,
Steps: []resource.TestStep{
resource.TestStep{
Config: testAccCheckArukasContainerConfig_minimum,
Check: resource.ComposeTestCheckFunc(
testAccCheckArukasContainerExists("arukas_container.foobar", &container),
resource.TestCheckResourceAttr(
"arukas_container.foobar", "name", "terraform_for_arukas_test_foobar"),
resource.TestCheckResourceAttr(
"arukas_container.foobar", "image", "nginx:latest"),
resource.TestCheckResourceAttr(
"arukas_container.foobar", "instances", "1"),
resource.TestCheckResourceAttr(
"arukas_container.foobar", "memory", "256"),
resource.TestCheckResourceAttr(
"arukas_container.foobar", "ports.#", "1"),
resource.TestCheckResourceAttr(
"arukas_container.foobar", "ports.0.protocol", "tcp"),
resource.TestCheckResourceAttr(
"arukas_container.foobar", "ports.0.number", "80"),
resource.TestCheckResourceAttr(
"arukas_container.foobar", "port_mappings.#", "1"),
),
},
},
})
}
func TestAccArukasContainer_Import(t *testing.T) {
resourceName := "arukas_container.foobar"
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckArukasContainerDestroy,
Steps: []resource.TestStep{
resource.TestStep{
Config: testAccCheckArukasContainerConfig_basic,
},
resource.TestStep{
ResourceName: resourceName,
ImportState: true,
ImportStateVerify: true,
},
},
})
}
func testAccCheckArukasContainerExists(n string, container *API.Container) resource.TestCheckFunc {
return func(s *terraform.State) error {
rs, ok := s.RootModule().Resources[n]
if !ok {
return fmt.Errorf("Not found: %s", n)
}
if rs.Primary.ID == "" {
return fmt.Errorf("No Container ID is set")
}
client := testAccProvider.Meta().(*ArukasClient)
var foundContainer API.Container
err := client.Get(&foundContainer, fmt.Sprintf("/containers/%s", rs.Primary.ID))
if err != nil {
return err
}
if foundContainer.ID != rs.Primary.ID {
return fmt.Errorf("Container not found")
}
*container = foundContainer
return nil
}
}
func testAccCheckArukasContainerDestroy(s *terraform.State) error {
client := testAccProvider.Meta().(*ArukasClient)
for _, rs := range s.RootModule().Resources {
if rs.Type != "arukas_container" {
continue
}
err := client.Get(nil, fmt.Sprintf("/containers/%s", rs.Primary.ID))
if err == nil {
return fmt.Errorf("Note still exists")
}
}
return nil
}
const testAccCheckArukasContainerConfig_basic = `
resource "arukas_container" "foobar" {
name = "terraform_for_arukas_test_foobar"
image = "nginx:latest"
instances = 1
memory = 256
endpoint = "terraform-for-arukas-test-endpoint"
ports = {
protocol = "tcp"
number = "80"
}
environments {
key = "key"
value = "value"
}
}`
const testAccCheckArukasContainerConfig_update = `
resource "arukas_container" "foobar" {
name = "terraform_for_arukas_test_foobar_upd"
image = "nginx:latest"
instances = 2
memory = 512
endpoint = "terraform-for-arukas-test-endpoint-upd"
ports = {
protocol = "tcp"
number = "80"
}
ports = {
protocol = "tcp"
number = "443"
}
environments {
key = "key"
value = "value"
}
environments {
key = "key_upd"
value = "value_upd"
}
}`
const testAccCheckArukasContainerConfig_minimum = `
resource "arukas_container" "foobar" {
name = "terraform_for_arukas_test_foobar"
image = "nginx:latest"
ports = {
number = "80"
}
}`

View File

@ -0,0 +1,110 @@
package arukas
import (
API "github.com/arukasio/cli"
"github.com/hashicorp/terraform/helper/schema"
"net"
)
// Takes the result of flatmap.Expand for an array of strings
// and returns a []string
func expandStringList(configured []interface{}) []string {
vs := make([]string, 0, len(configured))
for _, v := range configured {
vs = append(vs, string(v.(string)))
}
return vs
}
// Takes the result of schema.Set of strings and returns a []string
func expandStringSet(configured *schema.Set) []string {
return expandStringList(configured.List())
}
// Takes list of pointers to strings. Expand to an array
// of raw strings and returns a []interface{}
// to keep compatibility w/ schema.NewSetschema.NewSet
func flattenStringList(list []string) []interface{} {
vs := make([]interface{}, 0, len(list))
for _, v := range list {
vs = append(vs, v)
}
return vs
}
func expandEnvs(configured interface{}) API.Envs {
var envs API.Envs
if configured == nil {
return envs
}
rawEnvs := configured.([]interface{})
for _, raw := range rawEnvs {
env := raw.(map[string]interface{})
envs = append(envs, API.Env{Key: env["key"].(string), Value: env["value"].(string)})
}
return envs
}
func flattenEnvs(envs API.Envs) []interface{} {
var ret []interface{}
for _, env := range envs {
r := map[string]interface{}{}
r["key"] = env.Key
r["value"] = env.Value
ret = append(ret, r)
}
return ret
}
func expandPorts(configured interface{}) API.Ports {
var ports API.Ports
if configured == nil {
return ports
}
rawPorts := configured.([]interface{})
for _, raw := range rawPorts {
port := raw.(map[string]interface{})
ports = append(ports, API.Port{Protocol: port["protocol"].(string), Number: port["number"].(int)})
}
return ports
}
func flattenPorts(ports API.Ports) []interface{} {
var ret []interface{}
for _, port := range ports {
r := map[string]interface{}{}
r["protocol"] = port.Protocol
r["number"] = port.Number
ret = append(ret, r)
}
return ret
}
func flattenPortMappings(ports API.PortMappings) []interface{} {
var ret []interface{}
for _, tasks := range ports {
for _, port := range tasks {
r := map[string]interface{}{}
ip := ""
addrs, err := net.LookupHost(port.Host)
if err == nil && len(addrs) > 0 {
ip = addrs[0]
}
r["host"] = port.Host
r["ipaddress"] = ip
r["container_port"] = port.ContainerPort
r["service_port"] = port.ServicePort
ret = append(ret, r)
}
}
return ret
}
func forceString(target interface{}) string {
if target == nil {
return ""
}
return target.(string)
}

View File

@ -0,0 +1,92 @@
package arukas
import (
"fmt"
"github.com/hashicorp/terraform/helper/schema"
"strings"
)
func validateMaxLength(minLength, maxLength int) schema.SchemaValidateFunc {
return func(v interface{}, k string) (ws []string, errors []error) {
value := v.(string)
if len(value) < minLength {
errors = append(errors, fmt.Errorf(
"%q cannot be shorter than %d characters: %q", k, minLength, value))
}
if len(value) > maxLength {
errors = append(errors, fmt.Errorf(
"%q cannot be longer than %d characters: %q", k, maxLength, value))
}
return
}
}
func validateIntegerInRange(min, max int) schema.SchemaValidateFunc {
return func(v interface{}, k string) (ws []string, errors []error) {
value := v.(int)
if value < min {
errors = append(errors, fmt.Errorf(
"%q cannot be lower than %d: %d", k, min, value))
}
if value > max {
errors = append(errors, fmt.Errorf(
"%q cannot be higher than %d: %d", k, max, value))
}
return
}
}
func validateStringInWord(allowWords []string) schema.SchemaValidateFunc {
return func(v interface{}, k string) (ws []string, errors []error) {
var found bool
for _, t := range allowWords {
if v.(string) == t {
found = true
}
}
if !found {
errors = append(errors, fmt.Errorf("%q must be one of [%s]", k, strings.Join(allowWords, "/")))
}
return
}
}
func validateIntInWord(allowWords []string) schema.SchemaValidateFunc {
return func(v interface{}, k string) (ws []string, errors []error) {
var found bool
for _, t := range allowWords {
if fmt.Sprintf("%d", v.(int)) == t {
found = true
}
}
if !found {
errors = append(errors, fmt.Errorf("%q must be one of [%s]", k, strings.Join(allowWords, "/")))
}
return
}
}
func validateDNSRecordValue() schema.SchemaValidateFunc {
return func(v interface{}, k string) (ws []string, errors []error) {
var rtype, value string
values := v.(map[string]interface{})
rtype = values["type"].(string)
value = values["value"].(string)
switch rtype {
case "MX", "NS", "CNAME":
if rtype == "MX" {
if values["priority"] == nil {
errors = append(errors, fmt.Errorf("%q required when TYPE was MX", k))
}
}
if !strings.HasSuffix(value, ".") {
errors = append(errors, fmt.Errorf("%q must be period at the end [%s]", k, value))
}
}
return
}
}

View File

@ -8,6 +8,7 @@ package command
import (
alicloudprovider "github.com/hashicorp/terraform/builtin/providers/alicloud"
archiveprovider "github.com/hashicorp/terraform/builtin/providers/archive"
arukasprovider "github.com/hashicorp/terraform/builtin/providers/arukas"
atlasprovider "github.com/hashicorp/terraform/builtin/providers/atlas"
awsprovider "github.com/hashicorp/terraform/builtin/providers/aws"
azureprovider "github.com/hashicorp/terraform/builtin/providers/azure"
@ -79,6 +80,7 @@ import (
var InternalProviders = map[string]plugin.ProviderFunc{
"alicloud": alicloudprovider.Provider,
"archive": archiveprovider.Provider,
"arukas": arukasprovider.Provider,
"atlas": atlasprovider.Provider,
"aws": awsprovider.Provider,
"azure": azureprovider.Provider,

61
vendor/github.com/arukasio/cli/BUILDING.md generated vendored Normal file
View File

@ -0,0 +1,61 @@
# Building Arukas CLI
This document contains details about the process for building binaries for Arukas CLI
## QuickBuild
**Please note: Replaced by your arukas token and aruaks api secret is
`YOUR_API_TOKEN` and `YOUR_API_SECRET`**
* Clone the repo: `git clone https://github.com/arukasio/cli.git`
* CLI Build: `docker build -t arukasio/arukas:patch .`
* Test execute the CLI: `docker run --rm -e ARUKAS_JSON_API_TOKEN="YOUR_API_TOKEN"
-e ARUKAS_JSON_API_SECRET="YOUR_API_SECRET" arukasio/arukas:patch`
### Godep
You can use the `godep` in order to install the external package that depends.
It will install the package versions specified in `Godeps/Godeps.json` to your `$GOPATH`
```
go get -u github.com/tools/godep
godep restore
```
## Cross Compilation and Building for Distribution
If you wish to cross-compile arukas-cli for another architecture, you can set the `XC_OS` and `XC_ARCH` environment variables to values representing the target operating system and architecture before calling `make`. The output is placed in the `pkg` subdirectory tree both expanded in a directory representing the OS/architecture combination and as a ZIP archive.
For example, to compile 64-bit Linux binaries on Mac OS X Linux, you can run:
```sh
$ XC_OS=linux XC_ARCH=amd64 make bin
...
$ file pkg/linux_amd64/arukas
arukas: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, not stripped
```
`XC_OS` and `XC_ARCH` can be space separated lists representing different combinations of operating system and architecture. For example, to compile for both Linux and Mac OS X, targeting both 32- and 64-bit architectures, you can run:
```sh
$ XC_OS="linux darwin" XC_ARCH="386 amd64" make bin
...
$ tree ./pkg/ -P "arukas|*.zip"
./pkg/
├── darwin_386
│ └── arukas
├── darwin_386.zip
├── darwin_amd64
│ └── arukas
├── darwin_amd64.zip
├── linux_386
│ └── arukas
├── linux_386.zip
├── linux_amd64
│ └── arukas
└── linux_amd64.zip
4 directories, 8 files
```
_Note: Cross-compilation uses [gox](https://github.com/mitchellh/gox), which requires toolchains to be built with versions of Go prior to 1.5. In order to successfully cross-compile with older versions of Go, you will need to run `gox -build-toolchain` before running the commands detailed above._

15
vendor/github.com/arukasio/cli/Dockerfile generated vendored Normal file
View File

@ -0,0 +1,15 @@
FROM arukasio/arukas:dev
MAINTAINER "Shuji Yamada <s-yamada@arukas.io>"
ENV REPO_ROOT $GOPATH/src/github.com/arukasio/cli
COPY . $REPO_ROOT
WORKDIR $REPO_ROOT
RUN godep restore
RUN for package in $(go list ./...| grep -v vendor); do golint ${package}; done
RUN ARUKAS_DEV=1 scripts/build.sh
WORKDIR $GOPATH
ENTRYPOINT ["bin/arukas"]

21
vendor/github.com/arukasio/cli/LICENSE.txt generated vendored Normal file
View File

@ -0,0 +1,21 @@
Copyright (C) 2015 Arukas
All Rights Reserved.
MIT LICENSE
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

71
vendor/github.com/arukasio/cli/Makefile generated vendored Normal file
View File

@ -0,0 +1,71 @@
TEST?=$$(go list ./... | grep -v /vendor/)
VETARGS?=-all
GOFMT_FILES?=$$(find . -name '*.go' | grep -v vendor)
default: vet
# bin generates the releaseable binaries for Arukas
bin: fmtcheck generate
@sh -c "'$(CURDIR)/scripts/build.sh'"
# dev creates binaries for testing Arukas locally. These are put
# into ./bin/ as well as $GOPATH/bin
dev: fmtcheck generate
@ARUKAS_DEV=1 sh -c "'$(CURDIR)/scripts/build.sh'"
quickdev: generate
@ARUKAS_QUICKDEV=1 ARUKAS_DEV=1 sh -c "'$(CURDIR)/scripts/build.sh'"
# Shorthand for quickly building the core of Arukas. Note that some
# changes will require a rebuild of everything, in which case the dev
# target should be used.
core-dev: fmtcheck generate
go install github.com/arukasio/cli
# Shorthand for quickly testing the core of Arukas (i.e. "not providers")
core-test: generate
@echo "Testing core packages..." && go test $(shell go list ./... | grep -v -E 'builtin|vendor')
# Shorthand for building and installing just one plugin for local testing.
# Run as (for example): make plugin-dev PLUGIN=provider-aws
plugin-dev: fmtcheck generate
go install github.com/hashicorp/terraform/builtin/bins/$(PLUGIN)
mv $(GOPATH)/bin/$(PLUGIN) $(GOPATH)/bin/terraform-$(PLUGIN)
# test runs the unit tests
test: fmtcheck generate
ARUKAS_ACC= go test $(TEST) $(TESTARGS) -timeout=30s -parallel=4
# testrace runs the race checker
testrace: fmtcheck generate
ARUKAS_ACC= go test -race $(TEST) $(TESTARGS)
# vet runs the Go source code static analysis tool `vet` to find
# any common errors.
vet:
@go tool vet 2>/dev/null ; if [ $$? -eq 3 ]; then \
go get golang.org/x/tools/cmd/vet; \
fi
@echo "go tool vet $(VETARGS) ."
@go tool vet $(VETARGS) $$(ls -d */ | grep -v vendor) ; if [ $$? -eq 1 ]; then \
echo ""; \
echo "Vet found suspicious constructs. Please check the reported constructs"; \
echo "and fix them if necessary before submitting the code for review."; \
exit 1; \
fi
# generate runs `go generate` to build the dynamically generated
# source files.
generate:
@which stringer ; if [ $$? -ne 0 ]; then \
go get -u golang.org/x/tools/cmd/stringer; \
fi
go generate $$(go list ./... | grep -v /vendor/)
fmt:
gofmt -w $(GOFMT_FILES)
fmtcheck:
@sh -c "'$(CURDIR)/scripts/gofmtcheck.sh'"
.PHONY: bin default generate test updatedeps vet fmt fmtcheck

37
vendor/github.com/arukasio/cli/README.md generated vendored Normal file
View File

@ -0,0 +1,37 @@
<img src="https://app.arukas.io/images/logo-orca.svg" alt="" width="100" /> Arukas CLI
==========
[![Circle CI](https://circleci.com/gh/arukasio/cli.svg?style=shield)](https://circleci.com/gh/arukasio/cli)
The Arukas CLI is used to manage Arukas apps from the command line.
* Website: https://arukas.io
### Binary Releases
The official binary of Arukas CLI: https://github.com/arukasio/cli/releases/
### Dockerized
A dockerized version of Arukas CLI: https://hub.docker.com/r/arukasio/arukas/
## Setup
* Get API key here: https://app.arukas.io/settings/api-keys
* Edit it `.env` file
You can overload and customize specific variables when running scripts.
Simply create `.env` with the environment variables you need,
for example, `ARUKAS_JSON_API_TOKEN` and `ARUKAS_JSON_API_SECRET`
```
# .env
ARUKAS_JSON_API_TOKEN=YOUR_API_TOKEN
ARUKAS_JSON_API_SECRET=YOUR_API_SECRET
```
You can look at `.env.sample` for other variables used by this application.
## License
This project is licensed under the terms of the MIT license.

65
vendor/github.com/arukasio/cli/Vagrantfile generated vendored Normal file
View File

@ -0,0 +1,65 @@
# -*- mode: ruby -*-
# vi: set ft=ruby :
# Vagrantfile API/syntax version. Don't touch unless you know what you're doing!
VAGRANTFILE_API_VERSION = "2"
$script = <<SCRIPT
GOVERSION="1.5.2"
SRCROOT="/opt/go"
SRCPATH="/opt/gopath"
# Get the ARCH
ARCH=`uname -m | sed 's|i686|386|' | sed 's|x86_64|amd64|'`
# Install Prereq Packages
sudo apt-get update
sudo apt-get upgrade -y
sudo apt-get install -y build-essential curl git-core libpcre3-dev mercurial pkg-config zip tree shellcheck
# Install Go
cd /tmp
wget --quiet https://storage.googleapis.com/golang/go${GOVERSION}.linux-${ARCH}.tar.gz
tar -xvf go${GOVERSION}.linux-${ARCH}.tar.gz
sudo mv go $SRCROOT
sudo chmod 775 $SRCROOT
sudo chown vagrant:vagrant $SRCROOT
# Setup the GOPATH; even though the shared folder spec gives the working
# directory the right user/group, we need to set it properly on the
# parent path to allow subsequent "go get" commands to work.
sudo mkdir -p $SRCPATH
sudo chown -R vagrant:vagrant $SRCPATH 2>/dev/null || true
# ^^ silencing errors here because we expect this to fail for the shared folder
cat <<EOF >/tmp/gopath.sh
export GOPATH="$SRCPATH"
export GOROOT="$SRCROOT"
export PATH="$SRCROOT/bin:$SRCPATH/bin:\$PATH"
export GO15VENDOREXPERIMENT=1
EOF
sudo mv /tmp/gopath.sh /etc/profile.d/gopath.sh
sudo chmod 0755 /etc/profile.d/gopath.sh
source /etc/profile.d/gopath.sh
SCRIPT
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
config.vm.box = "bento/ubuntu-14.04"
config.vm.hostname = "cli"
config.vm.provision "shell", inline: $script, privileged: false
config.vm.synced_folder '.', '/opt/gopath/src/github.com/arukasio/cli'
["vmware_fusion", "vmware_workstation"].each do |p|
config.vm.provider p do |v|
v.vmx["memsize"] = "1024"
v.vmx["numvcpus"] = "2"
end
end
config.vm.provider "virtualbox" do |v|
v.memory = 2048
v.cpus = 2
end
end

114
vendor/github.com/arukasio/cli/app_sets.go generated vendored Normal file
View File

@ -0,0 +1,114 @@
package arukas
import (
"encoding/json"
"github.com/manyminds/api2go/jsonapi"
)
// TmpJSON Contain JSON data.
type TmpJSON struct {
Data []map[string]interface{} `json:"data"`
Meta map[string]interface{} `json:"-"`
}
// AppSet represents a application data in struct variables.
type AppSet struct {
App App
Container Container
}
// MarshalJSON returns as as the JSON encoding of as.
func (as AppSet) MarshalJSON() ([]byte, error) {
var (
app []byte
appJSON map[string]map[string]interface{}
container []byte
containerJSON map[string]map[string]interface{}
marshaled []byte
err error
)
if app, err = jsonapi.Marshal(as.App); err != nil {
return nil, err
}
if err = json.Unmarshal(app, &appJSON); err != nil {
return nil, err
}
if container, err = jsonapi.Marshal(as.Container); err != nil {
return nil, err
}
if err = json.Unmarshal(container, &containerJSON); err != nil {
return nil, err
}
data := map[string][]map[string]interface{}{
"data": []map[string]interface{}{
appJSON["data"],
containerJSON["data"],
},
}
if marshaled, err = json.Marshal(data); err != nil {
return nil, err
}
return marshaled, nil
}
// SelectResources returns the type filter value of TmpJSON.
func SelectResources(data TmpJSON, resourceType string) map[string][]map[string]interface{} {
var resources []map[string]interface{}
// resources := make([]map[string]interface{}, 0)
for _, v := range data.Data {
if v["type"] == resourceType {
resources = append(resources, v)
}
}
filtered := map[string][]map[string]interface{}{
"data": resources,
}
return filtered
}
// UnmarshalJSON sets *as to a copy of data.
func (as *AppSet) UnmarshalJSON(bytes []byte) error {
var (
appBytes []byte
containerBytes []byte
err error
data TmpJSON
)
if err = json.Unmarshal(bytes, &data); err != nil {
return err
}
apps := SelectResources(data, "apps")
containers := SelectResources(data, "containers")
if appBytes, err = json.Marshal(apps); err != nil {
return err
}
if containerBytes, err = json.Marshal(containers); err != nil {
return err
}
var parsedApps []App
if err = jsonapi.Unmarshal(appBytes, &parsedApps); err != nil {
return err
}
var parsedContainers []Container
if err = jsonapi.Unmarshal(containerBytes, &parsedContainers); err != nil {
return err
}
as.App = parsedApps[0]
as.Container = parsedContainers[0]
return nil
}

51
vendor/github.com/arukasio/cli/apps.go generated vendored Normal file
View File

@ -0,0 +1,51 @@
package arukas
import (
"errors"
"time"
)
// App represents a application data in struct variables.
type App struct {
ID string `json:"-"`
Name string `json:"name"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"-"`
ContainerID string `json:"-"`
Container *Container `json:"-"`
User *User `json:"-"`
}
// GetID returns a stringified of an ID.
func (a App) GetID() string {
return string(a.ID)
}
// SetID to satisfy jsonapi.UnmarshalIdentifier interface.
func (a *App) SetID(ID string) error {
a.ID = ID
return nil
}
// SetToOneReferenceID sets the reference ID and satisfies the jsonapi.UnmarshalToOneRelations interface
func (a *App) SetToOneReferenceID(name, ID string) error {
if name == "container" {
if ID == "" {
a.Container = nil
} else {
a.Container = &Container{ID: ID}
}
return nil
} else if name == "user" {
if ID == "" {
a.User = nil
} else {
a.User = &User{ID: ID}
}
return nil
}
return errors.New("There is no to-one relationship with the name " + name)
}

36
vendor/github.com/arukasio/cli/circle.yml generated vendored Normal file
View File

@ -0,0 +1,36 @@
machine:
environment:
GODIST: "go1.7.3.linux-amd64.tar.gz"
GOPATH: /home/ubuntu/.go_workspace
ARUKAS_JSON_API_SECRET: PASSWORD
ARUKAS_JSON_API_TOKEN: USER
REPO_ROOT: /home/ubuntu/.go_workspace/src/github.com/arukasio/cli
dependencies:
cache_directories:
- /home/ubuntu/.go_workspace
pre:
- if [[ ! -e /home/ubuntu/go/bin/go ]]; then cd /home/ubuntu; curl https://storage.googleapis.com/golang/${GODIST} | tar -xz; fi
- sudo rm -rf /usr/local/go
- sudo mv /home/ubuntu/go /usr/local/go
- go get -u github.com/tools/godep
- go get -u github.com/golang/lint/golint
override:
- mkdir -p ${REPO_ROOT}
- rsync -azC --delete ./ ${REPO_ROOT}
test:
pre:
- cd ${REPO_ROOT} && godep restore
override:
- cd ${REPO_ROOT} && make test vet
- cd ${REPO_ROOT} && for package in `go list ./...| grep -v vendor`; do golint ${package}; done
- cd ${REPO_ROOT} && godep go test -cover -bench -benchmem `go list ./... | grep -v /vendor/` -v
deployment:
release:
tag: /v[0-9]+(\.[0-9]+)*/
commands:
- cd ${REPO_ROOT} && CGO_ENABLED=0 XC_OS="linux darwin windows" XC_ARCH="amd64" make bin
- cd ${REPO_ROOT} && test "${CIRCLE_TAG}" == "$(arukas version)"
- cd ${REPO_ROOT} && bash ./scripts/dist.sh "$(arukas version)"

324
vendor/github.com/arukasio/cli/client.go generated vendored Normal file
View File

@ -0,0 +1,324 @@
package arukas
import (
"bytes"
"encoding/json"
"errors"
"fmt"
"github.com/manyminds/api2go/jsonapi"
"io"
"io/ioutil"
"log"
"net/http"
"net/url"
"os"
"reflect"
"sort"
"strings"
"time"
)
// VERSION is cli version.
const VERSION = "v0.1.3"
// Client represents a user client data in struct variables.
type Client struct {
APIURL *url.URL
HTTP *http.Client
Username string
Password string
UserAgent string
Debug bool
Output func(...interface{})
OutputDest io.Writer
Timeout time.Duration
}
var (
client *Client
)
// PrintHeaderln print as the values.
func (c *Client) PrintHeaderln(values ...interface{}) {
fmt.Fprint(c.OutputDest, ToTSV(values[1:]), "\n")
}
// Println print as the values.
func (c *Client) Println(values ...interface{}) {
fmt.Fprint(c.OutputDest, ToTSV(values[1:]), "\n")
}
// Get return *c as the get path of API request.
func (c *Client) Get(v interface{}, path string) error {
return c.APIReq(v, "GET", path, nil)
}
// Patch return *c as the patch path of API request.
func (c *Client) Patch(v interface{}, path string, body interface{}) error {
return c.APIReq(v, "PATCH", path, body)
}
// Post return *c as the post path of API request.
func (c *Client) Post(v interface{}, path string, body interface{}) error {
return c.APIReq(v, "POST", path, body)
}
// Put return *c as the put path of API request.
func (c *Client) Put(v interface{}, path string, body interface{}) error {
return c.APIReq(v, "PUT", path, body)
}
// Delete return *c as the delete path of API request.
func (c *Client) Delete(path string) error {
return c.APIReq(nil, "DELETE", path, nil)
}
// NewClientWithOsExitOnErr return client.
func NewClientWithOsExitOnErr() *Client {
client, err := NewClient()
if err != nil {
log.Fatal(err)
}
return client
}
// NewClient returns a new arukas client, requires an authorization key.
// You can generate a API key by visiting the Keys section of the Arukas
// control panel for your account.
func NewClient() (*Client, error) {
debug := false
if os.Getenv("ARUKAS_DEBUG") != "" {
debug = true
}
apiURL := "https://app.arukas.io/api/"
if os.Getenv("ARUKAS_JSON_API_URL") != "" {
apiURL = os.Getenv("ARUKAS_JSON_API_URL")
}
client := new(Client)
parsedURL, err := url.Parse(apiURL)
if err != nil {
fmt.Println("url err")
return nil, err
}
parsedURL.Path = strings.TrimRight(parsedURL.Path, "/")
client.APIURL = parsedURL
client.UserAgent = "Arukas CLI (" + VERSION + ")"
client.Debug = debug
client.OutputDest = os.Stdout
client.Timeout = 30 * time.Second
if username := os.Getenv("ARUKAS_JSON_API_TOKEN"); username != "" {
client.Username = username
} else {
return nil, errors.New("ARUKAS_JSON_API_TOKEN is not set")
}
if password := os.Getenv("ARUKAS_JSON_API_SECRET"); password != "" {
client.Password = password
} else {
return nil, errors.New("ARUKAS_JSON_API_SECRET is not set")
}
return client, nil
}
// NewRequest Generates an HTTP request for the Arukas API, but does not
// perform the request. The request's Accept header field will be
// set to:
//
// Accept: application/vnd.api+json;
//
// The type of body determines how to encode the request:
//
// nil no body
// io.Reader body is sent verbatim
// []byte body is encoded as application/vnd.api+json
// else body is encoded as application/json
func (c *Client) NewRequest(method, path string, body interface{}) (*http.Request, error) {
var ctype string
var rbody io.Reader
switch t := body.(type) {
case nil:
case string:
rbody = bytes.NewBufferString(t)
case io.Reader:
rbody = t
case []byte:
rbody = bytes.NewReader(t)
ctype = "application/vnd.api+json"
default:
v := reflect.ValueOf(body)
if !v.IsValid() {
break
}
if v.Type().Kind() == reflect.Ptr {
v = reflect.Indirect(v)
if !v.IsValid() {
break
}
}
j, err := json.Marshal(body)
if err != nil {
return nil, err
}
rbody = bytes.NewReader(j)
ctype = "application/json"
}
requestURL := *c.APIURL // shallow copy
requestURL.Path += path
if c.Debug {
fmt.Printf("Requesting: %s %s %s\n", method, requestURL, rbody)
}
req, err := http.NewRequest(method, requestURL.String(), rbody)
if err != nil {
return nil, err
}
req.Header.Set("Accept", "application/vnd.api+json")
req.Header.Set("User-Agent", c.UserAgent)
if ctype != "" {
req.Header.Set("Content-Type", ctype)
}
req.SetBasicAuth(c.Username, c.Password)
return req, nil
}
// APIReq Sends a Arukas API request and decodes the response into v.
// As described in NewRequest(), the type of body determines how to
// encode the request body. As described in DoReq(), the type of
// v determines how to handle the response body.
func (c *Client) APIReq(v interface{}, method, path string, body interface{}) error {
var marshaled []byte
var err1 error
var req *http.Request
if body != nil {
var err error
_, ok := body.(jsonapi.MarshalIdentifier)
if ok {
marshaled, err = jsonapi.Marshal(body)
} else {
marshaled, err = json.Marshal(body)
}
if err != nil {
return err
}
if c.Debug {
fmt.Println("json: ", string(marshaled))
}
req, err1 = c.NewRequest(method, path, marshaled)
} else {
req, err1 = c.NewRequest(method, path, body)
}
if err1 != nil {
return err1
}
return c.DoReq(req, v)
}
// DoReq Submits an HTTP request, checks its response, and deserializes
// the response into v. The type of v determines how to handle
// the response body:
//
// nil body is discarded
// io.Writer body is copied directly into v
// else body is decoded into v as json
//
func (c *Client) DoReq(req *http.Request, v interface{}) error {
httpClient := c.HTTP
if httpClient == nil {
httpClient = &http.Client{
Timeout: c.Timeout,
}
}
res, err := httpClient.Do(req)
if err != nil {
return err
}
defer res.Body.Close()
body, err := ioutil.ReadAll(res.Body)
if c.Debug {
fmt.Println("Status:", res.StatusCode)
headers := make([]string, len(res.Header))
for k := range res.Header {
headers = append(headers, k)
}
sort.Strings(headers)
for _, k := range headers {
if k != "" {
fmt.Println(k+":", strings.Join(res.Header[k], " "))
}
}
fmt.Println(string(body))
}
if err = checkResponse(res); err != nil {
return err
}
switch t := v.(type) {
case nil:
case io.Writer:
_, err = io.Copy(t, res.Body)
default:
err = jsonapi.Unmarshal(body, v)
if err != nil {
err = json.Unmarshal(body, v)
}
}
return err
}
// CheckResponse returns an error (of type *Error) if the response.
func checkResponse(res *http.Response) error {
if res.StatusCode == 404 {
return fmt.Errorf("The resource does not found on the server: %s", res.Request.URL)
} else if res.StatusCode >= 400 {
return fmt.Errorf("Got HTTP status code >= 400: %s", res.Status)
}
return nil
}
// PrintTsvln print Tab-separated values line.
func PrintTsvln(values ...interface{}) {
fmt.Println(ToTSV(values))
}
// ToTSV return Tab-separated values.
func ToTSV(values []interface{}) string {
var str []string
for _, s := range values {
if v, ok := s.(string); ok {
str = append(str, string(v))
} else {
str = append(str, fmt.Sprint(s))
}
}
return strings.Join(str, "\t")
}
// SplitTSV return splited Tab-separated values.
func SplitTSV(str string) []string {
splitStr := strings.Split(str, "\t")
var trimmed []string
for _, v := range splitStr {
trimmed = append(trimmed, strings.Trim(v, "\n"))
}
return trimmed
}
// removeFirstLine is remove first line.
func removeFirstLine(str string) string {
lines := strings.Split(str, "\n")
return strings.Join(lines[1:], "\n")
}

144
vendor/github.com/arukasio/cli/container.go generated vendored Normal file
View File

@ -0,0 +1,144 @@
package arukas
import (
"errors"
"fmt"
"github.com/manyminds/api2go/jsonapi"
"strconv"
"strings"
"time"
)
// PortMapping represents a docker container port mapping in struct variables.
type PortMapping struct {
ContainerPort int `json:"container_port"`
ServicePort int `json:"service_port"`
Host string `json:"host"`
}
// TaskPorts is Multiple PortMapping.
type TaskPorts []PortMapping
// PortMappings is multiple TaskPorts.
type PortMappings []TaskPorts
// Env represents a docker container environment key-value in struct variables.
type Env struct {
Key string `json:"key"`
Value string `json:"value"`
}
// Envs is multiple Env.
type Envs []Env
// Port represents a docker protocol and port-number in struct variables.
type Port struct {
Protocol string `json:"protocol"`
Number int `json:"number"`
}
// Ports is multiple Port.
type Ports []Port
// Container represents a docker container data in struct variables.
type Container struct {
Envs Envs `json:"envs"`
Ports Ports `json:"ports"`
PortMappings PortMappings `json:"port_mappings,omitempty"`
StatusText string `json:"status_text,omitempty"`
ID string
ImageName string `json:"image_name"`
CreatedAt JSONTime `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
App *App
Mem int `json:"mem"`
AppID string `json:"app_id"`
Instances int `json:"instances"`
IsRunning bool `json:"is_running,omitempty"`
Cmd string `json:"cmd"`
Name string `json:"name"`
Endpoint string `json:"end_point,omitempty"`
}
// GetID returns a stringified of an ID.
func (c Container) GetID() string {
return string(c.ID)
}
// SetID to satisfy jsonapi.UnmarshalIdentifier interface.
func (c *Container) SetID(ID string) error {
c.ID = ID
return nil
}
// GetReferences returns all related structs to transactions.
func (c Container) GetReferences() []jsonapi.Reference {
return []jsonapi.Reference{
{
Type: "apps",
Name: "app",
},
}
}
// GetReferencedIDs satisfies the jsonapi.MarshalLinkedRelations interface.
func (c Container) GetReferencedIDs() []jsonapi.ReferenceID {
result := []jsonapi.ReferenceID{}
if c.AppID != "" {
result = append(result, jsonapi.ReferenceID{ID: c.AppID, Name: "app", Type: "apps"})
}
return result
}
// GetReferencedStructs to satisfy the jsonapi.MarhsalIncludedRelations interface.
func (c Container) GetReferencedStructs() []jsonapi.MarshalIdentifier {
result := []jsonapi.MarshalIdentifier{}
if c.App != nil {
result = append(result, c.App)
}
return result
}
// SetToOneReferenceID sets the reference ID and satisfies the jsonapi.UnmarshalToOneRelations interface.
func (c *Container) SetToOneReferenceID(name, ID string) error {
if name == "app" {
if ID == "" {
c.App = nil
} else {
c.App = &App{ID: ID}
}
return nil
}
return errors.New("There is no to-one relationship with the name " + name)
}
// ParseEnv parse docker container envs.
func ParseEnv(envs []string) (Envs, error) {
var parsedEnvs Envs
for _, env := range envs {
kv := strings.Split(env, "=")
parsedEnvs = append(parsedEnvs, Env{Key: kv[0], Value: kv[1]})
}
return parsedEnvs, nil
}
// ParsePort parse docker container ports.
func ParsePort(ports []string) (Ports, error) {
var parsedPorts Ports
for _, port := range ports {
kv := strings.Split(port, ":")
num, err := strconv.Atoi(kv[0])
if err != nil {
return nil, fmt.Errorf("Port number must be numeric. Given: %s", kv[0])
}
if !(kv[1] == "tcp" || kv[1] == "udp") {
return nil, fmt.Errorf("Port protocol must be \"tcp\" or \"udp\"")
}
parsedPorts = append(parsedPorts, Port{Number: num, Protocol: kv[1]})
}
return parsedPorts, nil
}

35
vendor/github.com/arukasio/cli/json_time.go generated vendored Normal file
View File

@ -0,0 +1,35 @@
package arukas
import (
"fmt"
"time"
)
// JSONTime is time.Time that serializes as unix timestamp (in microseconds).
type JSONTime time.Time
// UnmarshalJSON sets *t to a copy of data.
func (t *JSONTime) UnmarshalJSON(data []byte) (err error) {
parsed, err := time.Parse(`"`+time.RFC3339Nano+`"`, string(data))
if err != nil {
return err
}
*t = JSONTime(parsed)
return
}
// MarshalJSON returns t as the JSON encoding of t.
func (t JSONTime) MarshalJSON() ([]byte, error) {
stamp := fmt.Sprintf("\"%s\"", time.Time(t).Format(time.RFC3339Nano))
return []byte(stamp), nil
}
// String return t as the string of t.
func (t JSONTime) String() string {
return time.Time(t).Format(time.RFC3339Nano)
}
// Time return t as the time of t.
func (t JSONTime) Time() time.Time {
return time.Time(t)
}

32
vendor/github.com/arukasio/cli/user.go generated vendored Normal file
View File

@ -0,0 +1,32 @@
package arukas
import (
// "errors"
// "fmt"
// "github.com/codegangsta/cli"
// "os"
"time"
)
// User represents a user data in struct variables.
type User struct {
ID string `json:"-"` // user id
Name string `json:"name"` // user name
Email string `json:"email"` // user e-mail
Provider string `json:"provider"` // user oAuth provider
ImageURL string `json:"image_url"` // user profile image
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
ConfirmedAt time.Time `json:"-"`
}
// GetID returns a stringified of an ID.
func (u User) GetID() string {
return string(u.ID)
}
// SetID to satisfy jsonapi.UnmarshalIdentifier interface.
func (u *User) SetID(ID string) error {
u.ID = ID
return nil
}

28
vendor/github.com/gedex/inflector/CakePHP_LICENSE.txt generated vendored Normal file
View File

@ -0,0 +1,28 @@
The MIT License
CakePHP(tm) : The Rapid Development PHP Framework (http://cakephp.org)
Copyright (c) 2005-2013, Cake Software Foundation, Inc.
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
Cake Software Foundation, Inc.
1785 E. Sahara Avenue,
Suite 490-204
Las Vegas, Nevada 89104,
United States of America.

29
vendor/github.com/gedex/inflector/LICENSE.md generated vendored Normal file
View File

@ -0,0 +1,29 @@
Copyright (c) 2013 Akeda Bagus <admin@gedex.web.id>. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
----------
Much of this library was inspired from CakePHP's inflector, a PHP
framework licensed under MIT license (see CakePHP_LICENSE.txt).

25
vendor/github.com/gedex/inflector/README.md generated vendored Normal file
View File

@ -0,0 +1,25 @@
Inflector
=========
Inflector pluralizes and singularizes English nouns.
[![Build Status](https://travis-ci.org/gedex/inflector.png?branch=master)](https://travis-ci.org/gedex/inflector)
[![Coverage Status](https://coveralls.io/repos/gedex/inflector/badge.png?branch=master)](https://coveralls.io/r/gedex/inflector?branch=master)
[![GoDoc](https://godoc.org/github.com/gedex/inflector?status.svg)](https://godoc.org/github.com/gedex/inflector)
## Basic Usage
There are only two exported functions: `Pluralize` and `Singularize`.
~~~go
fmt.Println(inflector.Singularize("People")) // will print "Person"
fmt.Println(inflector.Pluralize("octopus")) // will print "octopuses"
~~~
## Credits
* [CakePHP's Inflector](https://github.com/cakephp/cakephp/blob/master/lib/Cake/Utility/Inflector.php)
## License
This library is distributed under the BSD-style license found in the LICENSE.md file.

355
vendor/github.com/gedex/inflector/inflector.go generated vendored Normal file
View File

@ -0,0 +1,355 @@
// Copyright 2013 Akeda Bagus <admin@gedex.web.id>. All rights reserved.
//
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
/*
Package inflector pluralizes and singularizes English nouns.
There are only two exported functions: `Pluralize` and `Singularize`.
s := "People"
fmt.Println(inflector.Singularize(s)) // will print "Person"
s2 := "octopus"
fmt.Println(inflector.Pluralize(s2)) // will print "octopuses"
*/
package inflector
import (
"bytes"
"fmt"
"regexp"
"strings"
"sync"
)
// Rule represents name of the inflector rule, can be
// Plural or Singular
type Rule int
const (
Plural = iota
Singular
)
// InflectorRule represents inflector rule
type InflectorRule struct {
Rules []*ruleItem
Irregular []*irregularItem
Uninflected []string
compiledIrregular *regexp.Regexp
compiledUninflected *regexp.Regexp
compiledRules []*compiledRule
}
type ruleItem struct {
pattern string
replacement string
}
type irregularItem struct {
word string
replacement string
}
// compiledRule represents compiled version of Inflector.Rules.
type compiledRule struct {
replacement string
*regexp.Regexp
}
// threadsafe access to rules and caches
var mutex sync.Mutex
var rules = make(map[Rule]*InflectorRule)
// Words that should not be inflected
var uninflected = []string{
`Amoyese`, `bison`, `Borghese`, `bream`, `breeches`, `britches`, `buffalo`,
`cantus`, `carp`, `chassis`, `clippers`, `cod`, `coitus`, `Congoese`,
`contretemps`, `corps`, `debris`, `diabetes`, `djinn`, `eland`, `elk`,
`equipment`, `Faroese`, `flounder`, `Foochowese`, `gallows`, `Genevese`,
`Genoese`, `Gilbertese`, `graffiti`, `headquarters`, `herpes`, `hijinks`,
`Hottentotese`, `information`, `innings`, `jackanapes`, `Kiplingese`,
`Kongoese`, `Lucchese`, `mackerel`, `Maltese`, `.*?media`, `mews`, `moose`,
`mumps`, `Nankingese`, `news`, `nexus`, `Niasese`, `Pekingese`,
`Piedmontese`, `pincers`, `Pistoiese`, `pliers`, `Portuguese`, `proceedings`,
`rabies`, `rice`, `rhinoceros`, `salmon`, `Sarawakese`, `scissors`,
`sea[- ]bass`, `series`, `Shavese`, `shears`, `siemens`, `species`, `swine`,
`testes`, `trousers`, `trout`, `tuna`, `Vermontese`, `Wenchowese`, `whiting`,
`wildebeest`, `Yengeese`,
}
// Plural words that should not be inflected
var uninflectedPlurals = []string{
`.*[nrlm]ese`, `.*deer`, `.*fish`, `.*measles`, `.*ois`, `.*pox`, `.*sheep`,
`people`,
}
// Singular words that should not be inflected
var uninflectedSingulars = []string{
`.*[nrlm]ese`, `.*deer`, `.*fish`, `.*measles`, `.*ois`, `.*pox`, `.*sheep`,
`.*ss`,
}
type cache map[string]string
// Inflected words that already cached for immediate retrieval from a given Rule
var caches = make(map[Rule]cache)
// map of irregular words where its key is a word and its value is the replacement
var irregularMaps = make(map[Rule]cache)
func init() {
rules[Plural] = &InflectorRule{
Rules: []*ruleItem{
{`(?i)(s)tatus$`, `${1}${2}tatuses`},
{`(?i)(quiz)$`, `${1}zes`},
{`(?i)^(ox)$`, `${1}${2}en`},
{`(?i)([m|l])ouse$`, `${1}ice`},
{`(?i)(matr|vert|ind)(ix|ex)$`, `${1}ices`},
{`(?i)(x|ch|ss|sh)$`, `${1}es`},
{`(?i)([^aeiouy]|qu)y$`, `${1}ies`},
{`(?i)(hive)$`, `$1s`},
{`(?i)(?:([^f])fe|([lre])f)$`, `${1}${2}ves`},
{`(?i)sis$`, `ses`},
{`(?i)([ti])um$`, `${1}a`},
{`(?i)(p)erson$`, `${1}eople`},
{`(?i)(m)an$`, `${1}en`},
{`(?i)(c)hild$`, `${1}hildren`},
{`(?i)(buffal|tomat)o$`, `${1}${2}oes`},
{`(?i)(alumn|bacill|cact|foc|fung|nucle|radi|stimul|syllab|termin|vir)us$`, `${1}i`},
{`(?i)us$`, `uses`},
{`(?i)(alias)$`, `${1}es`},
{`(?i)(ax|cris|test)is$`, `${1}es`},
{`s$`, `s`},
{`^$`, ``},
{`$`, `s`},
},
Irregular: []*irregularItem{
{`atlas`, `atlases`},
{`beef`, `beefs`},
{`brother`, `brothers`},
{`cafe`, `cafes`},
{`child`, `children`},
{`cookie`, `cookies`},
{`corpus`, `corpuses`},
{`cow`, `cows`},
{`ganglion`, `ganglions`},
{`genie`, `genies`},
{`genus`, `genera`},
{`graffito`, `graffiti`},
{`hoof`, `hoofs`},
{`loaf`, `loaves`},
{`man`, `men`},
{`money`, `monies`},
{`mongoose`, `mongooses`},
{`move`, `moves`},
{`mythos`, `mythoi`},
{`niche`, `niches`},
{`numen`, `numina`},
{`occiput`, `occiputs`},
{`octopus`, `octopuses`},
{`opus`, `opuses`},
{`ox`, `oxen`},
{`penis`, `penises`},
{`person`, `people`},
{`sex`, `sexes`},
{`soliloquy`, `soliloquies`},
{`testis`, `testes`},
{`trilby`, `trilbys`},
{`turf`, `turfs`},
{`potato`, `potatoes`},
{`hero`, `heroes`},
{`tooth`, `teeth`},
{`goose`, `geese`},
{`foot`, `feet`},
},
}
prepare(Plural)
rules[Singular] = &InflectorRule{
Rules: []*ruleItem{
{`(?i)(s)tatuses$`, `${1}${2}tatus`},
{`(?i)^(.*)(menu)s$`, `${1}${2}`},
{`(?i)(quiz)zes$`, `$1`},
{`(?i)(matr)ices$`, `${1}ix`},
{`(?i)(vert|ind)ices$`, `${1}ex`},
{`(?i)^(ox)en`, `$1`},
{`(?i)(alias)(es)*$`, `$1`},
{`(?i)(alumn|bacill|cact|foc|fung|nucle|radi|stimul|syllab|termin|viri?)i$`, `${1}us`},
{`(?i)([ftw]ax)es`, `$1`},
{`(?i)(cris|ax|test)es$`, `${1}is`},
{`(?i)(shoe|slave)s$`, `$1`},
{`(?i)(o)es$`, `$1`},
{`ouses$`, `ouse`},
{`([^a])uses$`, `${1}us`},
{`(?i)([m|l])ice$`, `${1}ouse`},
{`(?i)(x|ch|ss|sh)es$`, `$1`},
{`(?i)(m)ovies$`, `${1}${2}ovie`},
{`(?i)(s)eries$`, `${1}${2}eries`},
{`(?i)([^aeiouy]|qu)ies$`, `${1}y`},
{`(?i)(tive)s$`, `$1`},
{`(?i)([lre])ves$`, `${1}f`},
{`(?i)([^fo])ves$`, `${1}fe`},
{`(?i)(hive)s$`, `$1`},
{`(?i)(drive)s$`, `$1`},
{`(?i)(^analy)ses$`, `${1}sis`},
{`(?i)(analy|diagno|^ba|(p)arenthe|(p)rogno|(s)ynop|(t)he)ses$`, `${1}${2}sis`},
{`(?i)([ti])a$`, `${1}um`},
{`(?i)(p)eople$`, `${1}${2}erson`},
{`(?i)(m)en$`, `${1}an`},
{`(?i)(c)hildren$`, `${1}${2}hild`},
{`(?i)(n)ews$`, `${1}${2}ews`},
{`eaus$`, `eau`},
{`^(.*us)$`, `$1`},
{`(?i)s$`, ``},
},
Irregular: []*irregularItem{
{`foes`, `foe`},
{`waves`, `wave`},
{`curves`, `curve`},
{`atlases`, `atlas`},
{`beefs`, `beef`},
{`brothers`, `brother`},
{`cafes`, `cafe`},
{`children`, `child`},
{`cookies`, `cookie`},
{`corpuses`, `corpus`},
{`cows`, `cow`},
{`ganglions`, `ganglion`},
{`genies`, `genie`},
{`genera`, `genus`},
{`graffiti`, `graffito`},
{`hoofs`, `hoof`},
{`loaves`, `loaf`},
{`men`, `man`},
{`monies`, `money`},
{`mongooses`, `mongoose`},
{`moves`, `move`},
{`mythoi`, `mythos`},
{`niches`, `niche`},
{`numina`, `numen`},
{`occiputs`, `occiput`},
{`octopuses`, `octopus`},
{`opuses`, `opus`},
{`oxen`, `ox`},
{`penises`, `penis`},
{`people`, `person`},
{`sexes`, `sex`},
{`soliloquies`, `soliloquy`},
{`testes`, `testis`},
{`trilbys`, `trilby`},
{`turfs`, `turf`},
{`potatoes`, `potato`},
{`heroes`, `hero`},
{`teeth`, `tooth`},
{`geese`, `goose`},
{`feet`, `foot`},
},
}
prepare(Singular)
}
// prepare rule, e.g., compile the pattern.
func prepare(r Rule) error {
var reString string
switch r {
case Plural:
// Merge global uninflected with singularsUninflected
rules[r].Uninflected = merge(uninflected, uninflectedPlurals)
case Singular:
// Merge global uninflected with singularsUninflected
rules[r].Uninflected = merge(uninflected, uninflectedSingulars)
}
// Set InflectorRule.compiledUninflected by joining InflectorRule.Uninflected into
// a single string then compile it.
reString = fmt.Sprintf(`(?i)(^(?:%s))$`, strings.Join(rules[r].Uninflected, `|`))
rules[r].compiledUninflected = regexp.MustCompile(reString)
// Prepare irregularMaps
irregularMaps[r] = make(cache, len(rules[r].Irregular))
// Set InflectorRule.compiledIrregular by joining the irregularItem.word of Inflector.Irregular
// into a single string then compile it.
vIrregulars := make([]string, len(rules[r].Irregular))
for i, item := range rules[r].Irregular {
vIrregulars[i] = item.word
irregularMaps[r][item.word] = item.replacement
}
reString = fmt.Sprintf(`(?i)(.*)\b((?:%s))$`, strings.Join(vIrregulars, `|`))
rules[r].compiledIrregular = regexp.MustCompile(reString)
// Compile all patterns in InflectorRule.Rules
rules[r].compiledRules = make([]*compiledRule, len(rules[r].Rules))
for i, item := range rules[r].Rules {
rules[r].compiledRules[i] = &compiledRule{item.replacement, regexp.MustCompile(item.pattern)}
}
// Prepare caches
caches[r] = make(cache)
return nil
}
// merge slice a and slice b
func merge(a []string, b []string) []string {
result := make([]string, len(a)+len(b))
copy(result, a)
copy(result[len(a):], b)
return result
}
// Pluralize returns string s in plural form.
func Pluralize(s string) string {
return getInflected(Plural, s)
}
// Singularize returns string s in singular form.
func Singularize(s string) string {
return getInflected(Singular, s)
}
func getInflected(r Rule, s string) string {
mutex.Lock()
defer mutex.Unlock()
if v, ok := caches[r][s]; ok {
return v
}
// Check for irregular words
if res := rules[r].compiledIrregular.FindStringSubmatch(s); len(res) >= 3 {
var buf bytes.Buffer
buf.WriteString(res[1])
buf.WriteString(s[0:1])
buf.WriteString(irregularMaps[r][strings.ToLower(res[2])][1:])
// Cache it then returns
caches[r][s] = buf.String()
return caches[r][s]
}
// Check for uninflected words
if rules[r].compiledUninflected.MatchString(s) {
caches[r][s] = s
return caches[r][s]
}
// Check each rule
for _, re := range rules[r].compiledRules {
if re.MatchString(s) {
caches[r][s] = re.ReplaceAllString(s, re.replacement)
return caches[r][s]
}
}
// Returns unaltered
caches[r][s] = s
return caches[r][s]
}

21
vendor/github.com/manyminds/api2go/LICENSE generated vendored Normal file
View File

@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2015 manyminds
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

14
vendor/github.com/manyminds/api2go/jsonapi/Readme.md generated vendored Normal file
View File

@ -0,0 +1,14 @@
# api2go JSONAPI package
This package contains [JSON API](http://jsonapi.org) compatible
marshal und unmarshal functionality.
```
go get github.com/manyminds/api2go/jsonapi
```
## Usage
For information on how to use this package, please refer to the
documentation on the [api2go](https://github.com/manyminds/api2go) main project,
the integration_test.go or the [godoc](http://godoc.org/github.com/manyminds/api2go/jsonapi).

View File

@ -0,0 +1,150 @@
package jsonapi
import (
"bytes"
"encoding/json"
"errors"
)
var objectSuffix = []byte("{")
var arraySuffix = []byte("[")
var stringSuffix = []byte(`"`)
// A Document represents a JSON API document as specified here: http://jsonapi.org.
type Document struct {
Links Links `json:"links,omitempty"`
Data *DataContainer `json:"data"`
Included []Data `json:"included,omitempty"`
Meta map[string]interface{} `json:"meta,omitempty"`
}
// A DataContainer is used to marshal and unmarshal single objects and arrays
// of objects.
type DataContainer struct {
DataObject *Data
DataArray []Data
}
// UnmarshalJSON unmarshals the JSON-encoded data to the DataObject field if the
// root element is an object or to the DataArray field for arrays.
func (c *DataContainer) UnmarshalJSON(payload []byte) error {
if bytes.HasPrefix(payload, objectSuffix) {
return json.Unmarshal(payload, &c.DataObject)
}
if bytes.HasPrefix(payload, arraySuffix) {
return json.Unmarshal(payload, &c.DataArray)
}
return errors.New("expected a JSON encoded object or array")
}
// MarshalJSON returns the JSON encoding of the DataArray field or the DataObject
// field. It will return "null" if neither of them is set.
func (c *DataContainer) MarshalJSON() ([]byte, error) {
if c.DataArray != nil {
return json.Marshal(c.DataArray)
}
return json.Marshal(c.DataObject)
}
// Link represents a link for return in the document.
type Link struct {
Href string `json:"href"`
Meta map[string]interface{} `json:"meta,omitempty"`
}
// UnmarshalJSON marshals a string value into the Href field or marshals an
// object value into the whole struct.
func (l *Link) UnmarshalJSON(payload []byte) error {
if bytes.HasPrefix(payload, stringSuffix) {
return json.Unmarshal(payload, &l.Href)
}
if bytes.HasPrefix(payload, objectSuffix) {
obj := make(map[string]interface{})
err := json.Unmarshal(payload, &obj)
if err != nil {
return err
}
var ok bool
l.Href, ok = obj["href"].(string)
if !ok {
return errors.New(`link object expects a "href" key`)
}
l.Meta, _ = obj["meta"].(map[string]interface{})
return nil
}
return errors.New("expected a JSON encoded string or object")
}
// MarshalJSON returns the JSON encoding of only the Href field if the Meta
// field is empty, otherwise it marshals the whole struct.
func (l Link) MarshalJSON() ([]byte, error) {
if len(l.Meta) == 0 {
return json.Marshal(l.Href)
}
return json.Marshal(map[string]interface{}{
"href": l.Href,
"meta": l.Meta,
})
}
// Links contains a map of custom Link objects as given by an element.
type Links map[string]Link
// Data is a general struct for document data and included data.
type Data struct {
Type string `json:"type"`
ID string `json:"id"`
Attributes json.RawMessage `json:"attributes"`
Relationships map[string]Relationship `json:"relationships,omitempty"`
Links Links `json:"links,omitempty"`
}
// Relationship contains reference IDs to the related structs
type Relationship struct {
Links Links `json:"links,omitempty"`
Data *RelationshipDataContainer `json:"data,omitempty"`
Meta map[string]interface{} `json:"meta,omitempty"`
}
// A RelationshipDataContainer is used to marshal and unmarshal single relationship
// objects and arrays of relationship objects.
type RelationshipDataContainer struct {
DataObject *RelationshipData
DataArray []RelationshipData
}
// UnmarshalJSON unmarshals the JSON-encoded data to the DataObject field if the
// root element is an object or to the DataArray field for arrays.
func (c *RelationshipDataContainer) UnmarshalJSON(payload []byte) error {
if bytes.HasPrefix(payload, objectSuffix) {
// payload is an object
return json.Unmarshal(payload, &c.DataObject)
}
if bytes.HasPrefix(payload, arraySuffix) {
// payload is an array
return json.Unmarshal(payload, &c.DataArray)
}
return errors.New("Invalid json for relationship data array/object")
}
// MarshalJSON returns the JSON encoding of the DataArray field or the DataObject
// field. It will return "null" if neither of them is set.
func (c *RelationshipDataContainer) MarshalJSON() ([]byte, error) {
if c.DataArray != nil {
return json.Marshal(c.DataArray)
}
return json.Marshal(c.DataObject)
}
// RelationshipData represents one specific reference ID.
type RelationshipData struct {
Type string `json:"type"`
ID string `json:"id"`
}

View File

@ -0,0 +1,9 @@
package jsonapi
// The EntityNamer interface can be optionally implemented to directly return the
// name of resource used for the "type" field.
//
// Note: By default the name is guessed from the struct name.
type EntityNamer interface {
GetName() string
}

65
vendor/github.com/manyminds/api2go/jsonapi/helpers.go generated vendored Normal file
View File

@ -0,0 +1,65 @@
package jsonapi
import (
"strings"
"unicode"
"github.com/gedex/inflector"
)
// https://github.com/golang/lint/blob/3d26dc39376c307203d3a221bada26816b3073cf/lint.go#L482
var commonInitialisms = map[string]bool{
"API": true,
"ASCII": true,
"CPU": true,
"CSS": true,
"DNS": true,
"EOF": true,
"GUID": true,
"HTML": true,
"HTTP": true,
"HTTPS": true,
"ID": true,
"IP": true,
"JSON": true,
"LHS": true,
"QPS": true,
"RAM": true,
"RHS": true,
"RPC": true,
"SLA": true,
"SMTP": true,
"SSH": true,
"TLS": true,
"TTL": true,
"UI": true,
"UID": true,
"UUID": true,
"URI": true,
"URL": true,
"UTF8": true,
"VM": true,
"XML": true,
"JWT": true,
}
// Jsonify returns a JSON formatted key name from a go struct field name.
func Jsonify(s string) string {
if s == "" {
return ""
}
if commonInitialisms[s] {
return strings.ToLower(s)
}
rs := []rune(s)
rs[0] = unicode.ToLower(rs[0])
return string(rs)
}
// Pluralize returns the pluralization of a noun.
func Pluralize(word string) string {
return inflector.Pluralize(word)
}

388
vendor/github.com/manyminds/api2go/jsonapi/marshal.go generated vendored Normal file
View File

@ -0,0 +1,388 @@
package jsonapi
import (
"encoding/json"
"errors"
"fmt"
"reflect"
"strings"
)
// RelationshipType specifies the type of a relationship.
type RelationshipType int
// The available relationship types.
//
// Note: DefaultRelationship guesses the relationship type based on the
// pluralization of the reference name.
const (
DefaultRelationship RelationshipType = iota
ToOneRelationship
ToManyRelationship
)
// The MarshalIdentifier interface is necessary to give an element a unique ID.
//
// Note: The implementation of this interface is mandatory.
type MarshalIdentifier interface {
GetID() string
}
// ReferenceID contains all necessary information in order to reference another
// struct in JSON API.
type ReferenceID struct {
ID string
Type string
Name string
Relationship RelationshipType
}
// A Reference information about possible references of a struct.
//
// Note: If IsNotLoaded is set to true, the `data` field will be omitted and only
// the `links` object will be generated. You should do this if there are some
// references, but you do not want to load them. Otherwise, if IsNotLoaded is
// false and GetReferencedIDs() returns no IDs for this reference name, an
// empty `data` field will be added which means that there are no references.
type Reference struct {
Type string
Name string
IsNotLoaded bool
Relationship RelationshipType
}
// The MarshalReferences interface must be implemented if the struct to be
// serialized has relationships.
type MarshalReferences interface {
GetReferences() []Reference
}
// The MarshalLinkedRelations interface must be implemented if there are
// reference ids that should be included in the document.
type MarshalLinkedRelations interface {
MarshalReferences
MarshalIdentifier
GetReferencedIDs() []ReferenceID
}
// The MarshalIncludedRelations interface must be implemented if referenced
// structs should be included in the document.
type MarshalIncludedRelations interface {
MarshalReferences
MarshalIdentifier
GetReferencedStructs() []MarshalIdentifier
}
// The MarshalCustomLinks interface can be implemented if the struct should
// want any custom links.
type MarshalCustomLinks interface {
MarshalIdentifier
GetCustomLinks(string) Links
}
// A ServerInformation implementor can be passed to MarshalWithURLs to generate
// the `self` and `related` urls inside `links`.
type ServerInformation interface {
GetBaseURL() string
GetPrefix() string
}
// MarshalWithURLs can be used to pass along a ServerInformation implementor.
func MarshalWithURLs(data interface{}, information ServerInformation) ([]byte, error) {
document, err := MarshalToStruct(data, information)
if err != nil {
return nil, err
}
return json.Marshal(document)
}
// Marshal wraps data in a Document and returns its JSON encoding.
//
// Data can be a struct, a pointer to a struct or a slice of structs. All structs
// must at least implement the `MarshalIdentifier` interface.
func Marshal(data interface{}) ([]byte, error) {
document, err := MarshalToStruct(data, nil)
if err != nil {
return nil, err
}
return json.Marshal(document)
}
// MarshalToStruct marshals an api2go compatible struct into a jsonapi Document
// structure which then can be marshaled to JSON. You only need this method if
// you want to extract or extend parts of the document. You should directly use
// Marshal to get a []byte with JSON in it.
func MarshalToStruct(data interface{}, information ServerInformation) (*Document, error) {
if data == nil {
return &Document{}, nil
}
switch reflect.TypeOf(data).Kind() {
case reflect.Slice:
return marshalSlice(data, information)
case reflect.Struct, reflect.Ptr:
return marshalStruct(data.(MarshalIdentifier), information)
default:
return nil, errors.New("Marshal only accepts slice, struct or ptr types")
}
}
func marshalSlice(data interface{}, information ServerInformation) (*Document, error) {
result := &Document{}
val := reflect.ValueOf(data)
dataElements := make([]Data, val.Len())
var referencedStructs []MarshalIdentifier
for i := 0; i < val.Len(); i++ {
k := val.Index(i).Interface()
element, ok := k.(MarshalIdentifier)
if !ok {
return nil, errors.New("all elements within the slice must implement api2go.MarshalIdentifier")
}
err := marshalData(element, &dataElements[i], information)
if err != nil {
return nil, err
}
included, ok := k.(MarshalIncludedRelations)
if ok {
referencedStructs = append(referencedStructs, included.GetReferencedStructs()...)
}
}
includedElements, err := filterDuplicates(referencedStructs, information)
if err != nil {
return nil, err
}
result.Data = &DataContainer{
DataArray: dataElements,
}
if includedElements != nil && len(includedElements) > 0 {
result.Included = includedElements
}
return result, nil
}
func filterDuplicates(input []MarshalIdentifier, information ServerInformation) ([]Data, error) {
alreadyIncluded := map[string]map[string]bool{}
includedElements := []Data{}
for _, referencedStruct := range input {
structType := getStructType(referencedStruct)
if alreadyIncluded[structType] == nil {
alreadyIncluded[structType] = make(map[string]bool)
}
if !alreadyIncluded[structType][referencedStruct.GetID()] {
var data Data
err := marshalData(referencedStruct, &data, information)
if err != nil {
return nil, err
}
includedElements = append(includedElements, data)
alreadyIncluded[structType][referencedStruct.GetID()] = true
}
}
return includedElements, nil
}
func marshalData(element MarshalIdentifier, data *Data, information ServerInformation) error {
refValue := reflect.ValueOf(element)
if refValue.Kind() == reflect.Ptr && refValue.IsNil() {
return errors.New("MarshalIdentifier must not be nil")
}
attributes, err := json.Marshal(element)
if err != nil {
return err
}
data.Attributes = attributes
data.ID = element.GetID()
data.Type = getStructType(element)
if information != nil {
if customLinks, ok := element.(MarshalCustomLinks); ok {
if data.Links == nil {
data.Links = make(Links)
}
base := getLinkBaseURL(element, information)
for k, v := range customLinks.GetCustomLinks(base) {
if _, ok := data.Links[k]; !ok {
data.Links[k] = v
}
}
}
}
if references, ok := element.(MarshalLinkedRelations); ok {
data.Relationships = getStructRelationships(references, information)
}
return nil
}
func isToMany(relationshipType RelationshipType, name string) bool {
if relationshipType == DefaultRelationship {
return Pluralize(name) == name
}
return relationshipType == ToManyRelationship
}
func getStructRelationships(relationer MarshalLinkedRelations, information ServerInformation) map[string]Relationship {
referencedIDs := relationer.GetReferencedIDs()
sortedResults := map[string][]ReferenceID{}
relationships := map[string]Relationship{}
for _, referenceID := range referencedIDs {
sortedResults[referenceID.Name] = append(sortedResults[referenceID.Name], referenceID)
}
references := relationer.GetReferences()
// helper map to check if all references are included to also include empty ones
notIncludedReferences := map[string]Reference{}
for _, reference := range references {
notIncludedReferences[reference.Name] = reference
}
for name, referenceIDs := range sortedResults {
relationships[name] = Relationship{}
// if referenceType is plural, we need to use an array for data, otherwise it's just an object
container := RelationshipDataContainer{}
if isToMany(referenceIDs[0].Relationship, referenceIDs[0].Name) {
// multiple elements in links
container.DataArray = []RelationshipData{}
for _, referenceID := range referenceIDs {
container.DataArray = append(container.DataArray, RelationshipData{
Type: referenceID.Type,
ID: referenceID.ID,
})
}
} else {
container.DataObject = &RelationshipData{
Type: referenceIDs[0].Type,
ID: referenceIDs[0].ID,
}
}
// set URLs if necessary
links := getLinksForServerInformation(relationer, name, information)
relationship := Relationship{
Data: &container,
Links: links,
}
relationships[name] = relationship
// this marks the reference as already included
delete(notIncludedReferences, referenceIDs[0].Name)
}
// check for empty references
for name, reference := range notIncludedReferences {
container := RelationshipDataContainer{}
// Plural empty relationships need an empty array and empty to-one need a null in the json
if !reference.IsNotLoaded && isToMany(reference.Relationship, reference.Name) {
container.DataArray = []RelationshipData{}
}
links := getLinksForServerInformation(relationer, name, information)
relationship := Relationship{
Links: links,
}
// skip relationship data completely if IsNotLoaded is set
if !reference.IsNotLoaded {
relationship.Data = &container
}
relationships[name] = relationship
}
return relationships
}
func getLinkBaseURL(element MarshalIdentifier, information ServerInformation) string {
prefix := strings.Trim(information.GetBaseURL(), "/")
namespace := strings.Trim(information.GetPrefix(), "/")
structType := getStructType(element)
if namespace != "" {
prefix += "/" + namespace
}
return fmt.Sprintf("%s/%s/%s", prefix, structType, element.GetID())
}
func getLinksForServerInformation(relationer MarshalLinkedRelations, name string, information ServerInformation) Links {
if information == nil {
return nil
}
links := make(Links)
base := getLinkBaseURL(relationer, information)
links["self"] = Link{Href: fmt.Sprintf("%s/relationships/%s", base, name)}
links["related"] = Link{Href: fmt.Sprintf("%s/%s", base, name)}
return links
}
func marshalStruct(data MarshalIdentifier, information ServerInformation) (*Document, error) {
var contentData Data
err := marshalData(data, &contentData, information)
if err != nil {
return nil, err
}
result := &Document{
Data: &DataContainer{
DataObject: &contentData,
},
}
included, ok := data.(MarshalIncludedRelations)
if ok {
included, err := filterDuplicates(included.GetReferencedStructs(), information)
if err != nil {
return nil, err
}
if len(included) > 0 {
result.Included = included
}
}
return result, nil
}
func getStructType(data interface{}) string {
entityName, ok := data.(EntityNamer)
if ok {
return entityName.GetName()
}
reflectType := reflect.TypeOf(data)
if reflectType.Kind() == reflect.Ptr {
return Pluralize(Jsonify(reflectType.Elem().Name()))
}
return Pluralize(Jsonify(reflectType.Name()))
}

233
vendor/github.com/manyminds/api2go/jsonapi/unmarshal.go generated vendored Normal file
View File

@ -0,0 +1,233 @@
package jsonapi
import (
"encoding/json"
"errors"
"fmt"
"reflect"
)
// The UnmarshalIdentifier interface must be implemented to set the ID during
// unmarshalling.
type UnmarshalIdentifier interface {
SetID(string) error
}
// The UnmarshalToOneRelations interface must be implemented to unmarshal
// to-one relations.
type UnmarshalToOneRelations interface {
SetToOneReferenceID(name, ID string) error
}
// The UnmarshalToManyRelations interface must be implemented to unmarshal
// to-many relations.
type UnmarshalToManyRelations interface {
SetToManyReferenceIDs(name string, IDs []string) error
}
// The EditToManyRelations interface can be optionally implemented to add and
// delete to-many relationships on a already unmarshalled struct. These methods
// are used by our API for the to-many relationship update routes.
//
// There are 3 HTTP Methods to edit to-many relations:
//
// PATCH /v1/posts/1/comments
// Content-Type: application/vnd.api+json
// Accept: application/vnd.api+json
//
// {
// "data": [
// { "type": "comments", "id": "2" },
// { "type": "comments", "id": "3" }
// ]
// }
//
// This replaces all of the comments that belong to post with ID 1 and the
// SetToManyReferenceIDs method will be called.
//
// POST /v1/posts/1/comments
// Content-Type: application/vnd.api+json
// Accept: application/vnd.api+json
//
// {
// "data": [
// { "type": "comments", "id": "123" }
// ]
// }
//
// Adds a new comment to the post with ID 1.
// The AddToManyIDs method will be called.
//
// DELETE /v1/posts/1/comments
// Content-Type: application/vnd.api+json
// Accept: application/vnd.api+json
//
// {
// "data": [
// { "type": "comments", "id": "12" },
// { "type": "comments", "id": "13" }
// ]
// }
//
// Deletes comments that belong to post with ID 1.
// The DeleteToManyIDs method will be called.
type EditToManyRelations interface {
AddToManyIDs(name string, IDs []string) error
DeleteToManyIDs(name string, IDs []string) error
}
// Unmarshal parses a JSON API compatible JSON and populates the target which
// must implement the `UnmarshalIdentifier` interface.
func Unmarshal(data []byte, target interface{}) error {
if target == nil {
return errors.New("target must not be nil")
}
if reflect.TypeOf(target).Kind() != reflect.Ptr {
return errors.New("target must be a ptr")
}
ctx := &Document{}
err := json.Unmarshal(data, ctx)
if err != nil {
return err
}
if ctx.Data == nil {
return errors.New(`Source JSON is empty and has no "attributes" payload object`)
}
if ctx.Data.DataObject != nil {
return setDataIntoTarget(ctx.Data.DataObject, target)
}
if ctx.Data.DataArray != nil {
targetSlice := reflect.TypeOf(target).Elem()
if targetSlice.Kind() != reflect.Slice {
return fmt.Errorf("Cannot unmarshal array to struct target %s", targetSlice)
}
targetType := targetSlice.Elem()
targetPointer := reflect.ValueOf(target)
targetValue := targetPointer.Elem()
for _, record := range ctx.Data.DataArray {
// check if there already is an entry with the same id in target slice,
// otherwise create a new target and append
var targetRecord, emptyValue reflect.Value
for i := 0; i < targetValue.Len(); i++ {
marshalCasted, ok := targetValue.Index(i).Interface().(MarshalIdentifier)
if !ok {
return errors.New("existing structs must implement interface MarshalIdentifier")
}
if record.ID == marshalCasted.GetID() {
targetRecord = targetValue.Index(i).Addr()
break
}
}
if targetRecord == emptyValue || targetRecord.IsNil() {
targetRecord = reflect.New(targetType)
err := setDataIntoTarget(&record, targetRecord.Interface())
if err != nil {
return err
}
targetValue = reflect.Append(targetValue, targetRecord.Elem())
} else {
err := setDataIntoTarget(&record, targetRecord.Interface())
if err != nil {
return err
}
}
}
targetPointer.Elem().Set(targetValue)
}
return nil
}
func setDataIntoTarget(data *Data, target interface{}) error {
castedTarget, ok := target.(UnmarshalIdentifier)
if !ok {
return errors.New("target must implement UnmarshalIdentifier interface")
}
if data.Type == "" {
return errors.New("invalid record, no type was specified")
}
err := checkType(data.Type, castedTarget)
if err != nil {
return err
}
if data.Attributes != nil {
err = json.Unmarshal(data.Attributes, castedTarget)
if err != nil {
return err
}
}
if err := castedTarget.SetID(data.ID); err != nil {
return err
}
return setRelationshipIDs(data.Relationships, castedTarget)
}
// extracts all found relationships and set's them via SetToOneReferenceID or
// SetToManyReferenceIDs
func setRelationshipIDs(relationships map[string]Relationship, target UnmarshalIdentifier) error {
for name, rel := range relationships {
// if Data is nil, it means that we have an empty toOne relationship
if rel.Data == nil {
castedToOne, ok := target.(UnmarshalToOneRelations)
if !ok {
return fmt.Errorf("struct %s does not implement UnmarshalToOneRelations", reflect.TypeOf(target))
}
castedToOne.SetToOneReferenceID(name, "")
break
}
// valid toOne case
if rel.Data.DataObject != nil {
castedToOne, ok := target.(UnmarshalToOneRelations)
if !ok {
return fmt.Errorf("struct %s does not implement UnmarshalToOneRelations", reflect.TypeOf(target))
}
err := castedToOne.SetToOneReferenceID(name, rel.Data.DataObject.ID)
if err != nil {
return err
}
}
// valid toMany case
if rel.Data.DataArray != nil {
castedToMany, ok := target.(UnmarshalToManyRelations)
if !ok {
return fmt.Errorf("struct %s does not implement UnmarshalToManyRelations", reflect.TypeOf(target))
}
IDs := make([]string, len(rel.Data.DataArray))
for index, relData := range rel.Data.DataArray {
IDs[index] = relData.ID
}
err := castedToMany.SetToManyReferenceIDs(name, IDs)
if err != nil {
return err
}
}
}
return nil
}
func checkType(incomingType string, target UnmarshalIdentifier) error {
actualType := getStructType(target)
if incomingType != actualType {
return fmt.Errorf("Type %s in JSON does not match target struct type %s", incomingType, actualType)
}
return nil
}

18
vendor/vendor.json vendored
View File

@ -461,6 +461,12 @@
"revision": "4239b77079c7b5d1243b7b4736304ce8ddb6f0f2",
"revisionTime": "2016-01-15T23:47:25Z"
},
{
"checksumSHA1": "p9hyEP07p5jnjgUKHjKftWaKgs8=",
"path": "github.com/arukasio/cli",
"revision": "4f0dee167044ef44260d985a4d325f35a06e3149",
"revisionTime": "2017-01-23T00:46:44Z"
},
{
"checksumSHA1": "FWMPfJtpwiMBj9Ni0eMCVQYPV+M=",
"path": "github.com/aws/aws-sdk-go",
@ -1265,6 +1271,12 @@
"revisionTime": "2016-04-27T17:25:47Z",
"tree": true
},
{
"checksumSHA1": "SYxDN6l6j6OJ9f9BQDzneaJBd0k=",
"path": "github.com/gedex/inflector",
"revision": "046f2c31204676e3623730ee70fd0964e05822e7",
"revisionTime": "2016-11-03T04:27:56Z"
},
{
"checksumSHA1": "JKjnR1ApU6NcC79xcGaT7QRMx3A=",
"comment": "0.0.1-42-gea19666",
@ -2057,6 +2069,12 @@
"revision": "d392059301313eee8059c85a4e698f22c664ef78",
"revisionTime": "2015-10-10T02:14:09Z"
},
{
"checksumSHA1": "BMxNUz0/EaTvexw9Vxm5jPG3w60=",
"path": "github.com/manyminds/api2go/jsonapi",
"revision": "dc368bb579c1a582faed50768e7fbcc463954c89",
"revisionTime": "2016-12-29T20:22:12Z"
},
{
"checksumSHA1": "yg57Q4J8Ob0LoYvqDxsWZ6AHffE=",
"path": "github.com/masterzen/simplexml/dom",

View File

@ -9,6 +9,7 @@ body.page-sub{
body.layout-commands-state,
body.layout-alicloud,
body.layout-archive,
body.layout-arukas,
body.layout-atlas,
body.layout-aws,
body.layout-azure,

View File

@ -0,0 +1,82 @@
---
layout: "arukas"
page_title: "Provider: Arukas"
sidebar_current: "docs-arukas-index"
description: |-
The Arukas provider is used to interact with the resources supported by Arukas.
---
# Arukas Provider
The Arukas provider is used to manage [Arukas](https://arukas.io/en/) resources.
Use the navigation to the left to read about the available resources.
For additional details please refer to [Arukas documentation](https://arukas.io/en/category/documents-en/).
## Example Usage
Here is an example that will setup the following:
+ A container resource using the "NGINX" image
+ Instance count is 1
+ Memory size is 256Mbyte
+ Expose tcp 80 port to the EndPoint
+ Set environments variable with like "key1=value1"
Add the below to a file called `arukas.tf` and run the `terraform` command from the same directory:
```hcl
provider "arukas" {
token = ""
secret = ""
}
resource "arukas_container" "foobar" {
name = "terraform_for_arukas_test_foobar"
image = "nginx:latest"
instances = 1
memory = 256
ports = {
protocol = "tcp"
number = "80"
}
environments {
key = "key1"
value = "value1"
}
}
```
You'll need to provide your Arukas API token and secret,
so that Terraform can connect. If you don't want to put
credentials in your configuration file, you can leave them
out:
```
provider "arukas" {}
```
...and instead set these environment variables:
- `ARUKAS_JSON_API_TOKEN` : Your Arukas API token
- `ARUKAS_JSON_API_SECRET`: Your Arukas API secret
## Argument Reference
The following arguments are supported:
* `token` - (Required) This is the Arukas API token. It must be provided, but
it can also be sourced from the `ARUKAS_JSON_API_TOKEN` environment variable.
* `secret` - (Required) This is the Arukas API secret. It must be provided, but
it can also be sourced from the `ARUKAS_JSON_API_SECRET` environment variable.
* `api_url` - (Optional) Override Arukas API Root URL. Also taken from the `ARUKAS_JSON_API_URL`
environment variable if provided.
* `trace` - (Optional) The flag of Arukas API trace log. Also taken from the `ARUKAS_DEBUG`
environment variable if provided.
* `timeout` - (Optional) Override Arukas API timeout seconds. Also taken from the `ARUKAS_TIMEOUT`
environment variable if provided.

View File

@ -0,0 +1,98 @@
---
layout: "arukas"
page_title: "Arukas: container"
sidebar_current: "docs-arukas-resource-container"
description: |-
Manages Arukas Containers
---
# arukas container
Provides container resource. This allows container to be created, updated and deleted.
For additional details please refer to [API documentation](https://arukas.io/en/documents-en/arukas-api-reference-en/#containers).
## Example Usage
Create a new container using the "NGINX" image.
```hcl
resource "arukas_container" "foobar" {
name = "terraform_for_arukas_test_foobar"
image = "nginx:latest"
instances = 1
memory = 256
ports = {
protocol = "tcp"
number = "80"
}
environments {
key = "key1"
value = "value1"
}
}
```
## Argument Reference
The following arguments are supported:
* `name` - (Required, string) The name of the container.
* `image` - (Required, string) The ID of the image to back this container.It must be a public image on DockerHub.
* `instances` - (Optional, int) The count of the instance. It must be between `1` and `10`.
* `memory` - (Optional, int) The size of the instance RAM.It must be `256` or `512`.
* `endpoint` - (Optional,string) The subdomain part of the endpoint assigned by Arukas. If it is not set, Arukas will do automatic assignment.
* `ports` - (Required , block) See [Ports](#ports) below for details.
* `environments` - (Required , block) See [Environments](#environments) below for details.
* `cmd` - (Optional , string) The command of the container.
<a id="ports"></a>
### Ports
`ports` is a block within the configuration that can be repeated to specify
the port mappings of the container. Each `ports` block supports
the following:
* `protocol` - (Optional, string) Protocol that can be used over this port, defaults to `tcp`,It must be `tcp` or `udp`.
* `number` - (Optional, int) Port within the container,defaults to `80`, It must be between `1` to `65535`.
<a id="environments"></a>
### Environments
`environments` is a block within the configuration that can be repeated to specify
the environment variables. Each `environments` block supports
the following:
* `key` - (Required, string) Key of environment variable.
* `value` - (Required, string) Value of environment variable.
## Attributes Reference
The following attributes are exported:
* `id` - The ID of the container.
* `app_id` - The ID of the Arukas application to which the container belongs.
* `name` - The name of the container.
* `image` - The ID of the image to back this container.
* `instances` - The count of the instance.
* `memory` - The size of the instance RAM.
* `endpoint` - The subdomain part of the endpoint assigned by Arukas.
* `ports` - See [Ports](#ports) below for details.
* `environments` - See [Environments](#environments) below for details.
* `cmd` - The command of the container.
* `port_mappings` - See [PortMappings](#port_mappings) below for details.
* `endpoint_full_url` - The URL of endpoint.
* `endpoint_full_hostname` - The Hostname of endpoint.
<a id="port_mappings"></a>
### PortMappings
`port_mappings` is a block within the configuration that
the port mappings of the container. Each `port_mappings` block supports
the following:
* `host` - The name of the host actually running the container.
* `ipaddress` - The IP address of the host actually running the container.
* `container_port` - Port within the container.
* `service_port` - The actual port mapped to the port in the container.

View File

@ -0,0 +1,26 @@
<% wrap_layout :inner do %>
<% content_for :sidebar do %>
<div class="docs-sidebar hidden-print affix-top" role="complementary">
<ul class="nav docs-sidenav">
<li<%= sidebar_current("docs-home") %>>
<a href="/docs/providers/index.html">&laquo; Documentation Home</a>
</li>
<li<%= sidebar_current("docs-arukas-index") %>>
<a href="/docs/providers/arukas/index.html">Arukas Provider</a>
</li>
<li<%= sidebar_current(/^docs-arukas-resource/) %>>
<a href="#">Resources</a>
<ul class="nav nav-visible">
<li<%= sidebar_current("docs-arukas-resource-container") %>>
<a href="/docs/providers/arukas/r/container.html">arukas_container</a>
</li>
</ul>
</li>
</ul>
</div>
<% end %>
<%= yield %>
<% end %>

View File

@ -182,6 +182,10 @@
<a href="/docs/providers/archive/index.html">Archive</a>
</li>
<li<%= sidebar_current("docs-providers-arukas") %>>
<a href="/docs/providers/arukas/index.html">Arukas</a>
</li>
<li<%= sidebar_current("docs-providers-atlas") %>>
<a href="/docs/providers/atlas/index.html">Atlas</a>
</li>