Revert "provider/triton: New provider for Joyent Triton"
This reverts commit f60f04ac70
.
This commit is contained in:
parent
5bae6cb1e6
commit
85b4b5813f
|
@ -740,22 +740,6 @@
|
||||||
"Comment": "0.2.2-2-gc01cf91",
|
"Comment": "0.2.2-2-gc01cf91",
|
||||||
"Rev": "c01cf91b011868172fdcd9f41838e80c9d716264"
|
"Rev": "c01cf91b011868172fdcd9f41838e80c9d716264"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"ImportPath": "github.com/joyent/gocommon",
|
|
||||||
"Rev": "40c7818502f7c1ebbb13dab185a26e77b746ff40"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ImportPath": "github.com/joyent/gosdc/cloudapi",
|
|
||||||
"Rev": "e5af42dc255d490169eaea98c610cf7660913844"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ImportPath": "github.com/joyent/gosign/auth",
|
|
||||||
"Rev": "0da0d5f1342065321c97812b1f4ac0c2b0bab56c"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ImportPath": "github.com/juju/loggo",
|
|
||||||
"Rev": "8477fc936adf0e382d680310047ca27e128a309a"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/kardianos/osext",
|
"ImportPath": "github.com/kardianos/osext",
|
||||||
"Rev": "29ae4ffbc9a6fe9fb2bc5029050ce6996ea1d3bc"
|
"Rev": "29ae4ffbc9a6fe9fb2bc5029050ce6996ea1d3bc"
|
||||||
|
|
|
@ -1,12 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/hashicorp/terraform/builtin/providers/triton"
|
|
||||||
"github.com/hashicorp/terraform/plugin"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
plugin.Serve(&plugin.ServeOpts{
|
|
||||||
ProviderFunc: triton.Provider,
|
|
||||||
})
|
|
||||||
}
|
|
|
@ -1,118 +0,0 @@
|
||||||
package triton
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/hashicorp/go-multierror"
|
|
||||||
"github.com/hashicorp/terraform/helper/schema"
|
|
||||||
"github.com/hashicorp/terraform/terraform"
|
|
||||||
"github.com/joyent/gocommon/client"
|
|
||||||
"github.com/joyent/gosdc/cloudapi"
|
|
||||||
"github.com/joyent/gosign/auth"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Provider returns a terraform.ResourceProvider.
|
|
||||||
func Provider() terraform.ResourceProvider {
|
|
||||||
return &schema.Provider{
|
|
||||||
Schema: map[string]*schema.Schema{
|
|
||||||
"account": &schema.Schema{
|
|
||||||
Type: schema.TypeString,
|
|
||||||
Required: true,
|
|
||||||
DefaultFunc: schema.EnvDefaultFunc("SDC_ACCOUNT", ""),
|
|
||||||
},
|
|
||||||
|
|
||||||
"url": &schema.Schema{
|
|
||||||
Type: schema.TypeString,
|
|
||||||
Required: true,
|
|
||||||
DefaultFunc: schema.EnvDefaultFunc("SDC_URL", "https://us-west-1.api.joyentcloud.com"),
|
|
||||||
},
|
|
||||||
|
|
||||||
"key_material": &schema.Schema{
|
|
||||||
Type: schema.TypeString,
|
|
||||||
Required: true,
|
|
||||||
DefaultFunc: schema.EnvDefaultFunc("SDC_KEY_MATERIAL", ""),
|
|
||||||
},
|
|
||||||
|
|
||||||
"key_id": &schema.Schema{
|
|
||||||
Type: schema.TypeString,
|
|
||||||
Required: true,
|
|
||||||
DefaultFunc: schema.EnvDefaultFunc("SDC_KEY_ID", ""),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
ResourcesMap: map[string]*schema.Resource{
|
|
||||||
"triton_firewall_rule": resourceFirewallRule(),
|
|
||||||
"triton_machine": resourceMachine(),
|
|
||||||
"triton_key": resourceKey(),
|
|
||||||
},
|
|
||||||
ConfigureFunc: providerConfigure,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type SDCConfig struct {
|
|
||||||
Account string
|
|
||||||
KeyMaterial string
|
|
||||||
KeyID string
|
|
||||||
URL string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c SDCConfig) validate() error {
|
|
||||||
var err *multierror.Error
|
|
||||||
|
|
||||||
if c.URL == "" {
|
|
||||||
err = multierror.Append(err, fmt.Errorf("URL must be configured for the Triton provider"))
|
|
||||||
}
|
|
||||||
if c.KeyMaterial == "" {
|
|
||||||
err = multierror.Append(err, fmt.Errorf("Key Material must be configured for the Triton provider"))
|
|
||||||
}
|
|
||||||
if c.KeyID == "" {
|
|
||||||
err = multierror.Append(err, fmt.Errorf("Key ID must be configured for the Triton provider"))
|
|
||||||
}
|
|
||||||
if c.Account == "" {
|
|
||||||
err = multierror.Append(err, fmt.Errorf("Account must be configured for the Triton provider"))
|
|
||||||
}
|
|
||||||
|
|
||||||
return err.ErrorOrNil()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c SDCConfig) getSDCClient() (*cloudapi.Client, error) {
|
|
||||||
userauth, err := auth.NewAuth(c.Account, c.KeyMaterial, "rsa-sha256")
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
creds := &auth.Credentials{
|
|
||||||
UserAuthentication: userauth,
|
|
||||||
SdcKeyId: c.KeyID,
|
|
||||||
SdcEndpoint: auth.Endpoint{URL: c.URL},
|
|
||||||
}
|
|
||||||
|
|
||||||
client := cloudapi.New(client.NewClient(
|
|
||||||
c.URL,
|
|
||||||
cloudapi.DefaultAPIVersion,
|
|
||||||
creds,
|
|
||||||
&cloudapi.Logger,
|
|
||||||
))
|
|
||||||
|
|
||||||
return client, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func providerConfigure(d *schema.ResourceData) (interface{}, error) {
|
|
||||||
config := SDCConfig{
|
|
||||||
Account: d.Get("account").(string),
|
|
||||||
URL: d.Get("url").(string),
|
|
||||||
KeyMaterial: d.Get("key_material").(string),
|
|
||||||
KeyID: d.Get("key_id").(string),
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := config.validate(); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
client, err := config.getSDCClient()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return client, nil
|
|
||||||
}
|
|
|
@ -1,44 +0,0 @@
|
||||||
package triton
|
|
||||||
|
|
||||||
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{
|
|
||||||
"triton": 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) {
|
|
||||||
sdcURL := os.Getenv("SDC_URL")
|
|
||||||
account := os.Getenv("SDC_ACCOUNT")
|
|
||||||
keyID := os.Getenv("SDC_KEY_ID")
|
|
||||||
keyMaterial := os.Getenv("SDC_KEY_MATERIAL")
|
|
||||||
|
|
||||||
if sdcURL == "" {
|
|
||||||
sdcURL = "https://us-west-1.api.joyentcloud.com"
|
|
||||||
}
|
|
||||||
|
|
||||||
if sdcURL == "" || account == "" || keyID == "" || keyMaterial == "" {
|
|
||||||
t.Fatal("SDC_ACCOUNT, SDC_KEY_ID and SDC_KEY_MATERIAL must be set for acceptance tests")
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,101 +0,0 @@
|
||||||
package triton
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/hashicorp/terraform/helper/schema"
|
|
||||||
"github.com/joyent/gosdc/cloudapi"
|
|
||||||
)
|
|
||||||
|
|
||||||
func resourceFirewallRule() *schema.Resource {
|
|
||||||
return &schema.Resource{
|
|
||||||
Create: resourceFirewallRuleCreate,
|
|
||||||
Exists: resourceFirewallRuleExists,
|
|
||||||
Read: resourceFirewallRuleRead,
|
|
||||||
Update: resourceFirewallRuleUpdate,
|
|
||||||
Delete: resourceFirewallRuleDelete,
|
|
||||||
|
|
||||||
Schema: map[string]*schema.Schema{
|
|
||||||
"rule": {
|
|
||||||
Description: "firewall rule text",
|
|
||||||
Type: schema.TypeString,
|
|
||||||
Required: true,
|
|
||||||
},
|
|
||||||
"enabled": {
|
|
||||||
Description: "Indicates if the rule is enabled",
|
|
||||||
Type: schema.TypeBool,
|
|
||||||
Optional: true,
|
|
||||||
Default: false,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func resourceFirewallRuleCreate(d *schema.ResourceData, meta interface{}) error {
|
|
||||||
client := meta.(*cloudapi.Client)
|
|
||||||
|
|
||||||
rule, err := client.CreateFirewallRule(cloudapi.CreateFwRuleOpts{
|
|
||||||
Rule: d.Get("rule").(string),
|
|
||||||
Enabled: d.Get("enabled").(bool),
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
d.SetId(rule.Id)
|
|
||||||
|
|
||||||
err = resourceFirewallRuleRead(d, meta)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func resourceFirewallRuleExists(d *schema.ResourceData, meta interface{}) (bool, error) {
|
|
||||||
client := meta.(*cloudapi.Client)
|
|
||||||
|
|
||||||
rule, err := client.GetFirewallRule(d.Id())
|
|
||||||
|
|
||||||
return rule != nil && err == nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func resourceFirewallRuleRead(d *schema.ResourceData, meta interface{}) error {
|
|
||||||
client := meta.(*cloudapi.Client)
|
|
||||||
|
|
||||||
rule, err := client.GetFirewallRule(d.Id())
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
d.SetId(rule.Id)
|
|
||||||
d.Set("rule", rule.Rule)
|
|
||||||
d.Set("enabled", rule.Enabled)
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func resourceFirewallRuleUpdate(d *schema.ResourceData, meta interface{}) error {
|
|
||||||
client := meta.(*cloudapi.Client)
|
|
||||||
|
|
||||||
_, err := client.UpdateFirewallRule(
|
|
||||||
d.Id(),
|
|
||||||
cloudapi.CreateFwRuleOpts{
|
|
||||||
Rule: d.Get("rule").(string),
|
|
||||||
Enabled: d.Get("enabled").(bool),
|
|
||||||
},
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return resourceFirewallRuleRead(d, meta)
|
|
||||||
}
|
|
||||||
|
|
||||||
func resourceFirewallRuleDelete(d *schema.ResourceData, meta interface{}) error {
|
|
||||||
client := meta.(*cloudapi.Client)
|
|
||||||
|
|
||||||
if err := client.DeleteFirewallRule(d.Id()); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
|
@ -1,152 +0,0 @@
|
||||||
package triton
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/hashicorp/terraform/helper/resource"
|
|
||||||
"github.com/hashicorp/terraform/terraform"
|
|
||||||
"github.com/joyent/gosdc/cloudapi"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestAccTritonFirewallRule_basic(t *testing.T) {
|
|
||||||
config := testAccTritonFirewallRule_basic
|
|
||||||
|
|
||||||
resource.Test(t, resource.TestCase{
|
|
||||||
PreCheck: func() { testAccPreCheck(t) },
|
|
||||||
Providers: testAccProviders,
|
|
||||||
CheckDestroy: testCheckTritonFirewallRuleDestroy,
|
|
||||||
Steps: []resource.TestStep{
|
|
||||||
resource.TestStep{
|
|
||||||
Config: config,
|
|
||||||
Check: resource.ComposeTestCheckFunc(
|
|
||||||
testCheckTritonFirewallRuleExists("triton_firewall_rule.test"),
|
|
||||||
),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestAccTritonFirewallRule_update(t *testing.T) {
|
|
||||||
preConfig := testAccTritonFirewallRule_basic
|
|
||||||
postConfig := testAccTritonFirewallRule_update
|
|
||||||
|
|
||||||
resource.Test(t, resource.TestCase{
|
|
||||||
PreCheck: func() { testAccPreCheck(t) },
|
|
||||||
Providers: testAccProviders,
|
|
||||||
CheckDestroy: testCheckTritonFirewallRuleDestroy,
|
|
||||||
Steps: []resource.TestStep{
|
|
||||||
resource.TestStep{
|
|
||||||
Config: preConfig,
|
|
||||||
Check: resource.ComposeTestCheckFunc(
|
|
||||||
testCheckTritonFirewallRuleExists("triton_firewall_rule.test"),
|
|
||||||
resource.TestCheckResourceAttr("triton_firewall_rule.test", "rule", "FROM any TO tag www ALLOW tcp PORT 80"),
|
|
||||||
resource.TestCheckResourceAttr("triton_firewall_rule.test", "enabled", "false"),
|
|
||||||
),
|
|
||||||
},
|
|
||||||
|
|
||||||
resource.TestStep{
|
|
||||||
Config: postConfig,
|
|
||||||
Check: resource.ComposeTestCheckFunc(
|
|
||||||
testCheckTritonFirewallRuleExists("triton_firewall_rule.test"),
|
|
||||||
resource.TestCheckResourceAttr("triton_firewall_rule.test", "rule", "FROM any TO tag www BLOCK tcp PORT 80"),
|
|
||||||
resource.TestCheckResourceAttr("triton_firewall_rule.test", "enabled", "true"),
|
|
||||||
),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestAccTritonFirewallRule_enable(t *testing.T) {
|
|
||||||
preConfig := testAccTritonFirewallRule_basic
|
|
||||||
postConfig := testAccTritonFirewallRule_enable
|
|
||||||
|
|
||||||
resource.Test(t, resource.TestCase{
|
|
||||||
PreCheck: func() { testAccPreCheck(t) },
|
|
||||||
Providers: testAccProviders,
|
|
||||||
CheckDestroy: testCheckTritonFirewallRuleDestroy,
|
|
||||||
Steps: []resource.TestStep{
|
|
||||||
resource.TestStep{
|
|
||||||
Config: preConfig,
|
|
||||||
Check: resource.ComposeTestCheckFunc(
|
|
||||||
testCheckTritonFirewallRuleExists("triton_firewall_rule.test"),
|
|
||||||
resource.TestCheckResourceAttr("triton_firewall_rule.test", "rule", "FROM any TO tag www ALLOW tcp PORT 80"),
|
|
||||||
resource.TestCheckResourceAttr("triton_firewall_rule.test", "enabled", "false"),
|
|
||||||
),
|
|
||||||
},
|
|
||||||
|
|
||||||
resource.TestStep{
|
|
||||||
Config: postConfig,
|
|
||||||
Check: resource.ComposeTestCheckFunc(
|
|
||||||
testCheckTritonFirewallRuleExists("triton_firewall_rule.test"),
|
|
||||||
resource.TestCheckResourceAttr("triton_firewall_rule.test", "rule", "FROM any TO tag www ALLOW tcp PORT 80"),
|
|
||||||
resource.TestCheckResourceAttr("triton_firewall_rule.test", "enabled", "true"),
|
|
||||||
),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func testCheckTritonFirewallRuleExists(name string) resource.TestCheckFunc {
|
|
||||||
return func(s *terraform.State) error {
|
|
||||||
// Ensure we have enough information in state to look up in API
|
|
||||||
rs, ok := s.RootModule().Resources[name]
|
|
||||||
if !ok {
|
|
||||||
return fmt.Errorf("Not found: %s", name)
|
|
||||||
}
|
|
||||||
conn := testAccProvider.Meta().(*cloudapi.Client)
|
|
||||||
|
|
||||||
rule, err := conn.GetFirewallRule(rs.Primary.ID)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("Bad: Check Firewall Rule Exists: %s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if rule == nil {
|
|
||||||
return fmt.Errorf("Bad: Firewall rule %q does not exist", rs.Primary.ID)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func testCheckTritonFirewallRuleDestroy(s *terraform.State) error {
|
|
||||||
conn := testAccProvider.Meta().(*cloudapi.Client)
|
|
||||||
|
|
||||||
for _, rs := range s.RootModule().Resources {
|
|
||||||
if rs.Type != "triton_firewall_rule" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
resp, err := conn.GetFirewallRule(rs.Primary.ID)
|
|
||||||
if err != nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if resp != nil {
|
|
||||||
return fmt.Errorf("Bad: Firewall rule %q still exists", rs.Primary.ID)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
var testAccTritonFirewallRule_basic = `
|
|
||||||
resource "triton_firewall_rule" "test" {
|
|
||||||
rule = "FROM any TO tag www ALLOW tcp PORT 80"
|
|
||||||
enabled = false
|
|
||||||
}
|
|
||||||
`
|
|
||||||
|
|
||||||
var testAccTritonFirewallRule_update = `
|
|
||||||
resource "triton_firewall_rule" "test" {
|
|
||||||
rule = "FROM any TO tag www BLOCK tcp PORT 80"
|
|
||||||
enabled = true
|
|
||||||
}
|
|
||||||
`
|
|
||||||
|
|
||||||
var testAccTritonFirewallRule_enable = `
|
|
||||||
resource "triton_firewall_rule" "test" {
|
|
||||||
rule = "FROM any TO tag www ALLOW tcp PORT 80"
|
|
||||||
enabled = true
|
|
||||||
}
|
|
||||||
`
|
|
|
@ -1,110 +0,0 @@
|
||||||
package triton
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/hashicorp/terraform/helper/schema"
|
|
||||||
"github.com/joyent/gosdc/cloudapi"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
// ErrNoKeyComment will be returned when the key name cannot be generated from
|
|
||||||
// the key comment and is not otherwise specified.
|
|
||||||
ErrNoKeyComment = errors.New("no key comment found to use as a name (and none specified)")
|
|
||||||
)
|
|
||||||
|
|
||||||
func resourceKey() *schema.Resource {
|
|
||||||
return &schema.Resource{
|
|
||||||
Create: resourceKeyCreate,
|
|
||||||
Exists: resourceKeyExists,
|
|
||||||
Read: resourceKeyRead,
|
|
||||||
Delete: resourceKeyDelete,
|
|
||||||
|
|
||||||
Schema: map[string]*schema.Schema{
|
|
||||||
"name": &schema.Schema{
|
|
||||||
Description: "name of this key (will be generated from the key comment, if not set and comment present)",
|
|
||||||
Type: schema.TypeString,
|
|
||||||
Optional: true,
|
|
||||||
Computed: true,
|
|
||||||
ForceNew: true,
|
|
||||||
},
|
|
||||||
"key": &schema.Schema{
|
|
||||||
Description: "content of public key from disk",
|
|
||||||
Type: schema.TypeString,
|
|
||||||
Required: true,
|
|
||||||
ForceNew: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func resourceKeyCreate(d *schema.ResourceData, meta interface{}) error {
|
|
||||||
client := meta.(*cloudapi.Client)
|
|
||||||
|
|
||||||
if d.Get("name").(string) == "" {
|
|
||||||
parts := strings.SplitN(d.Get("key").(string), " ", 3)
|
|
||||||
if len(parts) == 3 {
|
|
||||||
d.Set("name", parts[2])
|
|
||||||
} else {
|
|
||||||
return ErrNoKeyComment
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err := client.CreateKey(cloudapi.CreateKeyOpts{
|
|
||||||
Name: d.Get("name").(string),
|
|
||||||
Key: d.Get("key").(string),
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = resourceKeyRead(d, meta)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func resourceKeyExists(d *schema.ResourceData, meta interface{}) (bool, error) {
|
|
||||||
client := meta.(*cloudapi.Client)
|
|
||||||
|
|
||||||
keys, err := client.ListKeys()
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, key := range keys {
|
|
||||||
if key.Name == d.Id() {
|
|
||||||
return true, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func resourceKeyRead(d *schema.ResourceData, meta interface{}) error {
|
|
||||||
client := meta.(*cloudapi.Client)
|
|
||||||
|
|
||||||
key, err := client.GetKey(d.Get("name").(string))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
d.SetId(key.Name)
|
|
||||||
d.Set("name", key.Name)
|
|
||||||
d.Set("key", key.Key)
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func resourceKeyDelete(d *schema.ResourceData, meta interface{}) error {
|
|
||||||
client := meta.(*cloudapi.Client)
|
|
||||||
|
|
||||||
if err := client.DeleteKey(d.Get("name").(string)); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
|
@ -1,89 +0,0 @@
|
||||||
package triton
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"testing"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/hashicorp/terraform/helper/acctest"
|
|
||||||
"github.com/hashicorp/terraform/helper/resource"
|
|
||||||
"github.com/hashicorp/terraform/terraform"
|
|
||||||
"github.com/joyent/gosdc/cloudapi"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestAccTritonKey_basic(t *testing.T) {
|
|
||||||
keyName := fmt.Sprintf("acctest-%d", acctest.RandInt())
|
|
||||||
config := fmt.Sprintf(testAccTritonKey_basic, keyName, testAccTritonKey_basicMaterial)
|
|
||||||
|
|
||||||
resource.Test(t, resource.TestCase{
|
|
||||||
PreCheck: func() { testAccPreCheck(t) },
|
|
||||||
Providers: testAccProviders,
|
|
||||||
CheckDestroy: testCheckTritonKeyDestroy,
|
|
||||||
Steps: []resource.TestStep{
|
|
||||||
resource.TestStep{
|
|
||||||
Config: config,
|
|
||||||
Check: resource.ComposeTestCheckFunc(
|
|
||||||
testCheckTritonKeyExists("triton_key.test"),
|
|
||||||
func(*terraform.State) error {
|
|
||||||
time.Sleep(10 * time.Second)
|
|
||||||
return nil
|
|
||||||
},
|
|
||||||
),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func testCheckTritonKeyExists(name string) resource.TestCheckFunc {
|
|
||||||
return func(s *terraform.State) error {
|
|
||||||
// Ensure we have enough information in state to look up in API
|
|
||||||
rs, ok := s.RootModule().Resources[name]
|
|
||||||
if !ok {
|
|
||||||
return fmt.Errorf("Not found: %s", name)
|
|
||||||
}
|
|
||||||
conn := testAccProvider.Meta().(*cloudapi.Client)
|
|
||||||
|
|
||||||
rule, err := conn.GetKey(rs.Primary.ID)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("Bad: Check Key Exists: %s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if rule == nil {
|
|
||||||
return fmt.Errorf("Bad: Key %q does not exist", rs.Primary.ID)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func testCheckTritonKeyDestroy(s *terraform.State) error {
|
|
||||||
conn := testAccProvider.Meta().(*cloudapi.Client)
|
|
||||||
|
|
||||||
return resource.Retry(1*time.Minute, func() *resource.RetryError {
|
|
||||||
for _, rs := range s.RootModule().Resources {
|
|
||||||
if rs.Type != "triton_key" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
resp, err := conn.GetKey(rs.Primary.ID)
|
|
||||||
if err != nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if resp != nil {
|
|
||||||
return resource.RetryableError(fmt.Errorf("Bad: Key %q still exists", rs.Primary.ID))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
var testAccTritonKey_basic = `
|
|
||||||
resource "triton_key" "test" {
|
|
||||||
name = "%s"
|
|
||||||
key = "%s"
|
|
||||||
}
|
|
||||||
`
|
|
||||||
|
|
||||||
const testAccTritonKey_basicMaterial = `ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDL18KJIe8N7FxcgOMtabo10qZEDyYUSlOpsh/EYrugQCQHMKuNytog1lhFNZNk4LGNAz5L8/btG9+/axY/PfundbjR3SXt0hupAGQIVHuygWTr7foj5iGhckrEM+r3eMCXqoCnIFLhDZLDcq/zN2MxNbqDKcWSYmc8ul9dZWuiQpKOL+0nNXjhYA8Ewu+07kVAtsZD0WfvnAUjxmYb3rB15eBWk7gLxHrOPfZpeDSvOOX2bmzikpLn+L5NKrJsLrzO6hU/rpxD4OTHLULcsnIts3lYH8hShU8uY5ry94PBzdix++se3pUGvNSe967fKlHw3Ymh9nE/LJDQnzTNyFMj James@jn-mpb13`
|
|
|
@ -1,436 +0,0 @@
|
||||||
package triton
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"reflect"
|
|
||||||
"regexp"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/hashicorp/terraform/helper/schema"
|
|
||||||
"github.com/joyent/gosdc/cloudapi"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
machineStateRunning = "running"
|
|
||||||
machineStateStopped = "stopped"
|
|
||||||
machineStateDeleted = "deleted"
|
|
||||||
|
|
||||||
machineStateChangeTimeout = 10 * time.Minute
|
|
||||||
machineStateChangeCheckInterval = 10 * time.Second
|
|
||||||
|
|
||||||
resourceMachineMetadataKeys = map[string]string{
|
|
||||||
// semantics: "schema_name": "metadata_name"
|
|
||||||
"root_authorized_keys": "root_authorized_keys",
|
|
||||||
"user_script": "user-script",
|
|
||||||
"user_data": "user-data",
|
|
||||||
"administrator_pw": "administrator-pw",
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
func resourceMachine() *schema.Resource {
|
|
||||||
return &schema.Resource{
|
|
||||||
Create: resourceMachineCreate,
|
|
||||||
Exists: resourceMachineExists,
|
|
||||||
Read: resourceMachineRead,
|
|
||||||
Update: resourceMachineUpdate,
|
|
||||||
Delete: resourceMachineDelete,
|
|
||||||
|
|
||||||
Schema: map[string]*schema.Schema{
|
|
||||||
"name": {
|
|
||||||
Description: "friendly name",
|
|
||||||
Type: schema.TypeString,
|
|
||||||
Optional: true,
|
|
||||||
Computed: true,
|
|
||||||
ValidateFunc: resourceMachineValidateName,
|
|
||||||
},
|
|
||||||
"type": {
|
|
||||||
Description: "machine type (smartmachine or virtualmachine)",
|
|
||||||
Type: schema.TypeString,
|
|
||||||
Computed: true,
|
|
||||||
},
|
|
||||||
"state": {
|
|
||||||
Description: "current state of the machine",
|
|
||||||
Type: schema.TypeString,
|
|
||||||
Computed: true,
|
|
||||||
},
|
|
||||||
"dataset": {
|
|
||||||
Description: "dataset URN the machine was provisioned with",
|
|
||||||
Type: schema.TypeString,
|
|
||||||
Computed: true,
|
|
||||||
},
|
|
||||||
"memory": {
|
|
||||||
Description: "amount of memory the machine has (in Mb)",
|
|
||||||
Type: schema.TypeInt,
|
|
||||||
Computed: true,
|
|
||||||
},
|
|
||||||
"disk": {
|
|
||||||
Description: "amount of disk the machine has (in Gb)",
|
|
||||||
Type: schema.TypeInt,
|
|
||||||
Computed: true,
|
|
||||||
},
|
|
||||||
"ips": {
|
|
||||||
Description: "IP addresses the machine has",
|
|
||||||
Type: schema.TypeList,
|
|
||||||
Computed: true,
|
|
||||||
Elem: &schema.Schema{
|
|
||||||
Type: schema.TypeString,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"tags": {
|
|
||||||
Description: "machine tags",
|
|
||||||
Type: schema.TypeMap,
|
|
||||||
Optional: true,
|
|
||||||
},
|
|
||||||
"created": {
|
|
||||||
Description: "when the machine was created",
|
|
||||||
Type: schema.TypeString,
|
|
||||||
Computed: true,
|
|
||||||
},
|
|
||||||
"updated": {
|
|
||||||
Description: "when the machine was update",
|
|
||||||
Type: schema.TypeString,
|
|
||||||
Computed: true,
|
|
||||||
},
|
|
||||||
"package": {
|
|
||||||
Description: "name of the package to use on provisioning",
|
|
||||||
Type: schema.TypeString,
|
|
||||||
Required: true,
|
|
||||||
},
|
|
||||||
"image": {
|
|
||||||
Description: "image UUID",
|
|
||||||
Type: schema.TypeString,
|
|
||||||
Required: true,
|
|
||||||
ForceNew: true,
|
|
||||||
// TODO: validate that the UUID is valid
|
|
||||||
},
|
|
||||||
"primaryip": {
|
|
||||||
Description: "the primary (public) IP address for the machine",
|
|
||||||
Type: schema.TypeString,
|
|
||||||
Computed: true,
|
|
||||||
},
|
|
||||||
"networks": {
|
|
||||||
Description: "desired network IDs",
|
|
||||||
Type: schema.TypeList,
|
|
||||||
Optional: true,
|
|
||||||
Computed: true,
|
|
||||||
// TODO: this really should ForceNew but the Network IDs don't seem to
|
|
||||||
// be returned by the API, meaning if we track them here TF will replace
|
|
||||||
// the resource on every run.
|
|
||||||
// ForceNew: true,
|
|
||||||
Elem: &schema.Schema{
|
|
||||||
Type: schema.TypeString,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"firewall_enabled": {
|
|
||||||
Description: "enable firewall for this machine",
|
|
||||||
Type: schema.TypeBool,
|
|
||||||
Optional: true,
|
|
||||||
Default: false,
|
|
||||||
},
|
|
||||||
|
|
||||||
// computed resources from metadata
|
|
||||||
"root_authorized_keys": {
|
|
||||||
Description: "authorized keys for the root user on this machine",
|
|
||||||
Type: schema.TypeString,
|
|
||||||
Optional: true,
|
|
||||||
Computed: true,
|
|
||||||
},
|
|
||||||
"user_script": {
|
|
||||||
Description: "user script to run on boot (every boot on SmartMachines)",
|
|
||||||
Type: schema.TypeString,
|
|
||||||
Optional: true,
|
|
||||||
Computed: true,
|
|
||||||
},
|
|
||||||
"user_data": {
|
|
||||||
Description: "copied to machine on boot",
|
|
||||||
Type: schema.TypeString,
|
|
||||||
Optional: true,
|
|
||||||
Computed: true,
|
|
||||||
},
|
|
||||||
"administrator_pw": {
|
|
||||||
Description: "administrator's initial password (Windows only)",
|
|
||||||
Type: schema.TypeString,
|
|
||||||
Optional: true,
|
|
||||||
Computed: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func resourceMachineCreate(d *schema.ResourceData, meta interface{}) error {
|
|
||||||
client := meta.(*cloudapi.Client)
|
|
||||||
|
|
||||||
var networks []string
|
|
||||||
for _, network := range d.Get("networks").([]interface{}) {
|
|
||||||
networks = append(networks, network.(string))
|
|
||||||
}
|
|
||||||
|
|
||||||
metadata := map[string]string{}
|
|
||||||
for schemaName, metadataKey := range resourceMachineMetadataKeys {
|
|
||||||
if v, ok := d.GetOk(schemaName); ok {
|
|
||||||
metadata[metadataKey] = v.(string)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
tags := map[string]string{}
|
|
||||||
for k, v := range d.Get("tags").(map[string]interface{}) {
|
|
||||||
tags[k] = v.(string)
|
|
||||||
}
|
|
||||||
|
|
||||||
machine, err := client.CreateMachine(cloudapi.CreateMachineOpts{
|
|
||||||
Name: d.Get("name").(string),
|
|
||||||
Package: d.Get("package").(string),
|
|
||||||
Image: d.Get("image").(string),
|
|
||||||
Networks: networks,
|
|
||||||
Metadata: metadata,
|
|
||||||
Tags: tags,
|
|
||||||
FirewallEnabled: d.Get("firewall_enabled").(bool),
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = waitForMachineState(client, machine.Id, machineStateRunning, machineStateChangeTimeout)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// refresh state after it provisions
|
|
||||||
d.SetId(machine.Id)
|
|
||||||
err = resourceMachineRead(d, meta)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func resourceMachineExists(d *schema.ResourceData, meta interface{}) (bool, error) {
|
|
||||||
client := meta.(*cloudapi.Client)
|
|
||||||
|
|
||||||
machine, err := client.GetMachine(d.Id())
|
|
||||||
|
|
||||||
return machine != nil && err == nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func resourceMachineRead(d *schema.ResourceData, meta interface{}) error {
|
|
||||||
client := meta.(*cloudapi.Client)
|
|
||||||
|
|
||||||
machine, err := client.GetMachine(d.Id())
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
d.SetId(machine.Id)
|
|
||||||
d.Set("name", machine.Name)
|
|
||||||
d.Set("type", machine.Type)
|
|
||||||
d.Set("state", machine.State)
|
|
||||||
d.Set("dataset", machine.Dataset)
|
|
||||||
d.Set("memory", machine.Memory)
|
|
||||||
d.Set("disk", machine.Disk)
|
|
||||||
d.Set("ips", machine.IPs)
|
|
||||||
d.Set("tags", machine.Tags)
|
|
||||||
d.Set("created", machine.Created)
|
|
||||||
d.Set("updated", machine.Updated)
|
|
||||||
d.Set("package", machine.Package)
|
|
||||||
d.Set("image", machine.Image)
|
|
||||||
d.Set("primaryip", machine.PrimaryIP)
|
|
||||||
d.Set("networks", machine.Networks)
|
|
||||||
d.Set("firewall_enabled", machine.FirewallEnabled)
|
|
||||||
|
|
||||||
// computed attributes from metadata
|
|
||||||
for schemaName, metadataKey := range resourceMachineMetadataKeys {
|
|
||||||
d.Set(schemaName, machine.Metadata[metadataKey])
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func resourceMachineUpdate(d *schema.ResourceData, meta interface{}) error {
|
|
||||||
client := meta.(*cloudapi.Client)
|
|
||||||
|
|
||||||
d.Partial(true)
|
|
||||||
|
|
||||||
if d.HasChange("name") {
|
|
||||||
if err := client.RenameMachine(d.Id(), d.Get("name").(string)); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
err := waitFor(
|
|
||||||
func() (bool, error) {
|
|
||||||
machine, err := client.GetMachine(d.Id())
|
|
||||||
return machine.Name == d.Get("name").(string), err
|
|
||||||
},
|
|
||||||
machineStateChangeCheckInterval,
|
|
||||||
1*time.Minute,
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
d.SetPartial("name")
|
|
||||||
}
|
|
||||||
|
|
||||||
if d.HasChange("tags") {
|
|
||||||
tags := map[string]string{}
|
|
||||||
for k, v := range d.Get("tags").(map[string]interface{}) {
|
|
||||||
tags[k] = v.(string)
|
|
||||||
}
|
|
||||||
|
|
||||||
var err error
|
|
||||||
if len(tags) == 0 {
|
|
||||||
err = client.DeleteMachineTags(d.Id())
|
|
||||||
} else {
|
|
||||||
_, err = client.ReplaceMachineTags(d.Id(), tags)
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = waitFor(
|
|
||||||
func() (bool, error) {
|
|
||||||
machine, err := client.GetMachine(d.Id())
|
|
||||||
return reflect.DeepEqual(machine.Tags, tags), err
|
|
||||||
},
|
|
||||||
machineStateChangeCheckInterval,
|
|
||||||
1*time.Minute,
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
d.SetPartial("tags")
|
|
||||||
}
|
|
||||||
|
|
||||||
if d.HasChange("package") {
|
|
||||||
if err := client.ResizeMachine(d.Id(), d.Get("package").(string)); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
err := waitFor(
|
|
||||||
func() (bool, error) {
|
|
||||||
machine, err := client.GetMachine(d.Id())
|
|
||||||
return machine.Package == d.Get("package").(string) && machine.State == machineStateRunning, err
|
|
||||||
},
|
|
||||||
machineStateChangeCheckInterval,
|
|
||||||
machineStateChangeTimeout,
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
d.SetPartial("package")
|
|
||||||
}
|
|
||||||
|
|
||||||
if d.HasChange("firewall_enabled") {
|
|
||||||
var err error
|
|
||||||
if d.Get("firewall_enabled").(bool) {
|
|
||||||
err = client.EnableFirewallMachine(d.Id())
|
|
||||||
} else {
|
|
||||||
err = client.DisableFirewallMachine(d.Id())
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
d.SetPartial("firewall_enabled")
|
|
||||||
}
|
|
||||||
|
|
||||||
// metadata stuff
|
|
||||||
metadata := map[string]string{}
|
|
||||||
for schemaName, metadataKey := range resourceMachineMetadataKeys {
|
|
||||||
if d.HasChange(schemaName) {
|
|
||||||
metadata[metadataKey] = d.Get(schemaName).(string)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if len(metadata) > 0 {
|
|
||||||
_, err := client.UpdateMachineMetadata(d.Id(), metadata)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = waitFor(
|
|
||||||
func() (bool, error) {
|
|
||||||
machine, err := client.GetMachine(d.Id())
|
|
||||||
return reflect.DeepEqual(machine.Metadata, metadata), err
|
|
||||||
},
|
|
||||||
machineStateChangeCheckInterval,
|
|
||||||
1*time.Minute,
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
for schemaName := range resourceMachineMetadataKeys {
|
|
||||||
if d.HasChange(schemaName) {
|
|
||||||
d.SetPartial(schemaName)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
d.Partial(false)
|
|
||||||
|
|
||||||
err := resourceMachineRead(d, meta)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func resourceMachineDelete(d *schema.ResourceData, meta interface{}) error {
|
|
||||||
client := meta.(*cloudapi.Client)
|
|
||||||
|
|
||||||
state, err := readMachineState(client, d.Id())
|
|
||||||
if state != machineStateStopped {
|
|
||||||
err = client.StopMachine(d.Id())
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
waitForMachineState(client, d.Id(), machineStateStopped, machineStateChangeTimeout)
|
|
||||||
}
|
|
||||||
|
|
||||||
err = client.DeleteMachine(d.Id())
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
waitForMachineState(client, d.Id(), machineStateDeleted, machineStateChangeTimeout)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func readMachineState(api *cloudapi.Client, id string) (string, error) {
|
|
||||||
machine, err := api.GetMachine(id)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
return machine.State, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// waitForMachineState waits for a machine to be in the desired state (waiting
|
|
||||||
// some seconds between each poll). If it doesn't reach the state within the
|
|
||||||
// duration specified in `timeout`, it returns ErrMachineStateTimeout.
|
|
||||||
func waitForMachineState(api *cloudapi.Client, id, state string, timeout time.Duration) error {
|
|
||||||
return waitFor(
|
|
||||||
func() (bool, error) {
|
|
||||||
currentState, err := readMachineState(api, id)
|
|
||||||
return currentState == state, err
|
|
||||||
},
|
|
||||||
machineStateChangeCheckInterval,
|
|
||||||
machineStateChangeTimeout,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
func resourceMachineValidateName(value interface{}, name string) (warnings []string, errors []error) {
|
|
||||||
warnings = []string{}
|
|
||||||
errors = []error{}
|
|
||||||
|
|
||||||
r := regexp.MustCompile(`^[a-zA-Z0-9][a-zA-Z0-9\_\.\-]*$`)
|
|
||||||
if !r.Match([]byte(value.(string))) {
|
|
||||||
errors = append(errors, fmt.Errorf(`"%s" is not a valid %s`, value.(string), name))
|
|
||||||
}
|
|
||||||
|
|
||||||
return warnings, errors
|
|
||||||
}
|
|
|
@ -1,90 +0,0 @@
|
||||||
package triton
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"testing"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/hashicorp/terraform/helper/acctest"
|
|
||||||
"github.com/hashicorp/terraform/helper/resource"
|
|
||||||
"github.com/hashicorp/terraform/terraform"
|
|
||||||
"github.com/joyent/gosdc/cloudapi"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestAccTritonMachine_basic(t *testing.T) {
|
|
||||||
machineName := fmt.Sprintf("acctest-%d", acctest.RandInt())
|
|
||||||
config := fmt.Sprintf(testAccTritonMachine_basic, machineName)
|
|
||||||
|
|
||||||
resource.Test(t, resource.TestCase{
|
|
||||||
PreCheck: func() { testAccPreCheck(t) },
|
|
||||||
Providers: testAccProviders,
|
|
||||||
CheckDestroy: testCheckTritonMachineDestroy,
|
|
||||||
Steps: []resource.TestStep{
|
|
||||||
resource.TestStep{
|
|
||||||
Config: config,
|
|
||||||
Check: resource.ComposeTestCheckFunc(
|
|
||||||
testCheckTritonMachineExists("triton_machine.test"),
|
|
||||||
func(*terraform.State) error {
|
|
||||||
time.Sleep(10 * time.Second)
|
|
||||||
return nil
|
|
||||||
},
|
|
||||||
),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func testCheckTritonMachineExists(name string) resource.TestCheckFunc {
|
|
||||||
return func(s *terraform.State) error {
|
|
||||||
// Ensure we have enough information in state to look up in API
|
|
||||||
rs, ok := s.RootModule().Resources[name]
|
|
||||||
if !ok {
|
|
||||||
return fmt.Errorf("Not found: %s", name)
|
|
||||||
}
|
|
||||||
conn := testAccProvider.Meta().(*cloudapi.Client)
|
|
||||||
|
|
||||||
rule, err := conn.GetMachine(rs.Primary.ID)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("Bad: Check Machine Exists: %s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if rule == nil {
|
|
||||||
return fmt.Errorf("Bad: Machine %q does not exist", rs.Primary.ID)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func testCheckTritonMachineDestroy(s *terraform.State) error {
|
|
||||||
conn := testAccProvider.Meta().(*cloudapi.Client)
|
|
||||||
|
|
||||||
for _, rs := range s.RootModule().Resources {
|
|
||||||
if rs.Type != "triton_machine" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
resp, err := conn.GetMachine(rs.Primary.ID)
|
|
||||||
if err != nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if resp != nil {
|
|
||||||
return fmt.Errorf("Bad: Machine %q still exists", rs.Primary.ID)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
var testAccTritonMachine_basic = `
|
|
||||||
resource "triton_machine" "test" {
|
|
||||||
name = "%s"
|
|
||||||
package = "g3-standard-0.25-smartos"
|
|
||||||
image = "842e6fa6-6e9b-11e5-8402-1b490459e334"
|
|
||||||
|
|
||||||
tags = {
|
|
||||||
test = "hello!"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`
|
|
|
@ -1,30 +0,0 @@
|
||||||
package triton
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
// ErrTimeout is returned when waiting for state change
|
|
||||||
ErrTimeout = errors.New("timed out while waiting for resource change")
|
|
||||||
)
|
|
||||||
|
|
||||||
func waitFor(f func() (bool, error), every, timeout time.Duration) error {
|
|
||||||
start := time.Now()
|
|
||||||
|
|
||||||
for time.Since(start) <= timeout {
|
|
||||||
stop, err := f()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if stop {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
time.Sleep(every)
|
|
||||||
}
|
|
||||||
|
|
||||||
return ErrTimeout
|
|
||||||
}
|
|
|
@ -1,26 +0,0 @@
|
||||||
# Compiled Object files, Static and Dynamic libs (Shared Objects)
|
|
||||||
*.o
|
|
||||||
*.a
|
|
||||||
*.so
|
|
||||||
|
|
||||||
# Folders
|
|
||||||
_obj
|
|
||||||
_test
|
|
||||||
|
|
||||||
# Architecture specific extensions/prefixes
|
|
||||||
*.[568vq]
|
|
||||||
[568vq].out
|
|
||||||
|
|
||||||
*.cgo1.go
|
|
||||||
*.cgo2.c
|
|
||||||
_cgo_defun.c
|
|
||||||
_cgo_gotypes.go
|
|
||||||
_cgo_export.*
|
|
||||||
|
|
||||||
_testmain.go
|
|
||||||
|
|
||||||
*.exe
|
|
||||||
|
|
||||||
# IntelliJ files
|
|
||||||
.idea
|
|
||||||
*.iml
|
|
|
@ -1,674 +0,0 @@
|
||||||
GNU GENERAL PUBLIC LICENSE
|
|
||||||
Version 3, 29 June 2007
|
|
||||||
|
|
||||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
|
||||||
Everyone is permitted to copy and distribute verbatim copies
|
|
||||||
of this license document, but changing it is not allowed.
|
|
||||||
|
|
||||||
Preamble
|
|
||||||
|
|
||||||
The GNU General Public License is a free, copyleft license for
|
|
||||||
software and other kinds of works.
|
|
||||||
|
|
||||||
The licenses for most software and other practical works are designed
|
|
||||||
to take away your freedom to share and change the works. By contrast,
|
|
||||||
the GNU General Public License is intended to guarantee your freedom to
|
|
||||||
share and change all versions of a program--to make sure it remains free
|
|
||||||
software for all its users. We, the Free Software Foundation, use the
|
|
||||||
GNU General Public License for most of our software; it applies also to
|
|
||||||
any other work released this way by its authors. You can apply it to
|
|
||||||
your programs, too.
|
|
||||||
|
|
||||||
When we speak of free software, we are referring to freedom, not
|
|
||||||
price. Our General Public Licenses are designed to make sure that you
|
|
||||||
have the freedom to distribute copies of free software (and charge for
|
|
||||||
them if you wish), that you receive source code or can get it if you
|
|
||||||
want it, that you can change the software or use pieces of it in new
|
|
||||||
free programs, and that you know you can do these things.
|
|
||||||
|
|
||||||
To protect your rights, we need to prevent others from denying you
|
|
||||||
these rights or asking you to surrender the rights. Therefore, you have
|
|
||||||
certain responsibilities if you distribute copies of the software, or if
|
|
||||||
you modify it: responsibilities to respect the freedom of others.
|
|
||||||
|
|
||||||
For example, if you distribute copies of such a program, whether
|
|
||||||
gratis or for a fee, you must pass on to the recipients the same
|
|
||||||
freedoms that you received. You must make sure that they, too, receive
|
|
||||||
or can get the source code. And you must show them these terms so they
|
|
||||||
know their rights.
|
|
||||||
|
|
||||||
Developers that use the GNU GPL protect your rights with two steps:
|
|
||||||
(1) assert copyright on the software, and (2) offer you this License
|
|
||||||
giving you legal permission to copy, distribute and/or modify it.
|
|
||||||
|
|
||||||
For the developers' and authors' protection, the GPL clearly explains
|
|
||||||
that there is no warranty for this free software. For both users' and
|
|
||||||
authors' sake, the GPL requires that modified versions be marked as
|
|
||||||
changed, so that their problems will not be attributed erroneously to
|
|
||||||
authors of previous versions.
|
|
||||||
|
|
||||||
Some devices are designed to deny users access to install or run
|
|
||||||
modified versions of the software inside them, although the manufacturer
|
|
||||||
can do so. This is fundamentally incompatible with the aim of
|
|
||||||
protecting users' freedom to change the software. The systematic
|
|
||||||
pattern of such abuse occurs in the area of products for individuals to
|
|
||||||
use, which is precisely where it is most unacceptable. Therefore, we
|
|
||||||
have designed this version of the GPL to prohibit the practice for those
|
|
||||||
products. If such problems arise substantially in other domains, we
|
|
||||||
stand ready to extend this provision to those domains in future versions
|
|
||||||
of the GPL, as needed to protect the freedom of users.
|
|
||||||
|
|
||||||
Finally, every program is threatened constantly by software patents.
|
|
||||||
States should not allow patents to restrict development and use of
|
|
||||||
software on general-purpose computers, but in those that do, we wish to
|
|
||||||
avoid the special danger that patents applied to a free program could
|
|
||||||
make it effectively proprietary. To prevent this, the GPL assures that
|
|
||||||
patents cannot be used to render the program non-free.
|
|
||||||
|
|
||||||
The precise terms and conditions for copying, distribution and
|
|
||||||
modification follow.
|
|
||||||
|
|
||||||
TERMS AND CONDITIONS
|
|
||||||
|
|
||||||
0. Definitions.
|
|
||||||
|
|
||||||
"This License" refers to version 3 of the GNU General Public License.
|
|
||||||
|
|
||||||
"Copyright" also means copyright-like laws that apply to other kinds of
|
|
||||||
works, such as semiconductor masks.
|
|
||||||
|
|
||||||
"The Program" refers to any copyrightable work licensed under this
|
|
||||||
License. Each licensee is addressed as "you". "Licensees" and
|
|
||||||
"recipients" may be individuals or organizations.
|
|
||||||
|
|
||||||
To "modify" a work means to copy from or adapt all or part of the work
|
|
||||||
in a fashion requiring copyright permission, other than the making of an
|
|
||||||
exact copy. The resulting work is called a "modified version" of the
|
|
||||||
earlier work or a work "based on" the earlier work.
|
|
||||||
|
|
||||||
A "covered work" means either the unmodified Program or a work based
|
|
||||||
on the Program.
|
|
||||||
|
|
||||||
To "propagate" a work means to do anything with it that, without
|
|
||||||
permission, would make you directly or secondarily liable for
|
|
||||||
infringement under applicable copyright law, except executing it on a
|
|
||||||
computer or modifying a private copy. Propagation includes copying,
|
|
||||||
distribution (with or without modification), making available to the
|
|
||||||
public, and in some countries other activities as well.
|
|
||||||
|
|
||||||
To "convey" a work means any kind of propagation that enables other
|
|
||||||
parties to make or receive copies. Mere interaction with a user through
|
|
||||||
a computer network, with no transfer of a copy, is not conveying.
|
|
||||||
|
|
||||||
An interactive user interface displays "Appropriate Legal Notices"
|
|
||||||
to the extent that it includes a convenient and prominently visible
|
|
||||||
feature that (1) displays an appropriate copyright notice, and (2)
|
|
||||||
tells the user that there is no warranty for the work (except to the
|
|
||||||
extent that warranties are provided), that licensees may convey the
|
|
||||||
work under this License, and how to view a copy of this License. If
|
|
||||||
the interface presents a list of user commands or options, such as a
|
|
||||||
menu, a prominent item in the list meets this criterion.
|
|
||||||
|
|
||||||
1. Source Code.
|
|
||||||
|
|
||||||
The "source code" for a work means the preferred form of the work
|
|
||||||
for making modifications to it. "Object code" means any non-source
|
|
||||||
form of a work.
|
|
||||||
|
|
||||||
A "Standard Interface" means an interface that either is an official
|
|
||||||
standard defined by a recognized standards body, or, in the case of
|
|
||||||
interfaces specified for a particular programming language, one that
|
|
||||||
is widely used among developers working in that language.
|
|
||||||
|
|
||||||
The "System Libraries" of an executable work include anything, other
|
|
||||||
than the work as a whole, that (a) is included in the normal form of
|
|
||||||
packaging a Major Component, but which is not part of that Major
|
|
||||||
Component, and (b) serves only to enable use of the work with that
|
|
||||||
Major Component, or to implement a Standard Interface for which an
|
|
||||||
implementation is available to the public in source code form. A
|
|
||||||
"Major Component", in this context, means a major essential component
|
|
||||||
(kernel, window system, and so on) of the specific operating system
|
|
||||||
(if any) on which the executable work runs, or a compiler used to
|
|
||||||
produce the work, or an object code interpreter used to run it.
|
|
||||||
|
|
||||||
The "Corresponding Source" for a work in object code form means all
|
|
||||||
the source code needed to generate, install, and (for an executable
|
|
||||||
work) run the object code and to modify the work, including scripts to
|
|
||||||
control those activities. However, it does not include the work's
|
|
||||||
System Libraries, or general-purpose tools or generally available free
|
|
||||||
programs which are used unmodified in performing those activities but
|
|
||||||
which are not part of the work. For example, Corresponding Source
|
|
||||||
includes interface definition files associated with source files for
|
|
||||||
the work, and the source code for shared libraries and dynamically
|
|
||||||
linked subprograms that the work is specifically designed to require,
|
|
||||||
such as by intimate data communication or control flow between those
|
|
||||||
subprograms and other parts of the work.
|
|
||||||
|
|
||||||
The Corresponding Source need not include anything that users
|
|
||||||
can regenerate automatically from other parts of the Corresponding
|
|
||||||
Source.
|
|
||||||
|
|
||||||
The Corresponding Source for a work in source code form is that
|
|
||||||
same work.
|
|
||||||
|
|
||||||
2. Basic Permissions.
|
|
||||||
|
|
||||||
All rights granted under this License are granted for the term of
|
|
||||||
copyright on the Program, and are irrevocable provided the stated
|
|
||||||
conditions are met. This License explicitly affirms your unlimited
|
|
||||||
permission to run the unmodified Program. The output from running a
|
|
||||||
covered work is covered by this License only if the output, given its
|
|
||||||
content, constitutes a covered work. This License acknowledges your
|
|
||||||
rights of fair use or other equivalent, as provided by copyright law.
|
|
||||||
|
|
||||||
You may make, run and propagate covered works that you do not
|
|
||||||
convey, without conditions so long as your license otherwise remains
|
|
||||||
in force. You may convey covered works to others for the sole purpose
|
|
||||||
of having them make modifications exclusively for you, or provide you
|
|
||||||
with facilities for running those works, provided that you comply with
|
|
||||||
the terms of this License in conveying all material for which you do
|
|
||||||
not control copyright. Those thus making or running the covered works
|
|
||||||
for you must do so exclusively on your behalf, under your direction
|
|
||||||
and control, on terms that prohibit them from making any copies of
|
|
||||||
your copyrighted material outside their relationship with you.
|
|
||||||
|
|
||||||
Conveying under any other circumstances is permitted solely under
|
|
||||||
the conditions stated below. Sublicensing is not allowed; section 10
|
|
||||||
makes it unnecessary.
|
|
||||||
|
|
||||||
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
|
||||||
|
|
||||||
No covered work shall be deemed part of an effective technological
|
|
||||||
measure under any applicable law fulfilling obligations under article
|
|
||||||
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
|
||||||
similar laws prohibiting or restricting circumvention of such
|
|
||||||
measures.
|
|
||||||
|
|
||||||
When you convey a covered work, you waive any legal power to forbid
|
|
||||||
circumvention of technological measures to the extent such circumvention
|
|
||||||
is effected by exercising rights under this License with respect to
|
|
||||||
the covered work, and you disclaim any intention to limit operation or
|
|
||||||
modification of the work as a means of enforcing, against the work's
|
|
||||||
users, your or third parties' legal rights to forbid circumvention of
|
|
||||||
technological measures.
|
|
||||||
|
|
||||||
4. Conveying Verbatim Copies.
|
|
||||||
|
|
||||||
You may convey verbatim copies of the Program's source code as you
|
|
||||||
receive it, in any medium, provided that you conspicuously and
|
|
||||||
appropriately publish on each copy an appropriate copyright notice;
|
|
||||||
keep intact all notices stating that this License and any
|
|
||||||
non-permissive terms added in accord with section 7 apply to the code;
|
|
||||||
keep intact all notices of the absence of any warranty; and give all
|
|
||||||
recipients a copy of this License along with the Program.
|
|
||||||
|
|
||||||
You may charge any price or no price for each copy that you convey,
|
|
||||||
and you may offer support or warranty protection for a fee.
|
|
||||||
|
|
||||||
5. Conveying Modified Source Versions.
|
|
||||||
|
|
||||||
You may convey a work based on the Program, or the modifications to
|
|
||||||
produce it from the Program, in the form of source code under the
|
|
||||||
terms of section 4, provided that you also meet all of these conditions:
|
|
||||||
|
|
||||||
a) The work must carry prominent notices stating that you modified
|
|
||||||
it, and giving a relevant date.
|
|
||||||
|
|
||||||
b) The work must carry prominent notices stating that it is
|
|
||||||
released under this License and any conditions added under section
|
|
||||||
7. This requirement modifies the requirement in section 4 to
|
|
||||||
"keep intact all notices".
|
|
||||||
|
|
||||||
c) You must license the entire work, as a whole, under this
|
|
||||||
License to anyone who comes into possession of a copy. This
|
|
||||||
License will therefore apply, along with any applicable section 7
|
|
||||||
additional terms, to the whole of the work, and all its parts,
|
|
||||||
regardless of how they are packaged. This License gives no
|
|
||||||
permission to license the work in any other way, but it does not
|
|
||||||
invalidate such permission if you have separately received it.
|
|
||||||
|
|
||||||
d) If the work has interactive user interfaces, each must display
|
|
||||||
Appropriate Legal Notices; however, if the Program has interactive
|
|
||||||
interfaces that do not display Appropriate Legal Notices, your
|
|
||||||
work need not make them do so.
|
|
||||||
|
|
||||||
A compilation of a covered work with other separate and independent
|
|
||||||
works, which are not by their nature extensions of the covered work,
|
|
||||||
and which are not combined with it such as to form a larger program,
|
|
||||||
in or on a volume of a storage or distribution medium, is called an
|
|
||||||
"aggregate" if the compilation and its resulting copyright are not
|
|
||||||
used to limit the access or legal rights of the compilation's users
|
|
||||||
beyond what the individual works permit. Inclusion of a covered work
|
|
||||||
in an aggregate does not cause this License to apply to the other
|
|
||||||
parts of the aggregate.
|
|
||||||
|
|
||||||
6. Conveying Non-Source Forms.
|
|
||||||
|
|
||||||
You may convey a covered work in object code form under the terms
|
|
||||||
of sections 4 and 5, provided that you also convey the
|
|
||||||
machine-readable Corresponding Source under the terms of this License,
|
|
||||||
in one of these ways:
|
|
||||||
|
|
||||||
a) Convey the object code in, or embodied in, a physical product
|
|
||||||
(including a physical distribution medium), accompanied by the
|
|
||||||
Corresponding Source fixed on a durable physical medium
|
|
||||||
customarily used for software interchange.
|
|
||||||
|
|
||||||
b) Convey the object code in, or embodied in, a physical product
|
|
||||||
(including a physical distribution medium), accompanied by a
|
|
||||||
written offer, valid for at least three years and valid for as
|
|
||||||
long as you offer spare parts or customer support for that product
|
|
||||||
model, to give anyone who possesses the object code either (1) a
|
|
||||||
copy of the Corresponding Source for all the software in the
|
|
||||||
product that is covered by this License, on a durable physical
|
|
||||||
medium customarily used for software interchange, for a price no
|
|
||||||
more than your reasonable cost of physically performing this
|
|
||||||
conveying of source, or (2) access to copy the
|
|
||||||
Corresponding Source from a network server at no charge.
|
|
||||||
|
|
||||||
c) Convey individual copies of the object code with a copy of the
|
|
||||||
written offer to provide the Corresponding Source. This
|
|
||||||
alternative is allowed only occasionally and noncommercially, and
|
|
||||||
only if you received the object code with such an offer, in accord
|
|
||||||
with subsection 6b.
|
|
||||||
|
|
||||||
d) Convey the object code by offering access from a designated
|
|
||||||
place (gratis or for a charge), and offer equivalent access to the
|
|
||||||
Corresponding Source in the same way through the same place at no
|
|
||||||
further charge. You need not require recipients to copy the
|
|
||||||
Corresponding Source along with the object code. If the place to
|
|
||||||
copy the object code is a network server, the Corresponding Source
|
|
||||||
may be on a different server (operated by you or a third party)
|
|
||||||
that supports equivalent copying facilities, provided you maintain
|
|
||||||
clear directions next to the object code saying where to find the
|
|
||||||
Corresponding Source. Regardless of what server hosts the
|
|
||||||
Corresponding Source, you remain obligated to ensure that it is
|
|
||||||
available for as long as needed to satisfy these requirements.
|
|
||||||
|
|
||||||
e) Convey the object code using peer-to-peer transmission, provided
|
|
||||||
you inform other peers where the object code and Corresponding
|
|
||||||
Source of the work are being offered to the general public at no
|
|
||||||
charge under subsection 6d.
|
|
||||||
|
|
||||||
A separable portion of the object code, whose source code is excluded
|
|
||||||
from the Corresponding Source as a System Library, need not be
|
|
||||||
included in conveying the object code work.
|
|
||||||
|
|
||||||
A "User Product" is either (1) a "consumer product", which means any
|
|
||||||
tangible personal property which is normally used for personal, family,
|
|
||||||
or household purposes, or (2) anything designed or sold for incorporation
|
|
||||||
into a dwelling. In determining whether a product is a consumer product,
|
|
||||||
doubtful cases shall be resolved in favor of coverage. For a particular
|
|
||||||
product received by a particular user, "normally used" refers to a
|
|
||||||
typical or common use of that class of product, regardless of the status
|
|
||||||
of the particular user or of the way in which the particular user
|
|
||||||
actually uses, or expects or is expected to use, the product. A product
|
|
||||||
is a consumer product regardless of whether the product has substantial
|
|
||||||
commercial, industrial or non-consumer uses, unless such uses represent
|
|
||||||
the only significant mode of use of the product.
|
|
||||||
|
|
||||||
"Installation Information" for a User Product means any methods,
|
|
||||||
procedures, authorization keys, or other information required to install
|
|
||||||
and execute modified versions of a covered work in that User Product from
|
|
||||||
a modified version of its Corresponding Source. The information must
|
|
||||||
suffice to ensure that the continued functioning of the modified object
|
|
||||||
code is in no case prevented or interfered with solely because
|
|
||||||
modification has been made.
|
|
||||||
|
|
||||||
If you convey an object code work under this section in, or with, or
|
|
||||||
specifically for use in, a User Product, and the conveying occurs as
|
|
||||||
part of a transaction in which the right of possession and use of the
|
|
||||||
User Product is transferred to the recipient in perpetuity or for a
|
|
||||||
fixed term (regardless of how the transaction is characterized), the
|
|
||||||
Corresponding Source conveyed under this section must be accompanied
|
|
||||||
by the Installation Information. But this requirement does not apply
|
|
||||||
if neither you nor any third party retains the ability to install
|
|
||||||
modified object code on the User Product (for example, the work has
|
|
||||||
been installed in ROM).
|
|
||||||
|
|
||||||
The requirement to provide Installation Information does not include a
|
|
||||||
requirement to continue to provide support service, warranty, or updates
|
|
||||||
for a work that has been modified or installed by the recipient, or for
|
|
||||||
the User Product in which it has been modified or installed. Access to a
|
|
||||||
network may be denied when the modification itself materially and
|
|
||||||
adversely affects the operation of the network or violates the rules and
|
|
||||||
protocols for communication across the network.
|
|
||||||
|
|
||||||
Corresponding Source conveyed, and Installation Information provided,
|
|
||||||
in accord with this section must be in a format that is publicly
|
|
||||||
documented (and with an implementation available to the public in
|
|
||||||
source code form), and must require no special password or key for
|
|
||||||
unpacking, reading or copying.
|
|
||||||
|
|
||||||
7. Additional Terms.
|
|
||||||
|
|
||||||
"Additional permissions" are terms that supplement the terms of this
|
|
||||||
License by making exceptions from one or more of its conditions.
|
|
||||||
Additional permissions that are applicable to the entire Program shall
|
|
||||||
be treated as though they were included in this License, to the extent
|
|
||||||
that they are valid under applicable law. If additional permissions
|
|
||||||
apply only to part of the Program, that part may be used separately
|
|
||||||
under those permissions, but the entire Program remains governed by
|
|
||||||
this License without regard to the additional permissions.
|
|
||||||
|
|
||||||
When you convey a copy of a covered work, you may at your option
|
|
||||||
remove any additional permissions from that copy, or from any part of
|
|
||||||
it. (Additional permissions may be written to require their own
|
|
||||||
removal in certain cases when you modify the work.) You may place
|
|
||||||
additional permissions on material, added by you to a covered work,
|
|
||||||
for which you have or can give appropriate copyright permission.
|
|
||||||
|
|
||||||
Notwithstanding any other provision of this License, for material you
|
|
||||||
add to a covered work, you may (if authorized by the copyright holders of
|
|
||||||
that material) supplement the terms of this License with terms:
|
|
||||||
|
|
||||||
a) Disclaiming warranty or limiting liability differently from the
|
|
||||||
terms of sections 15 and 16 of this License; or
|
|
||||||
|
|
||||||
b) Requiring preservation of specified reasonable legal notices or
|
|
||||||
author attributions in that material or in the Appropriate Legal
|
|
||||||
Notices displayed by works containing it; or
|
|
||||||
|
|
||||||
c) Prohibiting misrepresentation of the origin of that material, or
|
|
||||||
requiring that modified versions of such material be marked in
|
|
||||||
reasonable ways as different from the original version; or
|
|
||||||
|
|
||||||
d) Limiting the use for publicity purposes of names of licensors or
|
|
||||||
authors of the material; or
|
|
||||||
|
|
||||||
e) Declining to grant rights under trademark law for use of some
|
|
||||||
trade names, trademarks, or service marks; or
|
|
||||||
|
|
||||||
f) Requiring indemnification of licensors and authors of that
|
|
||||||
material by anyone who conveys the material (or modified versions of
|
|
||||||
it) with contractual assumptions of liability to the recipient, for
|
|
||||||
any liability that these contractual assumptions directly impose on
|
|
||||||
those licensors and authors.
|
|
||||||
|
|
||||||
All other non-permissive additional terms are considered "further
|
|
||||||
restrictions" within the meaning of section 10. If the Program as you
|
|
||||||
received it, or any part of it, contains a notice stating that it is
|
|
||||||
governed by this License along with a term that is a further
|
|
||||||
restriction, you may remove that term. If a license document contains
|
|
||||||
a further restriction but permits relicensing or conveying under this
|
|
||||||
License, you may add to a covered work material governed by the terms
|
|
||||||
of that license document, provided that the further restriction does
|
|
||||||
not survive such relicensing or conveying.
|
|
||||||
|
|
||||||
If you add terms to a covered work in accord with this section, you
|
|
||||||
must place, in the relevant source files, a statement of the
|
|
||||||
additional terms that apply to those files, or a notice indicating
|
|
||||||
where to find the applicable terms.
|
|
||||||
|
|
||||||
Additional terms, permissive or non-permissive, may be stated in the
|
|
||||||
form of a separately written license, or stated as exceptions;
|
|
||||||
the above requirements apply either way.
|
|
||||||
|
|
||||||
8. Termination.
|
|
||||||
|
|
||||||
You may not propagate or modify a covered work except as expressly
|
|
||||||
provided under this License. Any attempt otherwise to propagate or
|
|
||||||
modify it is void, and will automatically terminate your rights under
|
|
||||||
this License (including any patent licenses granted under the third
|
|
||||||
paragraph of section 11).
|
|
||||||
|
|
||||||
However, if you cease all violation of this License, then your
|
|
||||||
license from a particular copyright holder is reinstated (a)
|
|
||||||
provisionally, unless and until the copyright holder explicitly and
|
|
||||||
finally terminates your license, and (b) permanently, if the copyright
|
|
||||||
holder fails to notify you of the violation by some reasonable means
|
|
||||||
prior to 60 days after the cessation.
|
|
||||||
|
|
||||||
Moreover, your license from a particular copyright holder is
|
|
||||||
reinstated permanently if the copyright holder notifies you of the
|
|
||||||
violation by some reasonable means, this is the first time you have
|
|
||||||
received notice of violation of this License (for any work) from that
|
|
||||||
copyright holder, and you cure the violation prior to 30 days after
|
|
||||||
your receipt of the notice.
|
|
||||||
|
|
||||||
Termination of your rights under this section does not terminate the
|
|
||||||
licenses of parties who have received copies or rights from you under
|
|
||||||
this License. If your rights have been terminated and not permanently
|
|
||||||
reinstated, you do not qualify to receive new licenses for the same
|
|
||||||
material under section 10.
|
|
||||||
|
|
||||||
9. Acceptance Not Required for Having Copies.
|
|
||||||
|
|
||||||
You are not required to accept this License in order to receive or
|
|
||||||
run a copy of the Program. Ancillary propagation of a covered work
|
|
||||||
occurring solely as a consequence of using peer-to-peer transmission
|
|
||||||
to receive a copy likewise does not require acceptance. However,
|
|
||||||
nothing other than this License grants you permission to propagate or
|
|
||||||
modify any covered work. These actions infringe copyright if you do
|
|
||||||
not accept this License. Therefore, by modifying or propagating a
|
|
||||||
covered work, you indicate your acceptance of this License to do so.
|
|
||||||
|
|
||||||
10. Automatic Licensing of Downstream Recipients.
|
|
||||||
|
|
||||||
Each time you convey a covered work, the recipient automatically
|
|
||||||
receives a license from the original licensors, to run, modify and
|
|
||||||
propagate that work, subject to this License. You are not responsible
|
|
||||||
for enforcing compliance by third parties with this License.
|
|
||||||
|
|
||||||
An "entity transaction" is a transaction transferring control of an
|
|
||||||
organization, or substantially all assets of one, or subdividing an
|
|
||||||
organization, or merging organizations. If propagation of a covered
|
|
||||||
work results from an entity transaction, each party to that
|
|
||||||
transaction who receives a copy of the work also receives whatever
|
|
||||||
licenses to the work the party's predecessor in interest had or could
|
|
||||||
give under the previous paragraph, plus a right to possession of the
|
|
||||||
Corresponding Source of the work from the predecessor in interest, if
|
|
||||||
the predecessor has it or can get it with reasonable efforts.
|
|
||||||
|
|
||||||
You may not impose any further restrictions on the exercise of the
|
|
||||||
rights granted or affirmed under this License. For example, you may
|
|
||||||
not impose a license fee, royalty, or other charge for exercise of
|
|
||||||
rights granted under this License, and you may not initiate litigation
|
|
||||||
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
|
||||||
any patent claim is infringed by making, using, selling, offering for
|
|
||||||
sale, or importing the Program or any portion of it.
|
|
||||||
|
|
||||||
11. Patents.
|
|
||||||
|
|
||||||
A "contributor" is a copyright holder who authorizes use under this
|
|
||||||
License of the Program or a work on which the Program is based. The
|
|
||||||
work thus licensed is called the contributor's "contributor version".
|
|
||||||
|
|
||||||
A contributor's "essential patent claims" are all patent claims
|
|
||||||
owned or controlled by the contributor, whether already acquired or
|
|
||||||
hereafter acquired, that would be infringed by some manner, permitted
|
|
||||||
by this License, of making, using, or selling its contributor version,
|
|
||||||
but do not include claims that would be infringed only as a
|
|
||||||
consequence of further modification of the contributor version. For
|
|
||||||
purposes of this definition, "control" includes the right to grant
|
|
||||||
patent sublicenses in a manner consistent with the requirements of
|
|
||||||
this License.
|
|
||||||
|
|
||||||
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
|
||||||
patent license under the contributor's essential patent claims, to
|
|
||||||
make, use, sell, offer for sale, import and otherwise run, modify and
|
|
||||||
propagate the contents of its contributor version.
|
|
||||||
|
|
||||||
In the following three paragraphs, a "patent license" is any express
|
|
||||||
agreement or commitment, however denominated, not to enforce a patent
|
|
||||||
(such as an express permission to practice a patent or covenant not to
|
|
||||||
sue for patent infringement). To "grant" such a patent license to a
|
|
||||||
party means to make such an agreement or commitment not to enforce a
|
|
||||||
patent against the party.
|
|
||||||
|
|
||||||
If you convey a covered work, knowingly relying on a patent license,
|
|
||||||
and the Corresponding Source of the work is not available for anyone
|
|
||||||
to copy, free of charge and under the terms of this License, through a
|
|
||||||
publicly available network server or other readily accessible means,
|
|
||||||
then you must either (1) cause the Corresponding Source to be so
|
|
||||||
available, or (2) arrange to deprive yourself of the benefit of the
|
|
||||||
patent license for this particular work, or (3) arrange, in a manner
|
|
||||||
consistent with the requirements of this License, to extend the patent
|
|
||||||
license to downstream recipients. "Knowingly relying" means you have
|
|
||||||
actual knowledge that, but for the patent license, your conveying the
|
|
||||||
covered work in a country, or your recipient's use of the covered work
|
|
||||||
in a country, would infringe one or more identifiable patents in that
|
|
||||||
country that you have reason to believe are valid.
|
|
||||||
|
|
||||||
If, pursuant to or in connection with a single transaction or
|
|
||||||
arrangement, you convey, or propagate by procuring conveyance of, a
|
|
||||||
covered work, and grant a patent license to some of the parties
|
|
||||||
receiving the covered work authorizing them to use, propagate, modify
|
|
||||||
or convey a specific copy of the covered work, then the patent license
|
|
||||||
you grant is automatically extended to all recipients of the covered
|
|
||||||
work and works based on it.
|
|
||||||
|
|
||||||
A patent license is "discriminatory" if it does not include within
|
|
||||||
the scope of its coverage, prohibits the exercise of, or is
|
|
||||||
conditioned on the non-exercise of one or more of the rights that are
|
|
||||||
specifically granted under this License. You may not convey a covered
|
|
||||||
work if you are a party to an arrangement with a third party that is
|
|
||||||
in the business of distributing software, under which you make payment
|
|
||||||
to the third party based on the extent of your activity of conveying
|
|
||||||
the work, and under which the third party grants, to any of the
|
|
||||||
parties who would receive the covered work from you, a discriminatory
|
|
||||||
patent license (a) in connection with copies of the covered work
|
|
||||||
conveyed by you (or copies made from those copies), or (b) primarily
|
|
||||||
for and in connection with specific products or compilations that
|
|
||||||
contain the covered work, unless you entered into that arrangement,
|
|
||||||
or that patent license was granted, prior to 28 March 2007.
|
|
||||||
|
|
||||||
Nothing in this License shall be construed as excluding or limiting
|
|
||||||
any implied license or other defenses to infringement that may
|
|
||||||
otherwise be available to you under applicable patent law.
|
|
||||||
|
|
||||||
12. No Surrender of Others' Freedom.
|
|
||||||
|
|
||||||
If conditions are imposed on you (whether by court order, agreement or
|
|
||||||
otherwise) that contradict the conditions of this License, they do not
|
|
||||||
excuse you from the conditions of this License. If you cannot convey a
|
|
||||||
covered work so as to satisfy simultaneously your obligations under this
|
|
||||||
License and any other pertinent obligations, then as a consequence you may
|
|
||||||
not convey it at all. For example, if you agree to terms that obligate you
|
|
||||||
to collect a royalty for further conveying from those to whom you convey
|
|
||||||
the Program, the only way you could satisfy both those terms and this
|
|
||||||
License would be to refrain entirely from conveying the Program.
|
|
||||||
|
|
||||||
13. Use with the GNU Affero General Public License.
|
|
||||||
|
|
||||||
Notwithstanding any other provision of this License, you have
|
|
||||||
permission to link or combine any covered work with a work licensed
|
|
||||||
under version 3 of the GNU Affero General Public License into a single
|
|
||||||
combined work, and to convey the resulting work. The terms of this
|
|
||||||
License will continue to apply to the part which is the covered work,
|
|
||||||
but the special requirements of the GNU Affero General Public License,
|
|
||||||
section 13, concerning interaction through a network will apply to the
|
|
||||||
combination as such.
|
|
||||||
|
|
||||||
14. Revised Versions of this License.
|
|
||||||
|
|
||||||
The Free Software Foundation may publish revised and/or new versions of
|
|
||||||
the GNU General Public License from time to time. Such new versions will
|
|
||||||
be similar in spirit to the present version, but may differ in detail to
|
|
||||||
address new problems or concerns.
|
|
||||||
|
|
||||||
Each version is given a distinguishing version number. If the
|
|
||||||
Program specifies that a certain numbered version of the GNU General
|
|
||||||
Public License "or any later version" applies to it, you have the
|
|
||||||
option of following the terms and conditions either of that numbered
|
|
||||||
version or of any later version published by the Free Software
|
|
||||||
Foundation. If the Program does not specify a version number of the
|
|
||||||
GNU General Public License, you may choose any version ever published
|
|
||||||
by the Free Software Foundation.
|
|
||||||
|
|
||||||
If the Program specifies that a proxy can decide which future
|
|
||||||
versions of the GNU General Public License can be used, that proxy's
|
|
||||||
public statement of acceptance of a version permanently authorizes you
|
|
||||||
to choose that version for the Program.
|
|
||||||
|
|
||||||
Later license versions may give you additional or different
|
|
||||||
permissions. However, no additional obligations are imposed on any
|
|
||||||
author or copyright holder as a result of your choosing to follow a
|
|
||||||
later version.
|
|
||||||
|
|
||||||
15. Disclaimer of Warranty.
|
|
||||||
|
|
||||||
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
|
||||||
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
|
||||||
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
|
||||||
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
|
||||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
|
||||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
|
||||||
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
|
||||||
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
|
||||||
|
|
||||||
16. Limitation of Liability.
|
|
||||||
|
|
||||||
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
|
||||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
|
||||||
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
|
||||||
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
|
||||||
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
|
||||||
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
|
||||||
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
|
||||||
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
|
||||||
SUCH DAMAGES.
|
|
||||||
|
|
||||||
17. Interpretation of Sections 15 and 16.
|
|
||||||
|
|
||||||
If the disclaimer of warranty and limitation of liability provided
|
|
||||||
above cannot be given local legal effect according to their terms,
|
|
||||||
reviewing courts shall apply local law that most closely approximates
|
|
||||||
an absolute waiver of all civil liability in connection with the
|
|
||||||
Program, unless a warranty or assumption of liability accompanies a
|
|
||||||
copy of the Program in return for a fee.
|
|
||||||
|
|
||||||
END OF TERMS AND CONDITIONS
|
|
||||||
|
|
||||||
How to Apply These Terms to Your New Programs
|
|
||||||
|
|
||||||
If you develop a new program, and you want it to be of the greatest
|
|
||||||
possible use to the public, the best way to achieve this is to make it
|
|
||||||
free software which everyone can redistribute and change under these terms.
|
|
||||||
|
|
||||||
To do so, attach the following notices to the program. It is safest
|
|
||||||
to attach them to the start of each source file to most effectively
|
|
||||||
state the exclusion of warranty; and each file should have at least
|
|
||||||
the "copyright" line and a pointer to where the full notice is found.
|
|
||||||
|
|
||||||
<one line to give the program's name and a brief idea of what it does.>
|
|
||||||
Copyright (C) <year> <name of author>
|
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU General Public License as published by
|
|
||||||
the Free Software Foundation, either version 3 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
Also add information on how to contact you by electronic and paper mail.
|
|
||||||
|
|
||||||
If the program does terminal interaction, make it output a short
|
|
||||||
notice like this when it starts in an interactive mode:
|
|
||||||
|
|
||||||
<program> Copyright (C) <year> <name of author>
|
|
||||||
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
|
||||||
This is free software, and you are welcome to redistribute it
|
|
||||||
under certain conditions; type `show c' for details.
|
|
||||||
|
|
||||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
|
||||||
parts of the General Public License. Of course, your program's commands
|
|
||||||
might be different; for a GUI interface, you would use an "about box".
|
|
||||||
|
|
||||||
You should also get your employer (if you work as a programmer) or school,
|
|
||||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
|
||||||
For more information on this, and how to apply and follow the GNU GPL, see
|
|
||||||
<http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
The GNU General Public License does not permit incorporating your program
|
|
||||||
into proprietary programs. If your program is a subroutine library, you
|
|
||||||
may consider it more useful to permit linking proprietary applications with
|
|
||||||
the library. If this is what you want to do, use the GNU Lesser General
|
|
||||||
Public License instead of this License. But first, please read
|
|
||||||
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
|
|
|
@ -1,165 +0,0 @@
|
||||||
GNU LESSER GENERAL PUBLIC LICENSE
|
|
||||||
Version 3, 29 June 2007
|
|
||||||
|
|
||||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
|
||||||
Everyone is permitted to copy and distribute verbatim copies
|
|
||||||
of this license document, but changing it is not allowed.
|
|
||||||
|
|
||||||
|
|
||||||
This version of the GNU Lesser General Public License incorporates
|
|
||||||
the terms and conditions of version 3 of the GNU General Public
|
|
||||||
License, supplemented by the additional permissions listed below.
|
|
||||||
|
|
||||||
0. Additional Definitions.
|
|
||||||
|
|
||||||
As used herein, "this License" refers to version 3 of the GNU Lesser
|
|
||||||
General Public License, and the "GNU GPL" refers to version 3 of the GNU
|
|
||||||
General Public License.
|
|
||||||
|
|
||||||
"The Library" refers to a covered work governed by this License,
|
|
||||||
other than an Application or a Combined Work as defined below.
|
|
||||||
|
|
||||||
An "Application" is any work that makes use of an interface provided
|
|
||||||
by the Library, but which is not otherwise based on the Library.
|
|
||||||
Defining a subclass of a class defined by the Library is deemed a mode
|
|
||||||
of using an interface provided by the Library.
|
|
||||||
|
|
||||||
A "Combined Work" is a work produced by combining or linking an
|
|
||||||
Application with the Library. The particular version of the Library
|
|
||||||
with which the Combined Work was made is also called the "Linked
|
|
||||||
Version".
|
|
||||||
|
|
||||||
The "Minimal Corresponding Source" for a Combined Work means the
|
|
||||||
Corresponding Source for the Combined Work, excluding any source code
|
|
||||||
for portions of the Combined Work that, considered in isolation, are
|
|
||||||
based on the Application, and not on the Linked Version.
|
|
||||||
|
|
||||||
The "Corresponding Application Code" for a Combined Work means the
|
|
||||||
object code and/or source code for the Application, including any data
|
|
||||||
and utility programs needed for reproducing the Combined Work from the
|
|
||||||
Application, but excluding the System Libraries of the Combined Work.
|
|
||||||
|
|
||||||
1. Exception to Section 3 of the GNU GPL.
|
|
||||||
|
|
||||||
You may convey a covered work under sections 3 and 4 of this License
|
|
||||||
without being bound by section 3 of the GNU GPL.
|
|
||||||
|
|
||||||
2. Conveying Modified Versions.
|
|
||||||
|
|
||||||
If you modify a copy of the Library, and, in your modifications, a
|
|
||||||
facility refers to a function or data to be supplied by an Application
|
|
||||||
that uses the facility (other than as an argument passed when the
|
|
||||||
facility is invoked), then you may convey a copy of the modified
|
|
||||||
version:
|
|
||||||
|
|
||||||
a) under this License, provided that you make a good faith effort to
|
|
||||||
ensure that, in the event an Application does not supply the
|
|
||||||
function or data, the facility still operates, and performs
|
|
||||||
whatever part of its purpose remains meaningful, or
|
|
||||||
|
|
||||||
b) under the GNU GPL, with none of the additional permissions of
|
|
||||||
this License applicable to that copy.
|
|
||||||
|
|
||||||
3. Object Code Incorporating Material from Library Header Files.
|
|
||||||
|
|
||||||
The object code form of an Application may incorporate material from
|
|
||||||
a header file that is part of the Library. You may convey such object
|
|
||||||
code under terms of your choice, provided that, if the incorporated
|
|
||||||
material is not limited to numerical parameters, data structure
|
|
||||||
layouts and accessors, or small macros, inline functions and templates
|
|
||||||
(ten or fewer lines in length), you do both of the following:
|
|
||||||
|
|
||||||
a) Give prominent notice with each copy of the object code that the
|
|
||||||
Library is used in it and that the Library and its use are
|
|
||||||
covered by this License.
|
|
||||||
|
|
||||||
b) Accompany the object code with a copy of the GNU GPL and this license
|
|
||||||
document.
|
|
||||||
|
|
||||||
4. Combined Works.
|
|
||||||
|
|
||||||
You may convey a Combined Work under terms of your choice that,
|
|
||||||
taken together, effectively do not restrict modification of the
|
|
||||||
portions of the Library contained in the Combined Work and reverse
|
|
||||||
engineering for debugging such modifications, if you also do each of
|
|
||||||
the following:
|
|
||||||
|
|
||||||
a) Give prominent notice with each copy of the Combined Work that
|
|
||||||
the Library is used in it and that the Library and its use are
|
|
||||||
covered by this License.
|
|
||||||
|
|
||||||
b) Accompany the Combined Work with a copy of the GNU GPL and this license
|
|
||||||
document.
|
|
||||||
|
|
||||||
c) For a Combined Work that displays copyright notices during
|
|
||||||
execution, include the copyright notice for the Library among
|
|
||||||
these notices, as well as a reference directing the user to the
|
|
||||||
copies of the GNU GPL and this license document.
|
|
||||||
|
|
||||||
d) Do one of the following:
|
|
||||||
|
|
||||||
0) Convey the Minimal Corresponding Source under the terms of this
|
|
||||||
License, and the Corresponding Application Code in a form
|
|
||||||
suitable for, and under terms that permit, the user to
|
|
||||||
recombine or relink the Application with a modified version of
|
|
||||||
the Linked Version to produce a modified Combined Work, in the
|
|
||||||
manner specified by section 6 of the GNU GPL for conveying
|
|
||||||
Corresponding Source.
|
|
||||||
|
|
||||||
1) Use a suitable shared library mechanism for linking with the
|
|
||||||
Library. A suitable mechanism is one that (a) uses at run time
|
|
||||||
a copy of the Library already present on the user's computer
|
|
||||||
system, and (b) will operate properly with a modified version
|
|
||||||
of the Library that is interface-compatible with the Linked
|
|
||||||
Version.
|
|
||||||
|
|
||||||
e) Provide Installation Information, but only if you would otherwise
|
|
||||||
be required to provide such information under section 6 of the
|
|
||||||
GNU GPL, and only to the extent that such information is
|
|
||||||
necessary to install and execute a modified version of the
|
|
||||||
Combined Work produced by recombining or relinking the
|
|
||||||
Application with a modified version of the Linked Version. (If
|
|
||||||
you use option 4d0, the Installation Information must accompany
|
|
||||||
the Minimal Corresponding Source and Corresponding Application
|
|
||||||
Code. If you use option 4d1, you must provide the Installation
|
|
||||||
Information in the manner specified by section 6 of the GNU GPL
|
|
||||||
for conveying Corresponding Source.)
|
|
||||||
|
|
||||||
5. Combined Libraries.
|
|
||||||
|
|
||||||
You may place library facilities that are a work based on the
|
|
||||||
Library side by side in a single library together with other library
|
|
||||||
facilities that are not Applications and are not covered by this
|
|
||||||
License, and convey such a combined library under terms of your
|
|
||||||
choice, if you do both of the following:
|
|
||||||
|
|
||||||
a) Accompany the combined library with a copy of the same work based
|
|
||||||
on the Library, uncombined with any other library facilities,
|
|
||||||
conveyed under the terms of this License.
|
|
||||||
|
|
||||||
b) Give prominent notice with the combined library that part of it
|
|
||||||
is a work based on the Library, and explaining where to find the
|
|
||||||
accompanying uncombined form of the same work.
|
|
||||||
|
|
||||||
6. Revised Versions of the GNU Lesser General Public License.
|
|
||||||
|
|
||||||
The Free Software Foundation may publish revised and/or new versions
|
|
||||||
of the GNU Lesser General Public License from time to time. Such new
|
|
||||||
versions will be similar in spirit to the present version, but may
|
|
||||||
differ in detail to address new problems or concerns.
|
|
||||||
|
|
||||||
Each version is given a distinguishing version number. If the
|
|
||||||
Library as you received it specifies that a certain numbered version
|
|
||||||
of the GNU Lesser General Public License "or any later version"
|
|
||||||
applies to it, you have the option of following the terms and
|
|
||||||
conditions either of that published version or of any later version
|
|
||||||
published by the Free Software Foundation. If the Library as you
|
|
||||||
received it does not specify a version number of the GNU Lesser
|
|
||||||
General Public License, you may choose any version of the GNU Lesser
|
|
||||||
General Public License ever published by the Free Software Foundation.
|
|
||||||
|
|
||||||
If the Library as you received it specifies that a proxy can decide
|
|
||||||
whether future versions of the GNU Lesser General Public License shall
|
|
||||||
apply, that proxy's public statement of acceptance of any version is
|
|
||||||
permanent authorization for you to choose that version for the
|
|
||||||
Library.
|
|
|
@ -1,15 +0,0 @@
|
||||||
GoCommon - Go Common Library for the Joyent Public Cloud and Joyent Manta
|
|
||||||
|
|
||||||
Copyright (c) 2013, Joyent Inc.
|
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify it under
|
|
||||||
the terms of the GNU Lesser General Public License as published by the Free
|
|
||||||
Software Foundation, either version 3 of the License, or (at your option) any
|
|
||||||
later version.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
||||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
|
||||||
PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
|
|
||||||
|
|
||||||
See both COPYING and COPYING.LESSER for the full terms of the GNU Lesser
|
|
||||||
General Public License.
|
|
|
@ -1,2 +0,0 @@
|
||||||
gocommon
|
|
||||||
========
|
|
|
@ -1,111 +0,0 @@
|
||||||
//
|
|
||||||
// gocommon - Go library to interact with the JoyentCloud
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// Copyright (c) 2013 Joyent Inc.
|
|
||||||
//
|
|
||||||
// Written by Daniele Stroppa <daniele.stroppa@joyent.com>
|
|
||||||
//
|
|
||||||
|
|
||||||
package client
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"net/url"
|
|
||||||
"strings"
|
|
||||||
"sync"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/juju/loggo"
|
|
||||||
|
|
||||||
joyenthttp "github.com/joyent/gocommon/http"
|
|
||||||
"github.com/joyent/gosign/auth"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
// The HTTP request methods.
|
|
||||||
GET = "GET"
|
|
||||||
POST = "POST"
|
|
||||||
PUT = "PUT"
|
|
||||||
DELETE = "DELETE"
|
|
||||||
HEAD = "HEAD"
|
|
||||||
COPY = "COPY"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Client implementations sends service requests to the JoyentCloud.
|
|
||||||
type Client interface {
|
|
||||||
SendRequest(method, apiCall, rfc1123Date string, request *joyenthttp.RequestData, response *joyenthttp.ResponseData) (err error)
|
|
||||||
// MakeServiceURL prepares a full URL to a service endpoint, with optional
|
|
||||||
// URL parts. It uses the first endpoint it can find for the given service type.
|
|
||||||
MakeServiceURL(parts []string) string
|
|
||||||
SignURL(path string, expires time.Time) (string, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
// This client sends requests without authenticating.
|
|
||||||
type client struct {
|
|
||||||
mu sync.Mutex
|
|
||||||
logger *loggo.Logger
|
|
||||||
baseURL string
|
|
||||||
creds *auth.Credentials
|
|
||||||
httpClient *joyenthttp.Client
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ Client = (*client)(nil)
|
|
||||||
|
|
||||||
func newClient(baseURL string, credentials *auth.Credentials, httpClient *joyenthttp.Client, logger *loggo.Logger) Client {
|
|
||||||
client := client{baseURL: baseURL, logger: logger, creds: credentials, httpClient: httpClient}
|
|
||||||
return &client
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewClient(baseURL, apiVersion string, credentials *auth.Credentials, logger *loggo.Logger) Client {
|
|
||||||
sharedHttpClient := joyenthttp.New(credentials, apiVersion, logger)
|
|
||||||
return newClient(baseURL, credentials, sharedHttpClient, logger)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *client) sendRequest(method, url, rfc1123Date string, request *joyenthttp.RequestData, response *joyenthttp.ResponseData) (err error) {
|
|
||||||
if request.ReqValue != nil || response.RespValue != nil {
|
|
||||||
err = c.httpClient.JsonRequest(method, url, rfc1123Date, request, response)
|
|
||||||
} else {
|
|
||||||
err = c.httpClient.BinaryRequest(method, url, rfc1123Date, request, response)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *client) SendRequest(method, apiCall, rfc1123Date string, request *joyenthttp.RequestData, response *joyenthttp.ResponseData) (err error) {
|
|
||||||
url := c.MakeServiceURL([]string{c.creds.UserAuthentication.User, apiCall})
|
|
||||||
err = c.sendRequest(method, url, rfc1123Date, request, response)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func makeURL(base string, parts []string) string {
|
|
||||||
if !strings.HasSuffix(base, "/") && len(parts) > 0 {
|
|
||||||
base += "/"
|
|
||||||
}
|
|
||||||
if parts[1] == "" {
|
|
||||||
return base + parts[0]
|
|
||||||
}
|
|
||||||
return base + strings.Join(parts, "/")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *client) MakeServiceURL(parts []string) string {
|
|
||||||
return makeURL(c.baseURL, parts)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *client) SignURL(path string, expires time.Time) (string, error) {
|
|
||||||
parsedURL, err := url.Parse(c.baseURL)
|
|
||||||
if err != nil {
|
|
||||||
return "", fmt.Errorf("bad Manta endpoint URL %q: %v", c.baseURL, err)
|
|
||||||
}
|
|
||||||
userAuthentication := c.creds.UserAuthentication
|
|
||||||
userAuthentication.Algorithm = "RSA-SHA1"
|
|
||||||
keyId := url.QueryEscape(fmt.Sprintf("/%s/keys/%s", userAuthentication.User, c.creds.MantaKeyId))
|
|
||||||
params := fmt.Sprintf("algorithm=%s&expires=%d&keyId=%s", userAuthentication.Algorithm, expires.Unix(), keyId)
|
|
||||||
signingLine := fmt.Sprintf("GET\n%s\n%s\n%s", parsedURL.Host, path, params)
|
|
||||||
|
|
||||||
signature, err := auth.GetSignature(userAuthentication, signingLine)
|
|
||||||
if err != nil {
|
|
||||||
return "", fmt.Errorf("cannot generate URL signature: %v", err)
|
|
||||||
}
|
|
||||||
signedURL := fmt.Sprintf("%s%s?%s&signature=%s", c.baseURL, path, params, url.QueryEscape(signature))
|
|
||||||
return signedURL, nil
|
|
||||||
}
|
|
|
@ -1,292 +0,0 @@
|
||||||
//
|
|
||||||
// gocommon - Go library to interact with the JoyentCloud
|
|
||||||
// This package provides an Error implementation which knows about types of error, and which has support
|
|
||||||
// for error causes.
|
|
||||||
//
|
|
||||||
// Copyright (c) 2013 Joyent Inc.
|
|
||||||
//
|
|
||||||
// Written by Daniele Stroppa <daniele.stroppa@joyent.com>
|
|
||||||
//
|
|
||||||
|
|
||||||
package errors
|
|
||||||
|
|
||||||
import "fmt"
|
|
||||||
|
|
||||||
type Code string
|
|
||||||
|
|
||||||
const (
|
|
||||||
// Public available error types.
|
|
||||||
// These errors are provided because they are specifically required by business logic in the callers.
|
|
||||||
BadRequestError = Code("BadRequest")
|
|
||||||
InternalErrorError = Code("InternalError")
|
|
||||||
InvalidArgumentError = Code("InvalidArgument")
|
|
||||||
InvalidCredentialsError = Code("InvalidCredentials")
|
|
||||||
InvalidHeaderError = Code("InvalidHeader")
|
|
||||||
InvalidVersionError = Code("InvalidVersion")
|
|
||||||
MissingParameterError = Code("MissinParameter")
|
|
||||||
NotAuthorizedError = Code("NotAuthorized")
|
|
||||||
RequestThrottledError = Code("RequestThrottled")
|
|
||||||
RequestTooLargeError = Code("RequestTooLarge")
|
|
||||||
RequestMovedError = Code("RequestMoved")
|
|
||||||
ResourceNotFoundError = Code("ResourceNotFound")
|
|
||||||
UnknownErrorError = Code("UnkownError")
|
|
||||||
)
|
|
||||||
|
|
||||||
// Error instances store an optional error cause.
|
|
||||||
type Error interface {
|
|
||||||
error
|
|
||||||
Cause() error
|
|
||||||
}
|
|
||||||
|
|
||||||
type gojoyentError struct {
|
|
||||||
error
|
|
||||||
errcode Code
|
|
||||||
cause error
|
|
||||||
}
|
|
||||||
|
|
||||||
// Type checks.
|
|
||||||
var _ Error = (*gojoyentError)(nil)
|
|
||||||
|
|
||||||
// Code returns the error code.
|
|
||||||
func (err *gojoyentError) code() Code {
|
|
||||||
if err.errcode != UnknownErrorError {
|
|
||||||
return err.errcode
|
|
||||||
}
|
|
||||||
if e, ok := err.cause.(*gojoyentError); ok {
|
|
||||||
return e.code()
|
|
||||||
}
|
|
||||||
return UnknownErrorError
|
|
||||||
}
|
|
||||||
|
|
||||||
// Cause returns the error cause.
|
|
||||||
func (err *gojoyentError) Cause() error {
|
|
||||||
return err.cause
|
|
||||||
}
|
|
||||||
|
|
||||||
// CausedBy returns true if this error or its cause are of the specified error code.
|
|
||||||
func (err *gojoyentError) causedBy(code Code) bool {
|
|
||||||
if err.code() == code {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
if cause, ok := err.cause.(*gojoyentError); ok {
|
|
||||||
return cause.code() == code
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// Error fulfills the error interface, taking account of any caused by error.
|
|
||||||
func (err *gojoyentError) Error() string {
|
|
||||||
if err.cause != nil {
|
|
||||||
return fmt.Sprintf("%v\ncaused by: %v", err.error, err.cause)
|
|
||||||
}
|
|
||||||
return err.error.Error()
|
|
||||||
}
|
|
||||||
|
|
||||||
func IsBadRequest(err error) bool {
|
|
||||||
if e, ok := err.(*gojoyentError); ok {
|
|
||||||
return e.causedBy(BadRequestError)
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func IsInternalError(err error) bool {
|
|
||||||
if e, ok := err.(*gojoyentError); ok {
|
|
||||||
return e.causedBy(InternalErrorError)
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func IsInvalidArgument(err error) bool {
|
|
||||||
if e, ok := err.(*gojoyentError); ok {
|
|
||||||
return e.causedBy(InvalidArgumentError)
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func IsInvalidCredentials(err error) bool {
|
|
||||||
if e, ok := err.(*gojoyentError); ok {
|
|
||||||
return e.causedBy(InvalidCredentialsError)
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func IsInvalidHeader(err error) bool {
|
|
||||||
if e, ok := err.(*gojoyentError); ok {
|
|
||||||
return e.causedBy(InvalidHeaderError)
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func IsInvalidVersion(err error) bool {
|
|
||||||
if e, ok := err.(*gojoyentError); ok {
|
|
||||||
return e.causedBy(InvalidVersionError)
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func IsMissingParameter(err error) bool {
|
|
||||||
if e, ok := err.(*gojoyentError); ok {
|
|
||||||
return e.causedBy(MissingParameterError)
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func IsNotAuthorized(err error) bool {
|
|
||||||
if e, ok := err.(*gojoyentError); ok {
|
|
||||||
return e.causedBy(NotAuthorizedError)
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func IsRequestThrottled(err error) bool {
|
|
||||||
if e, ok := err.(*gojoyentError); ok {
|
|
||||||
return e.causedBy(RequestThrottledError)
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func IsRequestTooLarge(err error) bool {
|
|
||||||
if e, ok := err.(*gojoyentError); ok {
|
|
||||||
return e.causedBy(RequestTooLargeError)
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func IsRequestMoved(err error) bool {
|
|
||||||
if e, ok := err.(*gojoyentError); ok {
|
|
||||||
return e.causedBy(RequestMovedError)
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func IsResourceNotFound(err error) bool {
|
|
||||||
if e, ok := err.(*gojoyentError); ok {
|
|
||||||
return e.causedBy(ResourceNotFoundError)
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func IsUnknownError(err error) bool {
|
|
||||||
if e, ok := err.(*gojoyentError); ok {
|
|
||||||
return e.causedBy(UnknownErrorError)
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// New creates a new Error instance with the specified cause.
|
|
||||||
func makeErrorf(code Code, cause error, format string, args ...interface{}) Error {
|
|
||||||
return &gojoyentError{
|
|
||||||
errcode: code,
|
|
||||||
error: fmt.Errorf(format, args...),
|
|
||||||
cause: cause,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// New creates a new UnknownError Error instance with the specified cause.
|
|
||||||
func Newf(cause error, format string, args ...interface{}) Error {
|
|
||||||
return makeErrorf(UnknownErrorError, cause, format, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// New creates a new BadRequest Error instance with the specified cause.
|
|
||||||
func NewBadRequestf(cause error, context interface{}, format string, args ...interface{}) Error {
|
|
||||||
if format == "" {
|
|
||||||
format = fmt.Sprintf("Bad Request: %s", context)
|
|
||||||
}
|
|
||||||
return makeErrorf(BadRequestError, cause, format, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// New creates a new InternalError Error instance with the specified cause.
|
|
||||||
func NewInternalErrorf(cause error, context interface{}, format string, args ...interface{}) Error {
|
|
||||||
if format == "" {
|
|
||||||
format = fmt.Sprintf("Internal Error: %s", context)
|
|
||||||
}
|
|
||||||
return makeErrorf(InternalErrorError, cause, format, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// New creates a new InvalidArgument Error instance with the specified cause.
|
|
||||||
func NewInvalidArgumentf(cause error, context interface{}, format string, args ...interface{}) Error {
|
|
||||||
if format == "" {
|
|
||||||
format = fmt.Sprintf("Invalid Argument: %s", context)
|
|
||||||
}
|
|
||||||
return makeErrorf(InvalidArgumentError, cause, format, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// New creates a new InvalidCredentials Error instance with the specified cause.
|
|
||||||
func NewInvalidCredentialsf(cause error, context interface{}, format string, args ...interface{}) Error {
|
|
||||||
if format == "" {
|
|
||||||
format = fmt.Sprintf("Invalid Credentials: %s", context)
|
|
||||||
}
|
|
||||||
return makeErrorf(InvalidCredentialsError, cause, format, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// New creates a new InvalidHeader Error instance with the specified cause.
|
|
||||||
func NewInvalidHeaderf(cause error, context interface{}, format string, args ...interface{}) Error {
|
|
||||||
if format == "" {
|
|
||||||
format = fmt.Sprintf("Invalid Header: %s", context)
|
|
||||||
}
|
|
||||||
return makeErrorf(InvalidHeaderError, cause, format, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// New creates a new InvalidVersion Error instance with the specified cause.
|
|
||||||
func NewInvalidVersionf(cause error, context interface{}, format string, args ...interface{}) Error {
|
|
||||||
if format == "" {
|
|
||||||
format = fmt.Sprintf("Invalid Version: %s", context)
|
|
||||||
}
|
|
||||||
return makeErrorf(InvalidVersionError, cause, format, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// New creates a new MissingParameter Error instance with the specified cause.
|
|
||||||
func NewMissingParameterf(cause error, context interface{}, format string, args ...interface{}) Error {
|
|
||||||
if format == "" {
|
|
||||||
format = fmt.Sprintf("Missing Parameter: %s", context)
|
|
||||||
}
|
|
||||||
return makeErrorf(MissingParameterError, cause, format, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// New creates a new NotAuthorized Error instance with the specified cause.
|
|
||||||
func NewNotAuthorizedf(cause error, context interface{}, format string, args ...interface{}) Error {
|
|
||||||
if format == "" {
|
|
||||||
format = fmt.Sprintf("Not Authorized: %s", context)
|
|
||||||
}
|
|
||||||
return makeErrorf(NotAuthorizedError, cause, format, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// New creates a new RequestThrottled Error instance with the specified cause.
|
|
||||||
func NewRequestThrottledf(cause error, context interface{}, format string, args ...interface{}) Error {
|
|
||||||
if format == "" {
|
|
||||||
format = fmt.Sprintf("Request Throttled: %s", context)
|
|
||||||
}
|
|
||||||
return makeErrorf(RequestThrottledError, cause, format, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// New creates a new RequestTooLarge Error instance with the specified cause.
|
|
||||||
func NewRequestTooLargef(cause error, context interface{}, format string, args ...interface{}) Error {
|
|
||||||
if format == "" {
|
|
||||||
format = fmt.Sprintf("Request Too Large: %s", context)
|
|
||||||
}
|
|
||||||
return makeErrorf(RequestTooLargeError, cause, format, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// New creates a new RequestMoved Error instance with the specified cause.
|
|
||||||
func NewRequestMovedf(cause error, context interface{}, format string, args ...interface{}) Error {
|
|
||||||
if format == "" {
|
|
||||||
format = fmt.Sprintf("Request Moved: %s", context)
|
|
||||||
}
|
|
||||||
return makeErrorf(RequestMovedError, cause, format, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// New creates a new ResourceNotFound Error instance with the specified cause.
|
|
||||||
func NewResourceNotFoundf(cause error, context interface{}, format string, args ...interface{}) Error {
|
|
||||||
if format == "" {
|
|
||||||
format = fmt.Sprintf("Resource Not Found: %s", context)
|
|
||||||
}
|
|
||||||
return makeErrorf(ResourceNotFoundError, cause, format, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// New creates a new UnknownError Error instance with the specified cause.
|
|
||||||
func NewUnknownErrorf(cause error, context interface{}, format string, args ...interface{}) Error {
|
|
||||||
if format == "" {
|
|
||||||
format = fmt.Sprintf("Unknown Error: %s", context)
|
|
||||||
}
|
|
||||||
return makeErrorf(UnknownErrorError, cause, format, args...)
|
|
||||||
}
|
|
|
@ -1,18 +0,0 @@
|
||||||
/*
|
|
||||||
The gocommon package collects common packages to interact with the Joyent Public Cloud and Joyent Manta services.
|
|
||||||
|
|
||||||
The gocommon package is structured as follow:
|
|
||||||
|
|
||||||
- gocommon/client. Client for sending requests.
|
|
||||||
- gocommon/errors. Joyent specific errors.
|
|
||||||
- gocommon/http. HTTP client for sending requests.
|
|
||||||
- gocommon/jpc. This package provides common structures and functions across packages.
|
|
||||||
- gocommon/testing. Testing Suite for local testing.
|
|
||||||
|
|
||||||
Licensed under LGPL v3.
|
|
||||||
|
|
||||||
Copyright (c) 2013 Joyent Inc.
|
|
||||||
Written by Daniele Stroppa <daniele.stroppa@joyent.com>
|
|
||||||
|
|
||||||
*/
|
|
||||||
package gocommon
|
|
|
@ -1,420 +0,0 @@
|
||||||
//
|
|
||||||
// gocommon - Go library to interact with the JoyentCloud
|
|
||||||
// An HTTP Client which sends json and binary requests, handling data marshalling and response processing.
|
|
||||||
//
|
|
||||||
// Copyright (c) 2013 Joyent Inc.
|
|
||||||
//
|
|
||||||
// Written by Daniele Stroppa <daniele.stroppa@joyent.com>
|
|
||||||
//
|
|
||||||
|
|
||||||
package http
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"io/ioutil"
|
|
||||||
"net/http"
|
|
||||||
"net/url"
|
|
||||||
"reflect"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/juju/loggo"
|
|
||||||
|
|
||||||
"github.com/joyent/gocommon"
|
|
||||||
"github.com/joyent/gocommon/errors"
|
|
||||||
"github.com/joyent/gocommon/jpc"
|
|
||||||
"github.com/joyent/gosign/auth"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
contentTypeJSON = "application/json"
|
|
||||||
contentTypeOctetStream = "application/octet-stream"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Client struct {
|
|
||||||
http.Client
|
|
||||||
maxSendAttempts int
|
|
||||||
credentials *auth.Credentials
|
|
||||||
apiVersion string
|
|
||||||
logger *loggo.Logger
|
|
||||||
}
|
|
||||||
|
|
||||||
type ErrorResponse struct {
|
|
||||||
Message string `json:"message"`
|
|
||||||
Code int `json:"code"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *ErrorResponse) Error() string {
|
|
||||||
return fmt.Sprintf("Failed: %d: %s", e.Code, e.Message)
|
|
||||||
}
|
|
||||||
|
|
||||||
type ErrorWrapper struct {
|
|
||||||
Error ErrorResponse `json:"error"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type RequestData struct {
|
|
||||||
ReqHeaders http.Header
|
|
||||||
Params *url.Values
|
|
||||||
ReqValue interface{}
|
|
||||||
ReqReader io.Reader
|
|
||||||
ReqLength int
|
|
||||||
}
|
|
||||||
|
|
||||||
type ResponseData struct {
|
|
||||||
ExpectedStatus []int
|
|
||||||
RespHeaders *http.Header
|
|
||||||
RespValue interface{}
|
|
||||||
RespReader io.ReadCloser
|
|
||||||
}
|
|
||||||
|
|
||||||
const (
|
|
||||||
// The maximum number of times to try sending a request before we give up
|
|
||||||
// (assuming any unsuccessful attempts can be sensibly tried again).
|
|
||||||
MaxSendAttempts = 3
|
|
||||||
)
|
|
||||||
|
|
||||||
// New returns a new http *Client using the default net/http client.
|
|
||||||
func New(credentials *auth.Credentials, apiVersion string, logger *loggo.Logger) *Client {
|
|
||||||
return &Client{*http.DefaultClient, MaxSendAttempts, credentials, apiVersion, logger}
|
|
||||||
}
|
|
||||||
|
|
||||||
func gojoyentAgent() string {
|
|
||||||
return fmt.Sprintf("gocommon (%s)", gocommon.Version)
|
|
||||||
}
|
|
||||||
|
|
||||||
func createHeaders(extraHeaders http.Header, credentials *auth.Credentials, contentType, rfc1123Date,
|
|
||||||
apiVersion string, isMantaRequest bool) (http.Header, error) {
|
|
||||||
|
|
||||||
headers := make(http.Header)
|
|
||||||
if extraHeaders != nil {
|
|
||||||
for header, values := range extraHeaders {
|
|
||||||
for _, value := range values {
|
|
||||||
headers.Add(header, value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if extraHeaders.Get("Content-Type") == "" {
|
|
||||||
headers.Add("Content-Type", contentType)
|
|
||||||
}
|
|
||||||
if extraHeaders.Get("Accept") == "" {
|
|
||||||
headers.Add("Accept", contentType)
|
|
||||||
}
|
|
||||||
if rfc1123Date != "" {
|
|
||||||
headers.Set("Date", rfc1123Date)
|
|
||||||
} else {
|
|
||||||
headers.Set("Date", getDateForRegion(credentials, isMantaRequest))
|
|
||||||
}
|
|
||||||
authHeaders, err := auth.CreateAuthorizationHeader(headers, credentials, isMantaRequest)
|
|
||||||
if err != nil {
|
|
||||||
return http.Header{}, err
|
|
||||||
}
|
|
||||||
headers.Set("Authorization", authHeaders)
|
|
||||||
if apiVersion != "" {
|
|
||||||
headers.Set("X-Api-Version", apiVersion)
|
|
||||||
}
|
|
||||||
headers.Add("User-Agent", gojoyentAgent())
|
|
||||||
return headers, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func getDateForRegion(credentials *auth.Credentials, isManta bool) string {
|
|
||||||
if isManta {
|
|
||||||
location, _ := time.LoadLocation(jpc.Locations["us-east-1"])
|
|
||||||
return time.Now().In(location).Format(time.RFC1123)
|
|
||||||
} else {
|
|
||||||
location, _ := time.LoadLocation(jpc.Locations[credentials.Region()])
|
|
||||||
return time.Now().In(location).Format(time.RFC1123)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// JsonRequest JSON encodes and sends the object in reqData.ReqValue (if any) to the specified URL.
|
|
||||||
// Optional method arguments are passed using the RequestData object.
|
|
||||||
// Relevant RequestData fields:
|
|
||||||
// ReqHeaders: additional HTTP header values to add to the request.
|
|
||||||
// ExpectedStatus: the allowed HTTP response status values, else an error is returned.
|
|
||||||
// ReqValue: the data object to send.
|
|
||||||
// RespValue: the data object to decode the result into.
|
|
||||||
func (c *Client) JsonRequest(method, url, rfc1123Date string, request *RequestData, response *ResponseData) (err error) {
|
|
||||||
err = nil
|
|
||||||
var body []byte
|
|
||||||
if request.Params != nil {
|
|
||||||
url += "?" + request.Params.Encode()
|
|
||||||
}
|
|
||||||
if request.ReqValue != nil {
|
|
||||||
body, err = json.Marshal(request.ReqValue)
|
|
||||||
if err != nil {
|
|
||||||
err = errors.Newf(err, "failed marshalling the request body")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
headers, err := createHeaders(request.ReqHeaders, c.credentials, contentTypeJSON, rfc1123Date, c.apiVersion,
|
|
||||||
isMantaRequest(url, c.credentials.UserAuthentication.User))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
respBody, respHeader, err := c.sendRequest(
|
|
||||||
method, url, bytes.NewReader(body), len(body), headers, response.ExpectedStatus, c.logger)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
defer respBody.Close()
|
|
||||||
respData, err := ioutil.ReadAll(respBody)
|
|
||||||
if err != nil {
|
|
||||||
err = errors.Newf(err, "failed reading the response body")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(respData) > 0 {
|
|
||||||
if response.RespValue != nil {
|
|
||||||
if _, ok := response.RespValue.(*[]byte); ok {
|
|
||||||
response.RespValue = respData
|
|
||||||
//err = decodeJSON(bytes.NewReader(respData), false, response.RespValue)
|
|
||||||
//if err != nil {
|
|
||||||
// err = errors.Newf(err, "failed unmarshaling/decoding the response body: %s", respData)
|
|
||||||
//}
|
|
||||||
} else {
|
|
||||||
err = json.Unmarshal(respData, response.RespValue)
|
|
||||||
if err != nil {
|
|
||||||
err = decodeJSON(bytes.NewReader(respData), true, response.RespValue)
|
|
||||||
if err != nil {
|
|
||||||
err = errors.Newf(err, "failed unmarshaling/decoding the response body: %s", respData)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if respHeader != nil {
|
|
||||||
response.RespHeaders = respHeader
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func decodeJSON(r io.Reader, multiple bool, into interface{}) error {
|
|
||||||
d := json.NewDecoder(r)
|
|
||||||
if multiple {
|
|
||||||
return decodeStream(d, into)
|
|
||||||
}
|
|
||||||
return d.Decode(into)
|
|
||||||
}
|
|
||||||
|
|
||||||
func decodeStream(d *json.Decoder, into interface{}) error {
|
|
||||||
t := reflect.TypeOf(into)
|
|
||||||
if t.Kind() != reflect.Ptr || t.Elem().Kind() != reflect.Slice {
|
|
||||||
return fmt.Errorf("unexpected type %s", t)
|
|
||||||
}
|
|
||||||
elemType := t.Elem().Elem()
|
|
||||||
slice := reflect.ValueOf(into).Elem()
|
|
||||||
for {
|
|
||||||
val := reflect.New(elemType)
|
|
||||||
if err := d.Decode(val.Interface()); err != nil {
|
|
||||||
if err == io.EOF {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
slice.Set(reflect.Append(slice, val.Elem()))
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sends the byte array in reqData.ReqValue (if any) to the specified URL.
|
|
||||||
// Optional method arguments are passed using the RequestData object.
|
|
||||||
// Relevant RequestData fields:
|
|
||||||
// ReqHeaders: additional HTTP header values to add to the request.
|
|
||||||
// ExpectedStatus: the allowed HTTP response status values, else an error is returned.
|
|
||||||
// ReqReader: an io.Reader providing the bytes to send.
|
|
||||||
// RespReader: assigned an io.ReadCloser instance used to read the returned data..
|
|
||||||
func (c *Client) BinaryRequest(method, url, rfc1123Date string, request *RequestData, response *ResponseData) (err error) {
|
|
||||||
err = nil
|
|
||||||
|
|
||||||
if request.Params != nil {
|
|
||||||
url += "?" + request.Params.Encode()
|
|
||||||
}
|
|
||||||
headers, err := createHeaders(request.ReqHeaders, c.credentials, contentTypeOctetStream, rfc1123Date,
|
|
||||||
c.apiVersion, isMantaRequest(url, c.credentials.UserAuthentication.User))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
respBody, respHeader, err := c.sendRequest(
|
|
||||||
method, url, request.ReqReader, request.ReqLength, headers, response.ExpectedStatus, c.logger)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if response.RespReader != nil {
|
|
||||||
response.RespReader = respBody
|
|
||||||
}
|
|
||||||
if respHeader != nil {
|
|
||||||
response.RespHeaders = respHeader
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sends the specified request to URL and checks that the HTTP response status is as expected.
|
|
||||||
// reqReader: a reader returning the data to send.
|
|
||||||
// length: the number of bytes to send.
|
|
||||||
// headers: HTTP headers to include with the request.
|
|
||||||
// expectedStatus: a slice of allowed response status codes.
|
|
||||||
func (c *Client) sendRequest(method, URL string, reqReader io.Reader, length int, headers http.Header,
|
|
||||||
expectedStatus []int, logger *loggo.Logger) (rc io.ReadCloser, respHeader *http.Header, err error) {
|
|
||||||
reqData := make([]byte, length)
|
|
||||||
if reqReader != nil {
|
|
||||||
nrRead, err := io.ReadFull(reqReader, reqData)
|
|
||||||
if err != nil {
|
|
||||||
err = errors.Newf(err, "failed reading the request data, read %v of %v bytes", nrRead, length)
|
|
||||||
return rc, respHeader, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
rawResp, err := c.sendRateLimitedRequest(method, URL, headers, reqData, logger)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if logger != nil && logger.IsTraceEnabled() {
|
|
||||||
logger.Tracef("Request: %s %s\n", method, URL)
|
|
||||||
logger.Tracef("Request header: %s\n", headers)
|
|
||||||
logger.Tracef("Request body: %s\n", reqData)
|
|
||||||
logger.Tracef("Response: %s\n", rawResp.Status)
|
|
||||||
logger.Tracef("Response header: %s\n", rawResp.Header)
|
|
||||||
logger.Tracef("Response body: %s\n", rawResp.Body)
|
|
||||||
logger.Tracef("Response error: %s\n", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
foundStatus := false
|
|
||||||
if len(expectedStatus) == 0 {
|
|
||||||
expectedStatus = []int{http.StatusOK}
|
|
||||||
}
|
|
||||||
for _, status := range expectedStatus {
|
|
||||||
if rawResp.StatusCode == status {
|
|
||||||
foundStatus = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !foundStatus && len(expectedStatus) > 0 {
|
|
||||||
err = handleError(URL, rawResp)
|
|
||||||
rawResp.Body.Close()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
return rawResp.Body, &rawResp.Header, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Client) sendRateLimitedRequest(method, URL string, headers http.Header, reqData []byte,
|
|
||||||
logger *loggo.Logger) (resp *http.Response, err error) {
|
|
||||||
for i := 0; i < c.maxSendAttempts; i++ {
|
|
||||||
var reqReader io.Reader
|
|
||||||
if reqData != nil {
|
|
||||||
reqReader = bytes.NewReader(reqData)
|
|
||||||
}
|
|
||||||
req, err := http.NewRequest(method, URL, reqReader)
|
|
||||||
if err != nil {
|
|
||||||
err = errors.Newf(err, "failed creating the request %s", URL)
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
// Setting req.Close to true to avoid malformed HTTP version "nullHTTP/1.1" error
|
|
||||||
// See http://stackoverflow.com/questions/17714494/golang-http-request-results-in-eof-errors-when-making-multiple-requests-successi
|
|
||||||
req.Close = true
|
|
||||||
for header, values := range headers {
|
|
||||||
for _, value := range values {
|
|
||||||
req.Header.Add(header, value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
req.ContentLength = int64(len(reqData))
|
|
||||||
resp, err = c.Do(req)
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.Newf(err, "failed executing the request %s", URL)
|
|
||||||
}
|
|
||||||
if resp.StatusCode != http.StatusRequestEntityTooLarge || resp.Header.Get("Retry-After") == "" {
|
|
||||||
return resp, nil
|
|
||||||
}
|
|
||||||
resp.Body.Close()
|
|
||||||
retryAfter, err := strconv.ParseFloat(resp.Header.Get("Retry-After"), 64)
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.Newf(err, "Invalid Retry-After header %s", URL)
|
|
||||||
}
|
|
||||||
if retryAfter == 0 {
|
|
||||||
return nil, errors.Newf(err, "Resource limit exeeded at URL %s", URL)
|
|
||||||
}
|
|
||||||
if logger != nil {
|
|
||||||
logger.Warningf("Too many requests, retrying in %dms.", int(retryAfter*1000))
|
|
||||||
}
|
|
||||||
time.Sleep(time.Duration(retryAfter) * time.Second)
|
|
||||||
}
|
|
||||||
return nil, errors.Newf(err, "Maximum number of attempts (%d) reached sending request to %s", c.maxSendAttempts, URL)
|
|
||||||
}
|
|
||||||
|
|
||||||
type HttpError struct {
|
|
||||||
StatusCode int
|
|
||||||
Data map[string][]string
|
|
||||||
Url string
|
|
||||||
ResponseMessage string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *HttpError) Error() string {
|
|
||||||
return fmt.Sprintf("request %q returned unexpected status %d with body %q",
|
|
||||||
e.Url,
|
|
||||||
e.StatusCode,
|
|
||||||
e.ResponseMessage,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// The HTTP response status code was not one of those expected, so we construct an error.
|
|
||||||
// NotFound (404) codes have their own NotFound error type.
|
|
||||||
// We also make a guess at duplicate value errors.
|
|
||||||
func handleError(URL string, resp *http.Response) error {
|
|
||||||
errBytes, _ := ioutil.ReadAll(resp.Body)
|
|
||||||
errInfo := string(errBytes)
|
|
||||||
// Check if we have a JSON representation of the failure, if so decode it.
|
|
||||||
if resp.Header.Get("Content-Type") == contentTypeJSON {
|
|
||||||
var errResponse ErrorResponse
|
|
||||||
if err := json.Unmarshal(errBytes, &errResponse); err == nil {
|
|
||||||
errInfo = errResponse.Message
|
|
||||||
}
|
|
||||||
}
|
|
||||||
httpError := &HttpError{
|
|
||||||
resp.StatusCode, map[string][]string(resp.Header), URL, errInfo,
|
|
||||||
}
|
|
||||||
switch resp.StatusCode {
|
|
||||||
case http.StatusBadRequest:
|
|
||||||
return errors.NewBadRequestf(httpError, "", "Bad request %s", URL)
|
|
||||||
case http.StatusUnauthorized:
|
|
||||||
return errors.NewNotAuthorizedf(httpError, "", "Unauthorised URL %s", URL)
|
|
||||||
//return errors.NewInvalidCredentialsf(httpError, "", "Unauthorised URL %s", URL)
|
|
||||||
case http.StatusForbidden:
|
|
||||||
//return errors.
|
|
||||||
case http.StatusNotFound:
|
|
||||||
return errors.NewResourceNotFoundf(httpError, "", "Resource not found %s", URL)
|
|
||||||
case http.StatusMethodNotAllowed:
|
|
||||||
//return errors.
|
|
||||||
case http.StatusNotAcceptable:
|
|
||||||
return errors.NewInvalidHeaderf(httpError, "", "Invalid Header %s", URL)
|
|
||||||
case http.StatusConflict:
|
|
||||||
return errors.NewMissingParameterf(httpError, "", "Missing parameters %s", URL)
|
|
||||||
//return errors.NewInvalidArgumentf(httpError, "", "Invalid parameter %s", URL)
|
|
||||||
case http.StatusRequestEntityTooLarge:
|
|
||||||
return errors.NewRequestTooLargef(httpError, "", "Request too large %s", URL)
|
|
||||||
case http.StatusUnsupportedMediaType:
|
|
||||||
//return errors.
|
|
||||||
case http.StatusServiceUnavailable:
|
|
||||||
return errors.NewInternalErrorf(httpError, "", "Internal error %s", URL)
|
|
||||||
case 420:
|
|
||||||
// SlowDown
|
|
||||||
return errors.NewRequestThrottledf(httpError, "", "Request throttled %s", URL)
|
|
||||||
case 422:
|
|
||||||
// Unprocessable Entity
|
|
||||||
return errors.NewInvalidArgumentf(httpError, "", "Invalid parameters %s", URL)
|
|
||||||
case 449:
|
|
||||||
// RetryWith
|
|
||||||
return errors.NewInvalidVersionf(httpError, "", "Invalid version %s", URL)
|
|
||||||
//RequestMovedError -> ?
|
|
||||||
}
|
|
||||||
|
|
||||||
return errors.NewUnknownErrorf(httpError, "", "Unknown error %s", URL)
|
|
||||||
}
|
|
||||||
|
|
||||||
func isMantaRequest(url, user string) bool {
|
|
||||||
return strings.Contains(url, "/"+user+"/stor") || strings.Contains(url, "/"+user+"/jobs") || strings.Contains(url, "/"+user+"/public")
|
|
||||||
}
|
|
|
@ -1,105 +0,0 @@
|
||||||
//
|
|
||||||
// gocommon - Go library to interact with the JoyentCloud
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// Copyright (c) 2013 Joyent Inc.
|
|
||||||
//
|
|
||||||
// Written by Daniele Stroppa <daniele.stroppa@joyent.com>
|
|
||||||
//
|
|
||||||
|
|
||||||
package jpc
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
|
||||||
"reflect"
|
|
||||||
"runtime"
|
|
||||||
|
|
||||||
"github.com/joyent/gosign/auth"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
// Environment variables
|
|
||||||
SdcAccount = "SDC_ACCOUNT"
|
|
||||||
SdcKeyId = "SDC_KEY_ID"
|
|
||||||
SdcUrl = "SDC_URL"
|
|
||||||
MantaUser = "MANTA_USER"
|
|
||||||
MantaKeyId = "MANTA_KEY_ID"
|
|
||||||
MantaUrl = "MANTA_URL"
|
|
||||||
)
|
|
||||||
|
|
||||||
var Locations = map[string]string{
|
|
||||||
"us-east-1": "America/New_York",
|
|
||||||
"us-west-1": "America/Los_Angeles",
|
|
||||||
"us-sw-1": "America/Los_Angeles",
|
|
||||||
"eu-ams-1": "Europe/Amsterdam",
|
|
||||||
}
|
|
||||||
|
|
||||||
// getConfig returns the value of the first available environment
|
|
||||||
// variable, among the given ones.
|
|
||||||
func getConfig(envVars ...string) (value string) {
|
|
||||||
value = ""
|
|
||||||
for _, v := range envVars {
|
|
||||||
value = os.Getenv(v)
|
|
||||||
if value != "" {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// getUserHome returns the value of HOME environment
|
|
||||||
// variable for the user environment.
|
|
||||||
func getUserHome() string {
|
|
||||||
if runtime.GOOS == "windows" {
|
|
||||||
return os.Getenv("APPDATA")
|
|
||||||
} else {
|
|
||||||
return os.Getenv("HOME")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// credentialsFromEnv creates and initializes the credentials from the
|
|
||||||
// environment variables.
|
|
||||||
func credentialsFromEnv(key string) (*auth.Credentials, error) {
|
|
||||||
var keyName string
|
|
||||||
if key == "" {
|
|
||||||
keyName = getUserHome() + "/.ssh/id_rsa"
|
|
||||||
} else {
|
|
||||||
keyName = key
|
|
||||||
}
|
|
||||||
privateKey, err := ioutil.ReadFile(keyName)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
authentication, err := auth.NewAuth(getConfig(SdcAccount, MantaUser), string(privateKey), "rsa-sha256")
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return &auth.Credentials{
|
|
||||||
UserAuthentication: authentication,
|
|
||||||
SdcKeyId: getConfig(SdcKeyId),
|
|
||||||
SdcEndpoint: auth.Endpoint{URL: getConfig(SdcUrl)},
|
|
||||||
MantaKeyId: getConfig(MantaKeyId),
|
|
||||||
MantaEndpoint: auth.Endpoint{URL: getConfig(MantaUrl)},
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// CompleteCredentialsFromEnv gets and verifies all the required
|
|
||||||
// authentication parameters have values in the environment.
|
|
||||||
func CompleteCredentialsFromEnv(keyName string) (cred *auth.Credentials, err error) {
|
|
||||||
cred, err = credentialsFromEnv(keyName)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
v := reflect.ValueOf(cred).Elem()
|
|
||||||
t := v.Type()
|
|
||||||
for i := 0; i < v.NumField(); i++ {
|
|
||||||
f := v.Field(i)
|
|
||||||
if f.String() == "" {
|
|
||||||
return nil, fmt.Errorf("Required environment variable not set for credentials attribute: %s", t.Field(i).Name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return cred, nil
|
|
||||||
}
|
|
|
@ -1,46 +0,0 @@
|
||||||
package testing
|
|
||||||
|
|
||||||
// This package provides an HTTPSuite infrastructure that lets you bring up an
|
|
||||||
// HTTP server. The server will handle requests based on whatever Handlers are
|
|
||||||
// attached to HTTPSuite.Mux. This Mux is reset after every test case, and the
|
|
||||||
// server is shut down at the end of the test suite.
|
|
||||||
|
|
||||||
import (
|
|
||||||
gc "launchpad.net/gocheck"
|
|
||||||
"net/http"
|
|
||||||
"net/http/httptest"
|
|
||||||
)
|
|
||||||
|
|
||||||
var _ = gc.Suite(&HTTPSuite{})
|
|
||||||
|
|
||||||
type HTTPSuite struct {
|
|
||||||
Server *httptest.Server
|
|
||||||
Mux *http.ServeMux
|
|
||||||
oldHandler http.Handler
|
|
||||||
UseTLS bool
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *HTTPSuite) SetUpSuite(c *gc.C) {
|
|
||||||
if s.UseTLS {
|
|
||||||
s.Server = httptest.NewTLSServer(nil)
|
|
||||||
} else {
|
|
||||||
s.Server = httptest.NewServer(nil)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *HTTPSuite) SetUpTest(c *gc.C) {
|
|
||||||
s.oldHandler = s.Server.Config.Handler
|
|
||||||
s.Mux = http.NewServeMux()
|
|
||||||
s.Server.Config.Handler = s.Mux
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *HTTPSuite) TearDownTest(c *gc.C) {
|
|
||||||
s.Mux = nil
|
|
||||||
s.Server.Config.Handler = s.oldHandler
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *HTTPSuite) TearDownSuite(c *gc.C) {
|
|
||||||
if s.Server != nil {
|
|
||||||
s.Server.Close()
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,32 +0,0 @@
|
||||||
//
|
|
||||||
// gocommon - Go library to interact with the JoyentCloud
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// Copyright (c) 2013 Joyent Inc.
|
|
||||||
//
|
|
||||||
// Written by Daniele Stroppa <daniele.stroppa@joyent.com>
|
|
||||||
//
|
|
||||||
|
|
||||||
package gocommon
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
)
|
|
||||||
|
|
||||||
type VersionNum struct {
|
|
||||||
Major int
|
|
||||||
Minor int
|
|
||||||
Micro int
|
|
||||||
}
|
|
||||||
|
|
||||||
func (v *VersionNum) String() string {
|
|
||||||
return fmt.Sprintf("%d.%d.%d", v.Major, v.Minor, v.Micro)
|
|
||||||
}
|
|
||||||
|
|
||||||
var VersionNumber = VersionNum{
|
|
||||||
Major: 0,
|
|
||||||
Minor: 1,
|
|
||||||
Micro: 0,
|
|
||||||
}
|
|
||||||
|
|
||||||
var Version = VersionNumber.String()
|
|
|
@ -1,373 +0,0 @@
|
||||||
Mozilla Public License Version 2.0
|
|
||||||
==================================
|
|
||||||
|
|
||||||
1. Definitions
|
|
||||||
--------------
|
|
||||||
|
|
||||||
1.1. "Contributor"
|
|
||||||
means each individual or legal entity that creates, contributes to
|
|
||||||
the creation of, or owns Covered Software.
|
|
||||||
|
|
||||||
1.2. "Contributor Version"
|
|
||||||
means the combination of the Contributions of others (if any) used
|
|
||||||
by a Contributor and that particular Contributor's Contribution.
|
|
||||||
|
|
||||||
1.3. "Contribution"
|
|
||||||
means Covered Software of a particular Contributor.
|
|
||||||
|
|
||||||
1.4. "Covered Software"
|
|
||||||
means Source Code Form to which the initial Contributor has attached
|
|
||||||
the notice in Exhibit A, the Executable Form of such Source Code
|
|
||||||
Form, and Modifications of such Source Code Form, in each case
|
|
||||||
including portions thereof.
|
|
||||||
|
|
||||||
1.5. "Incompatible With Secondary Licenses"
|
|
||||||
means
|
|
||||||
|
|
||||||
(a) that the initial Contributor has attached the notice described
|
|
||||||
in Exhibit B to the Covered Software; or
|
|
||||||
|
|
||||||
(b) that the Covered Software was made available under the terms of
|
|
||||||
version 1.1 or earlier of the License, but not also under the
|
|
||||||
terms of a Secondary License.
|
|
||||||
|
|
||||||
1.6. "Executable Form"
|
|
||||||
means any form of the work other than Source Code Form.
|
|
||||||
|
|
||||||
1.7. "Larger Work"
|
|
||||||
means a work that combines Covered Software with other material, in
|
|
||||||
a separate file or files, that is not Covered Software.
|
|
||||||
|
|
||||||
1.8. "License"
|
|
||||||
means this document.
|
|
||||||
|
|
||||||
1.9. "Licensable"
|
|
||||||
means having the right to grant, to the maximum extent possible,
|
|
||||||
whether at the time of the initial grant or subsequently, any and
|
|
||||||
all of the rights conveyed by this License.
|
|
||||||
|
|
||||||
1.10. "Modifications"
|
|
||||||
means any of the following:
|
|
||||||
|
|
||||||
(a) any file in Source Code Form that results from an addition to,
|
|
||||||
deletion from, or modification of the contents of Covered
|
|
||||||
Software; or
|
|
||||||
|
|
||||||
(b) any new file in Source Code Form that contains any Covered
|
|
||||||
Software.
|
|
||||||
|
|
||||||
1.11. "Patent Claims" of a Contributor
|
|
||||||
means any patent claim(s), including without limitation, method,
|
|
||||||
process, and apparatus claims, in any patent Licensable by such
|
|
||||||
Contributor that would be infringed, but for the grant of the
|
|
||||||
License, by the making, using, selling, offering for sale, having
|
|
||||||
made, import, or transfer of either its Contributions or its
|
|
||||||
Contributor Version.
|
|
||||||
|
|
||||||
1.12. "Secondary License"
|
|
||||||
means either the GNU General Public License, Version 2.0, the GNU
|
|
||||||
Lesser General Public License, Version 2.1, the GNU Affero General
|
|
||||||
Public License, Version 3.0, or any later versions of those
|
|
||||||
licenses.
|
|
||||||
|
|
||||||
1.13. "Source Code Form"
|
|
||||||
means the form of the work preferred for making modifications.
|
|
||||||
|
|
||||||
1.14. "You" (or "Your")
|
|
||||||
means an individual or a legal entity exercising rights under this
|
|
||||||
License. For legal entities, "You" includes any entity that
|
|
||||||
controls, is controlled by, or is under common control with You. For
|
|
||||||
purposes of this definition, "control" means (a) the power, direct
|
|
||||||
or indirect, to cause the direction or management of such entity,
|
|
||||||
whether by contract or otherwise, or (b) ownership of more than
|
|
||||||
fifty percent (50%) of the outstanding shares or beneficial
|
|
||||||
ownership of such entity.
|
|
||||||
|
|
||||||
2. License Grants and Conditions
|
|
||||||
--------------------------------
|
|
||||||
|
|
||||||
2.1. Grants
|
|
||||||
|
|
||||||
Each Contributor hereby grants You a world-wide, royalty-free,
|
|
||||||
non-exclusive license:
|
|
||||||
|
|
||||||
(a) under intellectual property rights (other than patent or trademark)
|
|
||||||
Licensable by such Contributor to use, reproduce, make available,
|
|
||||||
modify, display, perform, distribute, and otherwise exploit its
|
|
||||||
Contributions, either on an unmodified basis, with Modifications, or
|
|
||||||
as part of a Larger Work; and
|
|
||||||
|
|
||||||
(b) under Patent Claims of such Contributor to make, use, sell, offer
|
|
||||||
for sale, have made, import, and otherwise transfer either its
|
|
||||||
Contributions or its Contributor Version.
|
|
||||||
|
|
||||||
2.2. Effective Date
|
|
||||||
|
|
||||||
The licenses granted in Section 2.1 with respect to any Contribution
|
|
||||||
become effective for each Contribution on the date the Contributor first
|
|
||||||
distributes such Contribution.
|
|
||||||
|
|
||||||
2.3. Limitations on Grant Scope
|
|
||||||
|
|
||||||
The licenses granted in this Section 2 are the only rights granted under
|
|
||||||
this License. No additional rights or licenses will be implied from the
|
|
||||||
distribution or licensing of Covered Software under this License.
|
|
||||||
Notwithstanding Section 2.1(b) above, no patent license is granted by a
|
|
||||||
Contributor:
|
|
||||||
|
|
||||||
(a) for any code that a Contributor has removed from Covered Software;
|
|
||||||
or
|
|
||||||
|
|
||||||
(b) for infringements caused by: (i) Your and any other third party's
|
|
||||||
modifications of Covered Software, or (ii) the combination of its
|
|
||||||
Contributions with other software (except as part of its Contributor
|
|
||||||
Version); or
|
|
||||||
|
|
||||||
(c) under Patent Claims infringed by Covered Software in the absence of
|
|
||||||
its Contributions.
|
|
||||||
|
|
||||||
This License does not grant any rights in the trademarks, service marks,
|
|
||||||
or logos of any Contributor (except as may be necessary to comply with
|
|
||||||
the notice requirements in Section 3.4).
|
|
||||||
|
|
||||||
2.4. Subsequent Licenses
|
|
||||||
|
|
||||||
No Contributor makes additional grants as a result of Your choice to
|
|
||||||
distribute the Covered Software under a subsequent version of this
|
|
||||||
License (see Section 10.2) or under the terms of a Secondary License (if
|
|
||||||
permitted under the terms of Section 3.3).
|
|
||||||
|
|
||||||
2.5. Representation
|
|
||||||
|
|
||||||
Each Contributor represents that the Contributor believes its
|
|
||||||
Contributions are its original creation(s) or it has sufficient rights
|
|
||||||
to grant the rights to its Contributions conveyed by this License.
|
|
||||||
|
|
||||||
2.6. Fair Use
|
|
||||||
|
|
||||||
This License is not intended to limit any rights You have under
|
|
||||||
applicable copyright doctrines of fair use, fair dealing, or other
|
|
||||||
equivalents.
|
|
||||||
|
|
||||||
2.7. Conditions
|
|
||||||
|
|
||||||
Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
|
|
||||||
in Section 2.1.
|
|
||||||
|
|
||||||
3. Responsibilities
|
|
||||||
-------------------
|
|
||||||
|
|
||||||
3.1. Distribution of Source Form
|
|
||||||
|
|
||||||
All distribution of Covered Software in Source Code Form, including any
|
|
||||||
Modifications that You create or to which You contribute, must be under
|
|
||||||
the terms of this License. You must inform recipients that the Source
|
|
||||||
Code Form of the Covered Software is governed by the terms of this
|
|
||||||
License, and how they can obtain a copy of this License. You may not
|
|
||||||
attempt to alter or restrict the recipients' rights in the Source Code
|
|
||||||
Form.
|
|
||||||
|
|
||||||
3.2. Distribution of Executable Form
|
|
||||||
|
|
||||||
If You distribute Covered Software in Executable Form then:
|
|
||||||
|
|
||||||
(a) such Covered Software must also be made available in Source Code
|
|
||||||
Form, as described in Section 3.1, and You must inform recipients of
|
|
||||||
the Executable Form how they can obtain a copy of such Source Code
|
|
||||||
Form by reasonable means in a timely manner, at a charge no more
|
|
||||||
than the cost of distribution to the recipient; and
|
|
||||||
|
|
||||||
(b) You may distribute such Executable Form under the terms of this
|
|
||||||
License, or sublicense it under different terms, provided that the
|
|
||||||
license for the Executable Form does not attempt to limit or alter
|
|
||||||
the recipients' rights in the Source Code Form under this License.
|
|
||||||
|
|
||||||
3.3. Distribution of a Larger Work
|
|
||||||
|
|
||||||
You may create and distribute a Larger Work under terms of Your choice,
|
|
||||||
provided that You also comply with the requirements of this License for
|
|
||||||
the Covered Software. If the Larger Work is a combination of Covered
|
|
||||||
Software with a work governed by one or more Secondary Licenses, and the
|
|
||||||
Covered Software is not Incompatible With Secondary Licenses, this
|
|
||||||
License permits You to additionally distribute such Covered Software
|
|
||||||
under the terms of such Secondary License(s), so that the recipient of
|
|
||||||
the Larger Work may, at their option, further distribute the Covered
|
|
||||||
Software under the terms of either this License or such Secondary
|
|
||||||
License(s).
|
|
||||||
|
|
||||||
3.4. Notices
|
|
||||||
|
|
||||||
You may not remove or alter the substance of any license notices
|
|
||||||
(including copyright notices, patent notices, disclaimers of warranty,
|
|
||||||
or limitations of liability) contained within the Source Code Form of
|
|
||||||
the Covered Software, except that You may alter any license notices to
|
|
||||||
the extent required to remedy known factual inaccuracies.
|
|
||||||
|
|
||||||
3.5. Application of Additional Terms
|
|
||||||
|
|
||||||
You may choose to offer, and to charge a fee for, warranty, support,
|
|
||||||
indemnity or liability obligations to one or more recipients of Covered
|
|
||||||
Software. However, You may do so only on Your own behalf, and not on
|
|
||||||
behalf of any Contributor. You must make it absolutely clear that any
|
|
||||||
such warranty, support, indemnity, or liability obligation is offered by
|
|
||||||
You alone, and You hereby agree to indemnify every Contributor for any
|
|
||||||
liability incurred by such Contributor as a result of warranty, support,
|
|
||||||
indemnity or liability terms You offer. You may include additional
|
|
||||||
disclaimers of warranty and limitations of liability specific to any
|
|
||||||
jurisdiction.
|
|
||||||
|
|
||||||
4. Inability to Comply Due to Statute or Regulation
|
|
||||||
---------------------------------------------------
|
|
||||||
|
|
||||||
If it is impossible for You to comply with any of the terms of this
|
|
||||||
License with respect to some or all of the Covered Software due to
|
|
||||||
statute, judicial order, or regulation then You must: (a) comply with
|
|
||||||
the terms of this License to the maximum extent possible; and (b)
|
|
||||||
describe the limitations and the code they affect. Such description must
|
|
||||||
be placed in a text file included with all distributions of the Covered
|
|
||||||
Software under this License. Except to the extent prohibited by statute
|
|
||||||
or regulation, such description must be sufficiently detailed for a
|
|
||||||
recipient of ordinary skill to be able to understand it.
|
|
||||||
|
|
||||||
5. Termination
|
|
||||||
--------------
|
|
||||||
|
|
||||||
5.1. The rights granted under this License will terminate automatically
|
|
||||||
if You fail to comply with any of its terms. However, if You become
|
|
||||||
compliant, then the rights granted under this License from a particular
|
|
||||||
Contributor are reinstated (a) provisionally, unless and until such
|
|
||||||
Contributor explicitly and finally terminates Your grants, and (b) on an
|
|
||||||
ongoing basis, if such Contributor fails to notify You of the
|
|
||||||
non-compliance by some reasonable means prior to 60 days after You have
|
|
||||||
come back into compliance. Moreover, Your grants from a particular
|
|
||||||
Contributor are reinstated on an ongoing basis if such Contributor
|
|
||||||
notifies You of the non-compliance by some reasonable means, this is the
|
|
||||||
first time You have received notice of non-compliance with this License
|
|
||||||
from such Contributor, and You become compliant prior to 30 days after
|
|
||||||
Your receipt of the notice.
|
|
||||||
|
|
||||||
5.2. If You initiate litigation against any entity by asserting a patent
|
|
||||||
infringement claim (excluding declaratory judgment actions,
|
|
||||||
counter-claims, and cross-claims) alleging that a Contributor Version
|
|
||||||
directly or indirectly infringes any patent, then the rights granted to
|
|
||||||
You by any and all Contributors for the Covered Software under Section
|
|
||||||
2.1 of this License shall terminate.
|
|
||||||
|
|
||||||
5.3. In the event of termination under Sections 5.1 or 5.2 above, all
|
|
||||||
end user license agreements (excluding distributors and resellers) which
|
|
||||||
have been validly granted by You or Your distributors under this License
|
|
||||||
prior to termination shall survive termination.
|
|
||||||
|
|
||||||
************************************************************************
|
|
||||||
* *
|
|
||||||
* 6. Disclaimer of Warranty *
|
|
||||||
* ------------------------- *
|
|
||||||
* *
|
|
||||||
* Covered Software is provided under this License on an "as is" *
|
|
||||||
* basis, without warranty of any kind, either expressed, implied, or *
|
|
||||||
* statutory, including, without limitation, warranties that the *
|
|
||||||
* Covered Software is free of defects, merchantable, fit for a *
|
|
||||||
* particular purpose or non-infringing. The entire risk as to the *
|
|
||||||
* quality and performance of the Covered Software is with You. *
|
|
||||||
* Should any Covered Software prove defective in any respect, You *
|
|
||||||
* (not any Contributor) assume the cost of any necessary servicing, *
|
|
||||||
* repair, or correction. This disclaimer of warranty constitutes an *
|
|
||||||
* essential part of this License. No use of any Covered Software is *
|
|
||||||
* authorized under this License except under this disclaimer. *
|
|
||||||
* *
|
|
||||||
************************************************************************
|
|
||||||
|
|
||||||
************************************************************************
|
|
||||||
* *
|
|
||||||
* 7. Limitation of Liability *
|
|
||||||
* -------------------------- *
|
|
||||||
* *
|
|
||||||
* Under no circumstances and under no legal theory, whether tort *
|
|
||||||
* (including negligence), contract, or otherwise, shall any *
|
|
||||||
* Contributor, or anyone who distributes Covered Software as *
|
|
||||||
* permitted above, be liable to You for any direct, indirect, *
|
|
||||||
* special, incidental, or consequential damages of any character *
|
|
||||||
* including, without limitation, damages for lost profits, loss of *
|
|
||||||
* goodwill, work stoppage, computer failure or malfunction, or any *
|
|
||||||
* and all other commercial damages or losses, even if such party *
|
|
||||||
* shall have been informed of the possibility of such damages. This *
|
|
||||||
* limitation of liability shall not apply to liability for death or *
|
|
||||||
* personal injury resulting from such party's negligence to the *
|
|
||||||
* extent applicable law prohibits such limitation. Some *
|
|
||||||
* jurisdictions do not allow the exclusion or limitation of *
|
|
||||||
* incidental or consequential damages, so this exclusion and *
|
|
||||||
* limitation may not apply to You. *
|
|
||||||
* *
|
|
||||||
************************************************************************
|
|
||||||
|
|
||||||
8. Litigation
|
|
||||||
-------------
|
|
||||||
|
|
||||||
Any litigation relating to this License may be brought only in the
|
|
||||||
courts of a jurisdiction where the defendant maintains its principal
|
|
||||||
place of business and such litigation shall be governed by laws of that
|
|
||||||
jurisdiction, without reference to its conflict-of-law provisions.
|
|
||||||
Nothing in this Section shall prevent a party's ability to bring
|
|
||||||
cross-claims or counter-claims.
|
|
||||||
|
|
||||||
9. Miscellaneous
|
|
||||||
----------------
|
|
||||||
|
|
||||||
This License represents the complete agreement concerning the subject
|
|
||||||
matter hereof. If any provision of this License is held to be
|
|
||||||
unenforceable, such provision shall be reformed only to the extent
|
|
||||||
necessary to make it enforceable. Any law or regulation which provides
|
|
||||||
that the language of a contract shall be construed against the drafter
|
|
||||||
shall not be used to construe this License against a Contributor.
|
|
||||||
|
|
||||||
10. Versions of the License
|
|
||||||
---------------------------
|
|
||||||
|
|
||||||
10.1. New Versions
|
|
||||||
|
|
||||||
Mozilla Foundation is the license steward. Except as provided in Section
|
|
||||||
10.3, no one other than the license steward has the right to modify or
|
|
||||||
publish new versions of this License. Each version will be given a
|
|
||||||
distinguishing version number.
|
|
||||||
|
|
||||||
10.2. Effect of New Versions
|
|
||||||
|
|
||||||
You may distribute the Covered Software under the terms of the version
|
|
||||||
of the License under which You originally received the Covered Software,
|
|
||||||
or under the terms of any subsequent version published by the license
|
|
||||||
steward.
|
|
||||||
|
|
||||||
10.3. Modified Versions
|
|
||||||
|
|
||||||
If you create software not governed by this License, and you want to
|
|
||||||
create a new license for such software, you may create and use a
|
|
||||||
modified version of this License if you rename the license and remove
|
|
||||||
any references to the name of the license steward (except to note that
|
|
||||||
such modified license differs from this License).
|
|
||||||
|
|
||||||
10.4. Distributing Source Code Form that is Incompatible With Secondary
|
|
||||||
Licenses
|
|
||||||
|
|
||||||
If You choose to distribute Source Code Form that is Incompatible With
|
|
||||||
Secondary Licenses under the terms of this version of the License, the
|
|
||||||
notice described in Exhibit B of this License must be attached.
|
|
||||||
|
|
||||||
Exhibit A - Source Code Form License Notice
|
|
||||||
-------------------------------------------
|
|
||||||
|
|
||||||
This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
||||||
file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
||||||
|
|
||||||
If it is not possible or desirable to put the notice in a particular
|
|
||||||
file, then You may include the notice in a location (such as a LICENSE
|
|
||||||
file in a relevant directory) where a recipient would be likely to look
|
|
||||||
for such a notice.
|
|
||||||
|
|
||||||
You may add additional accurate notices of copyright ownership.
|
|
||||||
|
|
||||||
Exhibit B - "Incompatible With Secondary Licenses" Notice
|
|
||||||
---------------------------------------------------------
|
|
||||||
|
|
||||||
This Source Code Form is "Incompatible With Secondary Licenses", as
|
|
||||||
defined by the Mozilla Public License, v. 2.0.
|
|
|
@ -1,130 +0,0 @@
|
||||||
/*
|
|
||||||
Package cloudapi interacts with the Cloud API (http://apidocs.joyent.com/cloudapi/).
|
|
||||||
|
|
||||||
Licensed under the Mozilla Public License version 2.0
|
|
||||||
|
|
||||||
Copyright (c) Joyent Inc.
|
|
||||||
*/
|
|
||||||
package cloudapi
|
|
||||||
|
|
||||||
import (
|
|
||||||
"net/http"
|
|
||||||
"net/url"
|
|
||||||
"path"
|
|
||||||
|
|
||||||
"github.com/joyent/gocommon/client"
|
|
||||||
jh "github.com/joyent/gocommon/http"
|
|
||||||
"github.com/juju/loggo"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
// DefaultAPIVersion defines the default version of the Cloud API to use
|
|
||||||
DefaultAPIVersion = "~7.3"
|
|
||||||
|
|
||||||
// CloudAPI URL parts
|
|
||||||
apiKeys = "keys"
|
|
||||||
apiPackages = "packages"
|
|
||||||
apiImages = "images"
|
|
||||||
apiDatacenters = "datacenters"
|
|
||||||
apiMachines = "machines"
|
|
||||||
apiMetadata = "metadata"
|
|
||||||
apiSnapshots = "snapshots"
|
|
||||||
apiTags = "tags"
|
|
||||||
apiAnalytics = "analytics"
|
|
||||||
apiInstrumentations = "instrumentations"
|
|
||||||
apiInstrumentationsValue = "value"
|
|
||||||
apiInstrumentationsRaw = "raw"
|
|
||||||
apiInstrumentationsHeatmap = "heatmap"
|
|
||||||
apiInstrumentationsImage = "image"
|
|
||||||
apiInstrumentationsDetails = "details"
|
|
||||||
apiUsage = "usage"
|
|
||||||
apiAudit = "audit"
|
|
||||||
apiFirewallRules = "fwrules"
|
|
||||||
apiFirewallRulesEnable = "enable"
|
|
||||||
apiFirewallRulesDisable = "disable"
|
|
||||||
apiNetworks = "networks"
|
|
||||||
apiFabricVLANs = "fabrics/default/vlans"
|
|
||||||
apiFabricNetworks = "networks"
|
|
||||||
apiNICs = "nics"
|
|
||||||
|
|
||||||
// CloudAPI actions
|
|
||||||
actionExport = "export"
|
|
||||||
actionStop = "stop"
|
|
||||||
actionStart = "start"
|
|
||||||
actionReboot = "reboot"
|
|
||||||
actionResize = "resize"
|
|
||||||
actionRename = "rename"
|
|
||||||
actionEnableFw = "enable_firewall"
|
|
||||||
actionDisableFw = "disable_firewall"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Logger for this package
|
|
||||||
var Logger = loggo.GetLogger("gosdc.cloudapi")
|
|
||||||
|
|
||||||
// Client provides a means to access the Joyent CloudAPI
|
|
||||||
type Client struct {
|
|
||||||
client client.Client
|
|
||||||
}
|
|
||||||
|
|
||||||
// New creates a new Client.
|
|
||||||
func New(client client.Client) *Client {
|
|
||||||
return &Client{client}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Filter represents a filter that can be applied to an API request.
|
|
||||||
type Filter struct {
|
|
||||||
v url.Values
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewFilter creates a new Filter.
|
|
||||||
func NewFilter() *Filter {
|
|
||||||
return &Filter{make(url.Values)}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set a value for the specified filter.
|
|
||||||
func (f *Filter) Set(filter, value string) {
|
|
||||||
f.v.Set(filter, value)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add a value for the specified filter.
|
|
||||||
func (f *Filter) Add(filter, value string) {
|
|
||||||
f.v.Add(filter, value)
|
|
||||||
}
|
|
||||||
|
|
||||||
// request represents an API request
|
|
||||||
type request struct {
|
|
||||||
method string
|
|
||||||
url string
|
|
||||||
filter *Filter
|
|
||||||
reqValue interface{}
|
|
||||||
reqHeader http.Header
|
|
||||||
resp interface{}
|
|
||||||
respHeader *http.Header
|
|
||||||
expectedStatus int
|
|
||||||
}
|
|
||||||
|
|
||||||
// Helper method to send an API request
|
|
||||||
func (c *Client) sendRequest(req request) (*jh.ResponseData, error) {
|
|
||||||
request := jh.RequestData{
|
|
||||||
ReqValue: req.reqValue,
|
|
||||||
ReqHeaders: req.reqHeader,
|
|
||||||
}
|
|
||||||
if req.filter != nil {
|
|
||||||
request.Params = &req.filter.v
|
|
||||||
}
|
|
||||||
if req.expectedStatus == 0 {
|
|
||||||
req.expectedStatus = http.StatusOK
|
|
||||||
}
|
|
||||||
respData := jh.ResponseData{
|
|
||||||
RespValue: req.resp,
|
|
||||||
RespHeaders: req.respHeader,
|
|
||||||
ExpectedStatus: []int{req.expectedStatus},
|
|
||||||
}
|
|
||||||
err := c.client.SendRequest(req.method, req.url, "", &request, &respData)
|
|
||||||
return &respData, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Helper method to create the API URL
|
|
||||||
func makeURL(parts ...string) string {
|
|
||||||
return path.Join(parts...)
|
|
||||||
}
|
|
|
@ -1,41 +0,0 @@
|
||||||
package cloudapi
|
|
||||||
|
|
||||||
import (
|
|
||||||
"net/http"
|
|
||||||
|
|
||||||
"github.com/joyent/gocommon/client"
|
|
||||||
"github.com/joyent/gocommon/errors"
|
|
||||||
)
|
|
||||||
|
|
||||||
// ListDatacenters provides a list of all datacenters this cloud is aware of.
|
|
||||||
// See API docs: http://apidocs.joyent.com/cloudapi/#ListDatacenters
|
|
||||||
func (c *Client) ListDatacenters() (map[string]interface{}, error) {
|
|
||||||
var resp map[string]interface{}
|
|
||||||
req := request{
|
|
||||||
method: client.GET,
|
|
||||||
url: apiDatacenters,
|
|
||||||
resp: &resp,
|
|
||||||
}
|
|
||||||
if _, err := c.sendRequest(req); err != nil {
|
|
||||||
return nil, errors.Newf(err, "failed to get list of datcenters")
|
|
||||||
}
|
|
||||||
return resp, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetDatacenter gets an individual datacenter by name. Returns an HTTP redirect
|
|
||||||
// to your client, the datacenter URL is in the Location header.
|
|
||||||
// See API docs: http://apidocs.joyent.com/cloudapi/#GetDatacenter
|
|
||||||
func (c *Client) GetDatacenter(datacenterName string) (string, error) {
|
|
||||||
var respHeader http.Header
|
|
||||||
req := request{
|
|
||||||
method: client.GET,
|
|
||||||
url: makeURL(apiDatacenters, datacenterName),
|
|
||||||
respHeader: &respHeader,
|
|
||||||
expectedStatus: http.StatusFound,
|
|
||||||
}
|
|
||||||
respData, err := c.sendRequest(req)
|
|
||||||
if err != nil {
|
|
||||||
return "", errors.Newf(err, "failed to get datacenter with name: %s", datacenterName)
|
|
||||||
}
|
|
||||||
return respData.RespHeaders.Get("Location"), nil
|
|
||||||
}
|
|
|
@ -1,182 +0,0 @@
|
||||||
package cloudapi
|
|
||||||
|
|
||||||
import (
|
|
||||||
"net/http"
|
|
||||||
"strconv"
|
|
||||||
|
|
||||||
"github.com/joyent/gocommon/client"
|
|
||||||
"github.com/joyent/gocommon/errors"
|
|
||||||
)
|
|
||||||
|
|
||||||
type FabricVLAN struct {
|
|
||||||
Id int16 `json:"vlan_id"` // Number between 0-4095 indicating VLAN Id
|
|
||||||
Name string `json:"name"` // Unique name to identify VLAN
|
|
||||||
Description string `json:"description,omitempty"` // Optional description of the VLAN
|
|
||||||
}
|
|
||||||
|
|
||||||
type FabricNetwork struct {
|
|
||||||
Id string `json:"id"` // Unique identifier for network
|
|
||||||
Name string `json:"name"` // Network name
|
|
||||||
Public bool `json:"public"` // Whether or not this is an RFC1918 network
|
|
||||||
Fabric bool `json:"fabric"` // Whether this network is on a fabric
|
|
||||||
Description string `json:"description"` // Optional description of network
|
|
||||||
Subnet string `json:"subnet"` // CIDR formatted string describing network
|
|
||||||
ProvisionStartIp string `json:"provision_start_ip"` // First IP on the network that can be assigned
|
|
||||||
ProvisionEndIp string `json:"provision_end_ip"` // Last assignable IP on the network
|
|
||||||
Gateway string `json:"gateway"` // Optional Gateway IP
|
|
||||||
Resolvers []string `json:"resolvers,omitempty"` // Array of IP addresses for resolvers
|
|
||||||
Routes map[string]string `json:"routes,omitempty"` // Map of CIDR block to Gateway IP Address
|
|
||||||
InternetNAT bool `json:"internet_nat"` // If a NAT zone is provisioned at Gateway IP Address
|
|
||||||
VLANId int16 `json:"vlan_id"` // VLAN network is on
|
|
||||||
}
|
|
||||||
|
|
||||||
type CreateFabricNetworkOpts struct {
|
|
||||||
Name string `json:"name"` // Network name
|
|
||||||
Description string `json:"description,omitempty"` // Optional description of network
|
|
||||||
Subnet string `json:"subnet"` // CIDR formatted string describing network
|
|
||||||
ProvisionStartIp string `json:"provision_start_ip"` // First IP on the network that can be assigned
|
|
||||||
ProvisionEndIp string `json:"provision_end_ip"` // Last assignable IP on the network
|
|
||||||
Gateway string `json:"gateway,omitempty"` // Optional Gateway IP
|
|
||||||
Resolvers []string `json:"resolvers,omitempty"` // Array of IP addresses for resolvers
|
|
||||||
Routes map[string]string `json:"routes,omitempty"` // Map of CIDR block to Gateway IP Address
|
|
||||||
InternetNAT bool `json:"internet_nat"` // If a NAT zone is provisioned at Gateway IP Address
|
|
||||||
}
|
|
||||||
|
|
||||||
// ListFabricVLANs lists VLANs
|
|
||||||
// See API docs: https://apidocs.joyent.com/cloudapi/#ListFabricVLANs
|
|
||||||
func (c *Client) ListFabricVLANs() ([]FabricVLAN, error) {
|
|
||||||
var resp []FabricVLAN
|
|
||||||
req := request{
|
|
||||||
method: client.GET,
|
|
||||||
url: apiFabricVLANs,
|
|
||||||
resp: &resp,
|
|
||||||
}
|
|
||||||
if _, err := c.sendRequest(req); err != nil {
|
|
||||||
return nil, errors.Newf(err, "failed to get list of fabric VLANs")
|
|
||||||
}
|
|
||||||
return resp, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetFabricLAN retrieves a single VLAN by ID
|
|
||||||
// See API docs: https://apidocs.joyent.com/cloudapi/#GetFabricVLAN
|
|
||||||
func (c *Client) GetFabricVLAN(vlanID int16) (*FabricVLAN, error) {
|
|
||||||
var resp FabricVLAN
|
|
||||||
req := request{
|
|
||||||
method: client.GET,
|
|
||||||
url: makeURL(apiFabricVLANs, strconv.Itoa(int(vlanID))),
|
|
||||||
resp: &resp,
|
|
||||||
}
|
|
||||||
if _, err := c.sendRequest(req); err != nil {
|
|
||||||
return nil, errors.Newf(err, "failed to get fabric VLAN with id %d", vlanID)
|
|
||||||
}
|
|
||||||
return &resp, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// CreateFabricVLAN creates a new VLAN with the specified options
|
|
||||||
// See API docs: https://apidocs.joyent.com/cloudapi/#CreateFabricVLAN
|
|
||||||
func (c *Client) CreateFabricVLAN(vlan FabricVLAN) (*FabricVLAN, error) {
|
|
||||||
var resp FabricVLAN
|
|
||||||
req := request{
|
|
||||||
method: client.POST,
|
|
||||||
url: apiFabricVLANs,
|
|
||||||
reqValue: vlan,
|
|
||||||
resp: &resp,
|
|
||||||
expectedStatus: http.StatusCreated,
|
|
||||||
}
|
|
||||||
if _, err := c.sendRequest(req); err != nil {
|
|
||||||
return nil, errors.Newf(err, "failed to create fabric VLAN: %d - %s", vlan.Id, vlan.Name)
|
|
||||||
}
|
|
||||||
return &resp, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// UpdateFabricVLAN updates a given VLAN with new fields
|
|
||||||
// See API docs: https://apidocs.joyent.com/cloudapi/#UpdateFabricVLAN
|
|
||||||
func (c *Client) UpdateFabricVLAN(vlan FabricVLAN) (*FabricVLAN, error) {
|
|
||||||
var resp FabricVLAN
|
|
||||||
req := request{
|
|
||||||
method: client.PUT,
|
|
||||||
url: makeURL(apiFabricVLANs, strconv.Itoa(int(vlan.Id))),
|
|
||||||
reqValue: vlan,
|
|
||||||
resp: &resp,
|
|
||||||
expectedStatus: http.StatusAccepted,
|
|
||||||
}
|
|
||||||
if _, err := c.sendRequest(req); err != nil {
|
|
||||||
return nil, errors.Newf(err, "failed to update fabric VLAN with id %d to %s - %s", vlan.Id, vlan.Name, vlan.Description)
|
|
||||||
}
|
|
||||||
return &resp, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// DeleteFabricVLAN delets a given VLAN as specified by ID
|
|
||||||
// See API docs: https://apidocs.joyent.com/cloudapi/#DeleteFabricVLAN
|
|
||||||
func (c *Client) DeleteFabricVLAN(vlanID int16) error {
|
|
||||||
req := request{
|
|
||||||
method: client.DELETE,
|
|
||||||
url: makeURL(apiFabricVLANs, strconv.Itoa(int(vlanID))),
|
|
||||||
expectedStatus: http.StatusNoContent,
|
|
||||||
}
|
|
||||||
if _, err := c.sendRequest(req); err != nil {
|
|
||||||
return errors.Newf(err, "failed to delete fabric VLAN with id %d", vlanID)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ListFabricNetworks lists the networks inside the given VLAN
|
|
||||||
// See API docs: https://apidocs.joyent.com/cloudapi/#ListFabricNetworks
|
|
||||||
func (c *Client) ListFabricNetworks(vlanID int16) ([]FabricNetwork, error) {
|
|
||||||
var resp []FabricNetwork
|
|
||||||
req := request{
|
|
||||||
method: client.GET,
|
|
||||||
url: makeURL(apiFabricVLANs, strconv.Itoa(int(vlanID)), apiFabricNetworks),
|
|
||||||
resp: &resp,
|
|
||||||
}
|
|
||||||
if _, err := c.sendRequest(req); err != nil {
|
|
||||||
return nil, errors.Newf(err, "failed to get list of networks on fabric %d", vlanID)
|
|
||||||
}
|
|
||||||
return resp, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetFabricNetwork gets a single network by VLAN and Network IDs
|
|
||||||
// See API docs: https://apidocs.joyent.com/cloudapi/#GetFabricNetwork
|
|
||||||
func (c *Client) GetFabricNetwork(vlanID int16, networkID string) (*FabricNetwork, error) {
|
|
||||||
var resp FabricNetwork
|
|
||||||
req := request{
|
|
||||||
method: client.GET,
|
|
||||||
url: makeURL(apiFabricVLANs, strconv.Itoa(int(vlanID)), apiFabricNetworks, networkID),
|
|
||||||
resp: &resp,
|
|
||||||
}
|
|
||||||
if _, err := c.sendRequest(req); err != nil {
|
|
||||||
return nil, errors.Newf(err, "failed to get fabric network %s on vlan %d", networkID, vlanID)
|
|
||||||
}
|
|
||||||
return &resp, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// CreateFabricNetwork creates a new fabric network
|
|
||||||
// See API docs: https://apidocs.joyent.com/cloudapi/#CreateFabricNetwork
|
|
||||||
func (c *Client) CreateFabricNetwork(vlanID int16, opts CreateFabricNetworkOpts) (*FabricNetwork, error) {
|
|
||||||
var resp FabricNetwork
|
|
||||||
req := request{
|
|
||||||
method: client.POST,
|
|
||||||
url: makeURL(apiFabricVLANs, strconv.Itoa(int(vlanID)), apiFabricNetworks),
|
|
||||||
reqValue: opts,
|
|
||||||
resp: &resp,
|
|
||||||
expectedStatus: http.StatusCreated,
|
|
||||||
}
|
|
||||||
if _, err := c.sendRequest(req); err != nil {
|
|
||||||
return nil, errors.Newf(err, "failed to create fabric network %s on vlan %d", opts.Name, vlanID)
|
|
||||||
}
|
|
||||||
return &resp, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// DeleteFabricNetwork deletes an existing fabric network
|
|
||||||
// See API docs: https://apidocs.joyent.com/cloudapi/#DeleteFabricNetwork
|
|
||||||
func (c *Client) DeleteFabricNetwork(vlanID int16, networkID string) error {
|
|
||||||
req := request{
|
|
||||||
method: client.DELETE,
|
|
||||||
url: makeURL(apiFabricVLANs, strconv.Itoa(int(vlanID)), apiFabricNetworks, networkID),
|
|
||||||
expectedStatus: http.StatusNoContent,
|
|
||||||
}
|
|
||||||
if _, err := c.sendRequest(req); err != nil {
|
|
||||||
return errors.Newf(err, "failed to delete fabric network %s on vlan %d", networkID, vlanID)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
|
@ -1,144 +0,0 @@
|
||||||
package cloudapi
|
|
||||||
|
|
||||||
import (
|
|
||||||
"net/http"
|
|
||||||
|
|
||||||
"github.com/joyent/gocommon/client"
|
|
||||||
"github.com/joyent/gocommon/errors"
|
|
||||||
)
|
|
||||||
|
|
||||||
// FirewallRule represent a firewall rule that can be specifed for a machine.
|
|
||||||
type FirewallRule struct {
|
|
||||||
Id string // Unique identifier for the rule
|
|
||||||
Enabled bool // Whether the rule is enabled or not
|
|
||||||
Rule string // Firewall rule in the form 'FROM <target a> TO <target b> <action> <protocol> <port>'
|
|
||||||
}
|
|
||||||
|
|
||||||
// CreateFwRuleOpts represent the option that can be specified
|
|
||||||
// when creating a new firewall rule.
|
|
||||||
type CreateFwRuleOpts struct {
|
|
||||||
Enabled bool `json:"enabled"` // Whether to enable the rule or not
|
|
||||||
Rule string `json:"rule"` // Firewall rule in the form 'FROM <target a> TO <target b> <action> <protocol> <port>'
|
|
||||||
}
|
|
||||||
|
|
||||||
// ListFirewallRules lists all the firewall rules on record for a specified account.
|
|
||||||
// See API docs: http://apidocs.joyent.com/cloudapi/#ListFirewallRules
|
|
||||||
func (c *Client) ListFirewallRules() ([]FirewallRule, error) {
|
|
||||||
var resp []FirewallRule
|
|
||||||
req := request{
|
|
||||||
method: client.GET,
|
|
||||||
url: apiFirewallRules,
|
|
||||||
resp: &resp,
|
|
||||||
}
|
|
||||||
if _, err := c.sendRequest(req); err != nil {
|
|
||||||
return nil, errors.Newf(err, "failed to get list of firewall rules")
|
|
||||||
}
|
|
||||||
return resp, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetFirewallRule returns the specified firewall rule.
|
|
||||||
// See API docs: http://apidocs.joyent.com/cloudapi/#GetFirewallRule
|
|
||||||
func (c *Client) GetFirewallRule(fwRuleID string) (*FirewallRule, error) {
|
|
||||||
var resp FirewallRule
|
|
||||||
req := request{
|
|
||||||
method: client.GET,
|
|
||||||
url: makeURL(apiFirewallRules, fwRuleID),
|
|
||||||
resp: &resp,
|
|
||||||
}
|
|
||||||
if _, err := c.sendRequest(req); err != nil {
|
|
||||||
return nil, errors.Newf(err, "failed to get firewall rule with id %s", fwRuleID)
|
|
||||||
}
|
|
||||||
return &resp, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// CreateFirewallRule creates the firewall rule with the specified options.
|
|
||||||
// See API docs: http://apidocs.joyent.com/cloudapi/#CreateFirewallRule
|
|
||||||
func (c *Client) CreateFirewallRule(opts CreateFwRuleOpts) (*FirewallRule, error) {
|
|
||||||
var resp FirewallRule
|
|
||||||
req := request{
|
|
||||||
method: client.POST,
|
|
||||||
url: apiFirewallRules,
|
|
||||||
reqValue: opts,
|
|
||||||
resp: &resp,
|
|
||||||
expectedStatus: http.StatusCreated,
|
|
||||||
}
|
|
||||||
if _, err := c.sendRequest(req); err != nil {
|
|
||||||
return nil, errors.Newf(err, "failed to create firewall rule: %s", opts.Rule)
|
|
||||||
}
|
|
||||||
return &resp, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// UpdateFirewallRule updates the specified firewall rule.
|
|
||||||
// See API docs: http://apidocs.joyent.com/cloudapi/#UpdateFirewallRule
|
|
||||||
func (c *Client) UpdateFirewallRule(fwRuleID string, opts CreateFwRuleOpts) (*FirewallRule, error) {
|
|
||||||
var resp FirewallRule
|
|
||||||
req := request{
|
|
||||||
method: client.POST,
|
|
||||||
url: makeURL(apiFirewallRules, fwRuleID),
|
|
||||||
reqValue: opts,
|
|
||||||
resp: &resp,
|
|
||||||
}
|
|
||||||
if _, err := c.sendRequest(req); err != nil {
|
|
||||||
return nil, errors.Newf(err, "failed to update firewall rule with id %s to %s", fwRuleID, opts.Rule)
|
|
||||||
}
|
|
||||||
return &resp, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// EnableFirewallRule enables the given firewall rule record if it is disabled.
|
|
||||||
// See API docs: http://apidocs.joyent.com/cloudapi/#EnableFirewallRule
|
|
||||||
func (c *Client) EnableFirewallRule(fwRuleID string) (*FirewallRule, error) {
|
|
||||||
var resp FirewallRule
|
|
||||||
req := request{
|
|
||||||
method: client.POST,
|
|
||||||
url: makeURL(apiFirewallRules, fwRuleID, apiFirewallRulesEnable),
|
|
||||||
resp: &resp,
|
|
||||||
}
|
|
||||||
if _, err := c.sendRequest(req); err != nil {
|
|
||||||
return nil, errors.Newf(err, "failed to enable firewall rule with id %s", fwRuleID)
|
|
||||||
}
|
|
||||||
return &resp, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// DisableFirewallRule disables the given firewall rule record if it is enabled.
|
|
||||||
// See API docs: http://apidocs.joyent.com/cloudapi/#DisableFirewallRule
|
|
||||||
func (c *Client) DisableFirewallRule(fwRuleID string) (*FirewallRule, error) {
|
|
||||||
var resp FirewallRule
|
|
||||||
req := request{
|
|
||||||
method: client.POST,
|
|
||||||
url: makeURL(apiFirewallRules, fwRuleID, apiFirewallRulesDisable),
|
|
||||||
resp: &resp,
|
|
||||||
}
|
|
||||||
if _, err := c.sendRequest(req); err != nil {
|
|
||||||
return nil, errors.Newf(err, "failed to disable firewall rule with id %s", fwRuleID)
|
|
||||||
}
|
|
||||||
return &resp, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// DeleteFirewallRule removes the given firewall rule record from all the required account machines.
|
|
||||||
// See API docs: http://apidocs.joyent.com/cloudapi/#DeleteFirewallRule
|
|
||||||
func (c *Client) DeleteFirewallRule(fwRuleID string) error {
|
|
||||||
req := request{
|
|
||||||
method: client.DELETE,
|
|
||||||
url: makeURL(apiFirewallRules, fwRuleID),
|
|
||||||
expectedStatus: http.StatusNoContent,
|
|
||||||
}
|
|
||||||
if _, err := c.sendRequest(req); err != nil {
|
|
||||||
return errors.Newf(err, "failed to delete firewall rule with id %s", fwRuleID)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ListFirewallRuleMachines return the list of machines affected by the given firewall rule.
|
|
||||||
// See API docs: http://apidocs.joyent.com/cloudapi/#ListFirewallRuleMachines
|
|
||||||
func (c *Client) ListFirewallRuleMachines(fwRuleID string) ([]Machine, error) {
|
|
||||||
var resp []Machine
|
|
||||||
req := request{
|
|
||||||
method: client.GET,
|
|
||||||
url: makeURL(apiFirewallRules, fwRuleID, apiMachines),
|
|
||||||
resp: &resp,
|
|
||||||
}
|
|
||||||
if _, err := c.sendRequest(req); err != nil {
|
|
||||||
return nil, errors.Newf(err, "failed to get list of machines affected by firewall rule wit id %s", fwRuleID)
|
|
||||||
}
|
|
||||||
return resp, nil
|
|
||||||
}
|
|
|
@ -1,133 +0,0 @@
|
||||||
package cloudapi
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"net/http"
|
|
||||||
|
|
||||||
"github.com/joyent/gocommon/client"
|
|
||||||
"github.com/joyent/gocommon/errors"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Image represent the software packages that will be available on newly provisioned machines
|
|
||||||
type Image struct {
|
|
||||||
Id string // Unique identifier for the image
|
|
||||||
Name string // Image friendly name
|
|
||||||
OS string // Underlying operating system
|
|
||||||
Version string // Image version
|
|
||||||
Type string // Image type, one of 'smartmachine' or 'virtualmachine'
|
|
||||||
Description string // Image description
|
|
||||||
Requirements map[string]interface{} // Minimum requirements for provisioning a machine with this image, e.g. 'password' indicates that a password must be provided
|
|
||||||
Homepage string // URL for a web page including detailed information for this image (new in API version 7.0)
|
|
||||||
PublishedAt string `json:"published_at"` // Time this image has been made publicly available (new in API version 7.0)
|
|
||||||
Public string // Indicates if the image is publicly available (new in API version 7.1)
|
|
||||||
State string // Current image state. One of 'active', 'unactivated', 'disabled', 'creating', 'failed' (new in API version 7.1)
|
|
||||||
Tags map[string]string // A map of key/value pairs that allows clients to categorize images by any given criteria (new in API version 7.1)
|
|
||||||
EULA string // URL of the End User License Agreement (EULA) for the image (new in API version 7.1)
|
|
||||||
ACL []string // An array of account UUIDs given access to a private image. The field is only relevant to private images (new in API version 7.1)
|
|
||||||
Owner string // The UUID of the user owning the image
|
|
||||||
}
|
|
||||||
|
|
||||||
// ExportImageOpts represent the option that can be specified
|
|
||||||
// when exporting an image.
|
|
||||||
type ExportImageOpts struct {
|
|
||||||
MantaPath string `json:"manta_path"` // The Manta path prefix to use when exporting the image
|
|
||||||
}
|
|
||||||
|
|
||||||
// MantaLocation represent the properties that allow a user
|
|
||||||
// to retrieve the image file and manifest from Manta
|
|
||||||
type MantaLocation struct {
|
|
||||||
MantaURL string `json:"manta_url"` // Manta datacenter URL
|
|
||||||
ImagePath string `json:"image_path"` // Path to the image
|
|
||||||
ManifestPath string `json:"manifest_path"` // Path to the image manifest
|
|
||||||
}
|
|
||||||
|
|
||||||
// CreateImageFromMachineOpts represent the option that can be specified
|
|
||||||
// when creating a new image from an existing machine.
|
|
||||||
type CreateImageFromMachineOpts struct {
|
|
||||||
Machine string `json:"machine"` // The machine UUID from which the image is to be created
|
|
||||||
Name string `json:"name"` // Image name
|
|
||||||
Version string `json:"version"` // Image version
|
|
||||||
Description string `json:"description"` // Image description
|
|
||||||
Homepage string `json:"homepage"` // URL for a web page including detailed information for this image
|
|
||||||
EULA string `json:"eula"` // URL of the End User License Agreement (EULA) for the image
|
|
||||||
ACL []string `json:"acl"` // An array of account UUIDs given access to a private image. The field is only relevant to private images
|
|
||||||
Tags map[string]string `json:"tags"` // A map of key/value pairs that allows clients to categorize images by any given criteria
|
|
||||||
}
|
|
||||||
|
|
||||||
// ListImages provides a list of images available in the datacenter.
|
|
||||||
// See API docs: http://apidocs.joyent.com/cloudapi/#ListImages
|
|
||||||
func (c *Client) ListImages(filter *Filter) ([]Image, error) {
|
|
||||||
var resp []Image
|
|
||||||
req := request{
|
|
||||||
method: client.GET,
|
|
||||||
url: apiImages,
|
|
||||||
filter: filter,
|
|
||||||
resp: &resp,
|
|
||||||
}
|
|
||||||
if _, err := c.sendRequest(req); err != nil {
|
|
||||||
return nil, errors.Newf(err, "failed to get list of images")
|
|
||||||
}
|
|
||||||
return resp, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetImage returns the image specified by imageId.
|
|
||||||
// See API docs: http://apidocs.joyent.com/cloudapi/#GetImage
|
|
||||||
func (c *Client) GetImage(imageID string) (*Image, error) {
|
|
||||||
var resp Image
|
|
||||||
req := request{
|
|
||||||
method: client.GET,
|
|
||||||
url: makeURL(apiImages, imageID),
|
|
||||||
resp: &resp,
|
|
||||||
}
|
|
||||||
if _, err := c.sendRequest(req); err != nil {
|
|
||||||
return nil, errors.Newf(err, "failed to get image with id: %s", imageID)
|
|
||||||
}
|
|
||||||
return &resp, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// DeleteImage (Beta) Delete the image specified by imageId. Must be image owner to do so.
|
|
||||||
// See API docs: http://apidocs.joyent.com/cloudapi/#DeleteImage
|
|
||||||
func (c *Client) DeleteImage(imageID string) error {
|
|
||||||
req := request{
|
|
||||||
method: client.DELETE,
|
|
||||||
url: makeURL(apiImages, imageID),
|
|
||||||
expectedStatus: http.StatusNoContent,
|
|
||||||
}
|
|
||||||
if _, err := c.sendRequest(req); err != nil {
|
|
||||||
return errors.Newf(err, "failed to delete image with id: %s", imageID)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ExportImage (Beta) Exports an image to the specified Manta path.
|
|
||||||
// See API docs: http://apidocs.joyent.com/cloudapi/#ListImages
|
|
||||||
func (c *Client) ExportImage(imageID string, opts ExportImageOpts) (*MantaLocation, error) {
|
|
||||||
var resp MantaLocation
|
|
||||||
req := request{
|
|
||||||
method: client.POST,
|
|
||||||
url: fmt.Sprintf("%s/%s?action=%s", apiImages, imageID, actionExport),
|
|
||||||
reqValue: opts,
|
|
||||||
resp: &resp,
|
|
||||||
}
|
|
||||||
if _, err := c.sendRequest(req); err != nil {
|
|
||||||
return nil, errors.Newf(err, "failed to export image %s to %s", imageID, opts.MantaPath)
|
|
||||||
}
|
|
||||||
return &resp, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// CreateImageFromMachine (Beta) Create a new custom image from a machine.
|
|
||||||
// See API docs: http://apidocs.joyent.com/cloudapi/#ListImages
|
|
||||||
func (c *Client) CreateImageFromMachine(opts CreateImageFromMachineOpts) (*Image, error) {
|
|
||||||
var resp Image
|
|
||||||
req := request{
|
|
||||||
method: client.POST,
|
|
||||||
url: apiImages,
|
|
||||||
reqValue: opts,
|
|
||||||
resp: &resp,
|
|
||||||
expectedStatus: http.StatusCreated,
|
|
||||||
}
|
|
||||||
if _, err := c.sendRequest(req); err != nil {
|
|
||||||
return nil, errors.Newf(err, "failed to create image from machine %s", opts.Machine)
|
|
||||||
}
|
|
||||||
return &resp, nil
|
|
||||||
}
|
|
|
@ -1,216 +0,0 @@
|
||||||
package cloudapi
|
|
||||||
|
|
||||||
import (
|
|
||||||
"net/http"
|
|
||||||
|
|
||||||
"github.com/joyent/gocommon/client"
|
|
||||||
"github.com/joyent/gocommon/errors"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Analytics represents the available analytics
|
|
||||||
type Analytics struct {
|
|
||||||
Modules map[string]interface{} // Namespace to organize metrics
|
|
||||||
Fields map[string]interface{} // Fields represent metadata by which data points can be filtered or decomposed
|
|
||||||
Types map[string]interface{} // Types are used with both metrics and fields for two purposes: to hint to clients at how to best label values, and to distinguish between numeric and discrete quantities.
|
|
||||||
Metrics map[string]interface{} // Metrics describe quantities which can be measured by the system
|
|
||||||
Transformations map[string]interface{} // Transformations are post-processing functions that can be applied to data when it's retrieved.
|
|
||||||
}
|
|
||||||
|
|
||||||
// Instrumentation specify which metric to collect, how frequently to aggregate data (e.g., every second, every hour, etc.)
|
|
||||||
// how much data to keep (e.g., 10 minutes' worth, 6 months' worth, etc.) and other configuration options
|
|
||||||
type Instrumentation struct {
|
|
||||||
Module string `json:"module"`
|
|
||||||
Stat string `json:"stat"`
|
|
||||||
Predicate string `json:"predicate"`
|
|
||||||
Decomposition []string `json:"decomposition"`
|
|
||||||
ValueDimension int `json:"value-dimenstion"`
|
|
||||||
ValueArity string `json:"value-arity"`
|
|
||||||
RetentionTime int `json:"retention-time"`
|
|
||||||
Granularity int `json:"granularitiy"`
|
|
||||||
IdleMax int `json:"idle-max"`
|
|
||||||
Transformations []string `json:"transformations"`
|
|
||||||
PersistData bool `json:"persist-data"`
|
|
||||||
Crtime int `json:"crtime"`
|
|
||||||
ValueScope string `json:"value-scope"`
|
|
||||||
Id string `json:"id"`
|
|
||||||
Uris []Uri `json:"uris"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Uri represents a Universal Resource Identifier
|
|
||||||
type Uri struct {
|
|
||||||
Uri string // Resource identifier
|
|
||||||
Name string // URI name
|
|
||||||
}
|
|
||||||
|
|
||||||
// InstrumentationValue represents the data associated to an instrumentation for a point in time
|
|
||||||
type InstrumentationValue struct {
|
|
||||||
Value interface{}
|
|
||||||
Transformations map[string]interface{}
|
|
||||||
StartTime int
|
|
||||||
Duration int
|
|
||||||
}
|
|
||||||
|
|
||||||
// HeatmapOpts represent the option that can be specified
|
|
||||||
// when retrieving an instrumentation.'s heatmap
|
|
||||||
type HeatmapOpts struct {
|
|
||||||
Height int `json:"height"` // Height of the image in pixels
|
|
||||||
Width int `json:"width"` // Width of the image in pixels
|
|
||||||
Ymin int `json:"ymin"` // Y-Axis value for the bottom of the image (default: 0)
|
|
||||||
Ymax int `json:"ymax"` // Y-Axis value for the top of the image (default: auto)
|
|
||||||
Nbuckets int `json:"nbuckets"` // Number of buckets in the vertical dimension
|
|
||||||
Selected []string `json:"selected"` // Array of field values to highlight, isolate or exclude
|
|
||||||
Isolate bool `json:"isolate"` // If true, only draw selected values
|
|
||||||
Exclude bool `json:"exclude"` // If true, don't draw selected values at all
|
|
||||||
Hues []string `json:"hues"` // Array of colors for highlighting selected field values
|
|
||||||
DecomposeAll bool `json:"decompose_all"` // Highlight all field values
|
|
||||||
X int `json:"x"`
|
|
||||||
Y int `json:"y"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Heatmap represents an instrumentation's heatmap
|
|
||||||
type Heatmap struct {
|
|
||||||
BucketTime int `json:"bucket_time"` // Time corresponding to the bucket (Unix seconds)
|
|
||||||
BucketYmin int `json:"bucket_ymin"` // Minimum y-axis value for the bucket
|
|
||||||
BucketYmax int `json:"bucket_ymax"` // Maximum y-axis value for the bucket
|
|
||||||
Present map[string]interface{} `json:"present"` // If the instrumentation defines a discrete decomposition, this property's value is an object whose keys are values of that field and whose values are the number of data points in that bucket for that key
|
|
||||||
Total int `json:"total"` // The total number of data points in the bucket
|
|
||||||
}
|
|
||||||
|
|
||||||
// CreateInstrumentationOpts represent the option that can be specified
|
|
||||||
// when creating a new instrumentation.
|
|
||||||
type CreateInstrumentationOpts struct {
|
|
||||||
Clone int `json:"clone"` // An existing instrumentation ID to be cloned
|
|
||||||
Module string `json:"module"` // Analytics module
|
|
||||||
Stat string `json:"stat"` // Analytics stat
|
|
||||||
Predicate string `json:"predicate"` // Instrumentation predicate, must be JSON string
|
|
||||||
Decomposition string `json:"decomposition"`
|
|
||||||
Granularity int `json:"granularity"` // Number of seconds between data points (default is 1)
|
|
||||||
RetentionTime int `json:"retention-time"` // How long to keep this instrumentation data for
|
|
||||||
PersistData bool `json:"persist-data"` // Whether or not to store this for historical analysis
|
|
||||||
IdleMax int `json:"idle-max"` // Number of seconds after which if the instrumentation or its data has not been accessed via the API the service may delete the instrumentation and its data
|
|
||||||
}
|
|
||||||
|
|
||||||
// DescribeAnalytics retrieves the "schema" for instrumentations that can be created.
|
|
||||||
// See API docs: http://apidocs.joyent.com/cloudapi/#DescribeAnalytics
|
|
||||||
func (c *Client) DescribeAnalytics() (*Analytics, error) {
|
|
||||||
var resp Analytics
|
|
||||||
req := request{
|
|
||||||
method: client.GET,
|
|
||||||
url: apiAnalytics,
|
|
||||||
resp: &resp,
|
|
||||||
}
|
|
||||||
if _, err := c.sendRequest(req); err != nil {
|
|
||||||
return nil, errors.Newf(err, "failed to get analytics")
|
|
||||||
}
|
|
||||||
return &resp, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ListInstrumentations retrieves all currently created instrumentations.
|
|
||||||
// See API docs: http://apidocs.joyent.com/cloudapi/#ListInstrumentations
|
|
||||||
func (c *Client) ListInstrumentations() ([]Instrumentation, error) {
|
|
||||||
var resp []Instrumentation
|
|
||||||
req := request{
|
|
||||||
method: client.GET,
|
|
||||||
url: makeURL(apiAnalytics, apiInstrumentations),
|
|
||||||
resp: &resp,
|
|
||||||
}
|
|
||||||
if _, err := c.sendRequest(req); err != nil {
|
|
||||||
return nil, errors.Newf(err, "failed to get instrumentations")
|
|
||||||
}
|
|
||||||
return resp, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetInstrumentation retrieves the configuration for the specified instrumentation.
|
|
||||||
// See API docs: http://apidocs.joyent.com/cloudapi/#GetInstrumentation
|
|
||||||
func (c *Client) GetInstrumentation(instrumentationID string) (*Instrumentation, error) {
|
|
||||||
var resp Instrumentation
|
|
||||||
req := request{
|
|
||||||
method: client.GET,
|
|
||||||
url: makeURL(apiAnalytics, apiInstrumentations, instrumentationID),
|
|
||||||
resp: &resp,
|
|
||||||
}
|
|
||||||
if _, err := c.sendRequest(req); err != nil {
|
|
||||||
return nil, errors.Newf(err, "failed to get instrumentation with id %s", instrumentationID)
|
|
||||||
}
|
|
||||||
return &resp, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetInstrumentationValue retrieves the data associated to an instrumentation
|
|
||||||
// for a point in time.
|
|
||||||
// See API docs: http://apidocs.joyent.com/cloudapi/#GetInstrumentationValue
|
|
||||||
func (c *Client) GetInstrumentationValue(instrumentationID string) (*InstrumentationValue, error) {
|
|
||||||
var resp InstrumentationValue
|
|
||||||
req := request{
|
|
||||||
method: client.GET,
|
|
||||||
url: makeURL(apiAnalytics, apiInstrumentations, instrumentationID, apiInstrumentationsValue, apiInstrumentationsRaw),
|
|
||||||
resp: &resp,
|
|
||||||
}
|
|
||||||
if _, err := c.sendRequest(req); err != nil {
|
|
||||||
return nil, errors.Newf(err, "failed to get value for instrumentation with id %s", instrumentationID)
|
|
||||||
}
|
|
||||||
return &resp, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetInstrumentationHeatmap retrieves the specified instrumentation's heatmap.
|
|
||||||
// See API docs: http://apidocs.joyent.com/cloudapi/#GetInstrumentationHeatmap
|
|
||||||
func (c *Client) GetInstrumentationHeatmap(instrumentationID string) (*Heatmap, error) {
|
|
||||||
var resp Heatmap
|
|
||||||
req := request{
|
|
||||||
method: client.GET,
|
|
||||||
url: makeURL(apiAnalytics, apiInstrumentations, instrumentationID, apiInstrumentationsValue, apiInstrumentationsHeatmap, apiInstrumentationsImage),
|
|
||||||
resp: &resp,
|
|
||||||
}
|
|
||||||
if _, err := c.sendRequest(req); err != nil {
|
|
||||||
return nil, errors.Newf(err, "failed to get heatmap image for instrumentation with id %s", instrumentationID)
|
|
||||||
}
|
|
||||||
return &resp, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetInstrumentationHeatmapDetails allows you to retrieve the bucket details
|
|
||||||
// for a heatmap.
|
|
||||||
// See API docs: http://apidocs.joyent.com/cloudapi/#GetInstrumentationHeatmapDetails
|
|
||||||
func (c *Client) GetInstrumentationHeatmapDetails(instrumentationID string) (*Heatmap, error) {
|
|
||||||
var resp Heatmap
|
|
||||||
req := request{
|
|
||||||
method: client.GET,
|
|
||||||
url: makeURL(apiAnalytics, apiInstrumentations, instrumentationID, apiInstrumentationsValue, apiInstrumentationsHeatmap, apiInstrumentationsDetails),
|
|
||||||
resp: &resp,
|
|
||||||
}
|
|
||||||
if _, err := c.sendRequest(req); err != nil {
|
|
||||||
return nil, errors.Newf(err, "failed to get heatmap details for instrumentation with id %s", instrumentationID)
|
|
||||||
}
|
|
||||||
return &resp, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// CreateInstrumentation Creates an instrumentation. You can clone an existing
|
|
||||||
// instrumentation by passing in the parameter clone, which should be a numeric id
|
|
||||||
// of an existing instrumentation.
|
|
||||||
// See API docs: http://apidocs.joyent.com/cloudapi/#CreateInstrumentation
|
|
||||||
func (c *Client) CreateInstrumentation(opts CreateInstrumentationOpts) (*Instrumentation, error) {
|
|
||||||
var resp Instrumentation
|
|
||||||
req := request{
|
|
||||||
method: client.POST,
|
|
||||||
url: makeURL(apiAnalytics, apiInstrumentations),
|
|
||||||
reqValue: opts,
|
|
||||||
resp: &resp,
|
|
||||||
expectedStatus: http.StatusCreated,
|
|
||||||
}
|
|
||||||
if _, err := c.sendRequest(req); err != nil {
|
|
||||||
return nil, errors.Newf(err, "failed to create instrumentation")
|
|
||||||
}
|
|
||||||
return &resp, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// DeleteInstrumentation destroys an instrumentation.
|
|
||||||
// See API docs: http://apidocs.joyent.com/cloudapi/#DeleteInstrumentation
|
|
||||||
func (c *Client) DeleteInstrumentation(instrumentationID string) error {
|
|
||||||
req := request{
|
|
||||||
method: client.DELETE,
|
|
||||||
url: makeURL(apiAnalytics, apiInstrumentations, instrumentationID),
|
|
||||||
expectedStatus: http.StatusNoContent,
|
|
||||||
}
|
|
||||||
if _, err := c.sendRequest(req); err != nil {
|
|
||||||
return errors.Newf(err, "failed to delete instrumentation with id %s", instrumentationID)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
|
@ -1,90 +0,0 @@
|
||||||
package cloudapi
|
|
||||||
|
|
||||||
import (
|
|
||||||
"net/http"
|
|
||||||
|
|
||||||
"github.com/joyent/gocommon/client"
|
|
||||||
"github.com/joyent/gocommon/errors"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Key represent a public key
|
|
||||||
type Key struct {
|
|
||||||
Name string // Name for the key
|
|
||||||
Fingerprint string // Key Fingerprint
|
|
||||||
Key string // OpenSSH formatted public key
|
|
||||||
}
|
|
||||||
|
|
||||||
/*func (k Key) Equals(other Key) bool {
|
|
||||||
if k.Name == other.Name && k.Fingerprint == other.Fingerprint && k.Key == other.Key {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}*/
|
|
||||||
|
|
||||||
// CreateKeyOpts represent the option that can be specified
|
|
||||||
// when creating a new key.
|
|
||||||
type CreateKeyOpts struct {
|
|
||||||
Name string `json:"name"` // Name for the key, optional
|
|
||||||
Key string `json:"key"` // OpenSSH formatted public key
|
|
||||||
}
|
|
||||||
|
|
||||||
// ListKeys returns a list of public keys registered with a specific account.
|
|
||||||
// See API docs: http://apidocs.joyent.com/cloudapi/#ListKeys
|
|
||||||
func (c *Client) ListKeys() ([]Key, error) {
|
|
||||||
var resp []Key
|
|
||||||
req := request{
|
|
||||||
method: client.GET,
|
|
||||||
url: apiKeys,
|
|
||||||
resp: &resp,
|
|
||||||
}
|
|
||||||
if _, err := c.sendRequest(req); err != nil {
|
|
||||||
return nil, errors.Newf(err, "failed to get list of keys")
|
|
||||||
}
|
|
||||||
return resp, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetKey returns the key identified by keyName.
|
|
||||||
// See API docs: http://apidocs.joyent.com/cloudapi/#GetKey
|
|
||||||
func (c *Client) GetKey(keyName string) (*Key, error) {
|
|
||||||
var resp Key
|
|
||||||
req := request{
|
|
||||||
method: client.GET,
|
|
||||||
url: makeURL(apiKeys, keyName),
|
|
||||||
resp: &resp,
|
|
||||||
}
|
|
||||||
if _, err := c.sendRequest(req); err != nil {
|
|
||||||
return nil, errors.Newf(err, "failed to get key with name: %s", keyName)
|
|
||||||
}
|
|
||||||
return &resp, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// CreateKey creates a new key with the specified options.
|
|
||||||
// See API docs: http://apidocs.joyent.com/cloudapi/#CreateKey
|
|
||||||
func (c *Client) CreateKey(opts CreateKeyOpts) (*Key, error) {
|
|
||||||
var resp Key
|
|
||||||
req := request{
|
|
||||||
method: client.POST,
|
|
||||||
url: apiKeys,
|
|
||||||
reqValue: opts,
|
|
||||||
resp: &resp,
|
|
||||||
expectedStatus: http.StatusCreated,
|
|
||||||
}
|
|
||||||
if _, err := c.sendRequest(req); err != nil {
|
|
||||||
return nil, errors.Newf(err, "failed to create key with name: %s", opts.Name)
|
|
||||||
}
|
|
||||||
return &resp, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// DeleteKey deletes the key identified by keyName.
|
|
||||||
// See API docs: http://apidocs.joyent.com/cloudapi/#DeleteKey
|
|
||||||
func (c *Client) DeleteKey(keyName string) error {
|
|
||||||
req := request{
|
|
||||||
method: client.DELETE,
|
|
||||||
url: makeURL(apiKeys, keyName),
|
|
||||||
expectedStatus: http.StatusNoContent,
|
|
||||||
}
|
|
||||||
if _, err := c.sendRequest(req); err != nil {
|
|
||||||
return errors.Newf(err, "failed to delete key with name: %s", keyName)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
|
@ -1,52 +0,0 @@
|
||||||
package cloudapi
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"net/http"
|
|
||||||
|
|
||||||
"github.com/joyent/gocommon/client"
|
|
||||||
"github.com/joyent/gocommon/errors"
|
|
||||||
)
|
|
||||||
|
|
||||||
// ListMachineFirewallRules lists all the firewall rules for the specified machine.
|
|
||||||
// See API docs: http://apidocs.joyent.com/cloudapi/#ListMachineFirewallRules
|
|
||||||
func (c *Client) ListMachineFirewallRules(machineID string) ([]FirewallRule, error) {
|
|
||||||
var resp []FirewallRule
|
|
||||||
req := request{
|
|
||||||
method: client.GET,
|
|
||||||
url: makeURL(apiMachines, machineID, apiFirewallRules),
|
|
||||||
resp: &resp,
|
|
||||||
}
|
|
||||||
if _, err := c.sendRequest(req); err != nil {
|
|
||||||
return nil, errors.Newf(err, "failed to get list of firewall rules for machine with id %s", machineID)
|
|
||||||
}
|
|
||||||
return resp, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// EnableFirewallMachine enables the firewall for the specified machine.
|
|
||||||
// See API docs: http://apidocs.joyent.com/cloudapi/#EnableMachineFirewall
|
|
||||||
func (c *Client) EnableFirewallMachine(machineID string) error {
|
|
||||||
req := request{
|
|
||||||
method: client.POST,
|
|
||||||
url: fmt.Sprintf("%s/%s?action=%s", apiMachines, machineID, actionEnableFw),
|
|
||||||
expectedStatus: http.StatusAccepted,
|
|
||||||
}
|
|
||||||
if _, err := c.sendRequest(req); err != nil {
|
|
||||||
return errors.Newf(err, "failed to enable firewall on machine with id: %s", machineID)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// DisableFirewallMachine disables the firewall for the specified machine.
|
|
||||||
// See API docs: http://apidocs.joyent.com/cloudapi/#DisableMachineFirewall
|
|
||||||
func (c *Client) DisableFirewallMachine(machineID string) error {
|
|
||||||
req := request{
|
|
||||||
method: client.POST,
|
|
||||||
url: fmt.Sprintf("%s/%s?action=%s", apiMachines, machineID, actionDisableFw),
|
|
||||||
expectedStatus: http.StatusAccepted,
|
|
||||||
}
|
|
||||||
if _, err := c.sendRequest(req); err != nil {
|
|
||||||
return errors.Newf(err, "failed to disable firewall on machine with id: %s", machineID)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
|
@ -1,70 +0,0 @@
|
||||||
package cloudapi
|
|
||||||
|
|
||||||
import (
|
|
||||||
"net/http"
|
|
||||||
|
|
||||||
"github.com/joyent/gocommon/client"
|
|
||||||
"github.com/joyent/gocommon/errors"
|
|
||||||
)
|
|
||||||
|
|
||||||
// UpdateMachineMetadata updates the metadata for a given machine.
|
|
||||||
// Any metadata keys passed in here are created if they do not exist, and
|
|
||||||
// overwritten if they do.
|
|
||||||
// See API docs: http://apidocs.joyent.com/cloudapi/#UpdateMachineMetadata
|
|
||||||
func (c *Client) UpdateMachineMetadata(machineID string, metadata map[string]string) (map[string]interface{}, error) {
|
|
||||||
var resp map[string]interface{}
|
|
||||||
req := request{
|
|
||||||
method: client.POST,
|
|
||||||
url: makeURL(apiMachines, machineID, apiMetadata),
|
|
||||||
reqValue: metadata,
|
|
||||||
resp: &resp,
|
|
||||||
}
|
|
||||||
if _, err := c.sendRequest(req); err != nil {
|
|
||||||
return nil, errors.Newf(err, "failed to update metadata for machine with id %s", machineID)
|
|
||||||
}
|
|
||||||
return resp, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetMachineMetadata returns the complete set of metadata associated with the
|
|
||||||
// specified machine.
|
|
||||||
// See API docs: http://apidocs.joyent.com/cloudapi/#GetMachineMetadata
|
|
||||||
func (c *Client) GetMachineMetadata(machineID string) (map[string]interface{}, error) {
|
|
||||||
var resp map[string]interface{}
|
|
||||||
req := request{
|
|
||||||
method: client.GET,
|
|
||||||
url: makeURL(apiMachines, machineID, apiMetadata),
|
|
||||||
resp: &resp,
|
|
||||||
}
|
|
||||||
if _, err := c.sendRequest(req); err != nil {
|
|
||||||
return nil, errors.Newf(err, "failed to get list of metadata for machine with id %s", machineID)
|
|
||||||
}
|
|
||||||
return resp, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// DeleteMachineMetadata deletes a single metadata key from the specified machine.
|
|
||||||
// See API docs: http://apidocs.joyent.com/cloudapi/#DeleteMachineMetadata
|
|
||||||
func (c *Client) DeleteMachineMetadata(machineID, metadataKey string) error {
|
|
||||||
req := request{
|
|
||||||
method: client.DELETE,
|
|
||||||
url: makeURL(apiMachines, machineID, apiMetadata, metadataKey),
|
|
||||||
expectedStatus: http.StatusNoContent,
|
|
||||||
}
|
|
||||||
if _, err := c.sendRequest(req); err != nil {
|
|
||||||
return errors.Newf(err, "failed to delete metadata with key %s for machine with id %s", metadataKey, machineID)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// DeleteAllMachineMetadata deletes all metadata keys from the specified machine.
|
|
||||||
// See API docs: http://apidocs.joyent.com/cloudapi/#DeleteAllMachineMetadata
|
|
||||||
func (c *Client) DeleteAllMachineMetadata(machineID string) error {
|
|
||||||
req := request{
|
|
||||||
method: client.DELETE,
|
|
||||||
url: makeURL(apiMachines, machineID, apiMetadata),
|
|
||||||
expectedStatus: http.StatusNoContent,
|
|
||||||
}
|
|
||||||
if _, err := c.sendRequest(req); err != nil {
|
|
||||||
return errors.Newf(err, "failed to delete metadata for machine with id %s", machineID)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
|
@ -1,92 +0,0 @@
|
||||||
package cloudapi
|
|
||||||
|
|
||||||
import (
|
|
||||||
"net/http"
|
|
||||||
|
|
||||||
"github.com/joyent/gocommon/client"
|
|
||||||
"github.com/joyent/gocommon/errors"
|
|
||||||
)
|
|
||||||
|
|
||||||
type NICState string
|
|
||||||
|
|
||||||
var (
|
|
||||||
NICStateProvisioning NICState = "provisioning"
|
|
||||||
NICStateRunning NICState = "running"
|
|
||||||
NICStateStopped NICState = "stopped"
|
|
||||||
)
|
|
||||||
|
|
||||||
type NIC struct {
|
|
||||||
IP string `json:"ip"` // NIC's IPv4 Address
|
|
||||||
MAC string `json:"mac"` // NIC's MAC address
|
|
||||||
Primary bool `json:"primary"` // Whether this is the machine's primary NIC
|
|
||||||
Netmask string `json:"netmask"` // IPv4 netmask
|
|
||||||
Gateway string `json:"gateway"` // IPv4 gateway
|
|
||||||
State NICState `json:"state"` // Describes the state of the NIC (e.g. provisioning, running, or stopped)
|
|
||||||
}
|
|
||||||
|
|
||||||
type addNICOptions struct {
|
|
||||||
Network string `json:"network"` // UUID of network this NIC should attach to
|
|
||||||
}
|
|
||||||
|
|
||||||
// ListNICs lists all the NICs on a machine belonging to a given account
|
|
||||||
// See API docs: https://apidocs.joyent.com/cloudapi/#ListNics
|
|
||||||
func (c *Client) ListNICs(machineID string) ([]NIC, error) {
|
|
||||||
resp := make([]NIC, 0)
|
|
||||||
req := request{
|
|
||||||
method: client.GET,
|
|
||||||
url: makeURL(apiMachines, machineID, apiNICs),
|
|
||||||
resp: &resp,
|
|
||||||
}
|
|
||||||
if _, err := c.sendRequest(req); err != nil {
|
|
||||||
return nil, errors.Newf(err, "failed to list NICs")
|
|
||||||
}
|
|
||||||
return resp, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetNIC gets a specific NIC on a machine belonging to a given account
|
|
||||||
// See API docs: https://apidocs.joyent.com/cloudapi/#GetNic
|
|
||||||
func (c *Client) GetNIC(machineID, MAC string) (*NIC, error) {
|
|
||||||
resp := new(NIC)
|
|
||||||
req := request{
|
|
||||||
method: client.GET,
|
|
||||||
url: makeURL(apiMachines, machineID, apiNICs, MAC),
|
|
||||||
resp: resp,
|
|
||||||
}
|
|
||||||
if _, err := c.sendRequest(req); err != nil {
|
|
||||||
return nil, errors.Newf(err, "failed to get NIC with MAC: %s", MAC)
|
|
||||||
}
|
|
||||||
return resp, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// AddNIC creates a new NIC on a machine belonging to a given account.
|
|
||||||
// *WARNING*: this causes the machine to reboot while adding the NIC.
|
|
||||||
// See API docs: https://apidocs.joyent.com/cloudapi/#AddNic
|
|
||||||
func (c *Client) AddNIC(machineID, networkID string) (*NIC, error) {
|
|
||||||
resp := new(NIC)
|
|
||||||
req := request{
|
|
||||||
method: client.POST,
|
|
||||||
url: makeURL(apiMachines, machineID, apiNICs),
|
|
||||||
reqValue: addNICOptions{networkID},
|
|
||||||
resp: resp,
|
|
||||||
expectedStatus: http.StatusCreated,
|
|
||||||
}
|
|
||||||
if _, err := c.sendRequest(req); err != nil {
|
|
||||||
return nil, errors.Newf(err, "failed to add NIC to machine %s on network: %s", machineID, networkID)
|
|
||||||
}
|
|
||||||
return resp, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// RemoveNIC removes a NIC on a machine belonging to a given account.
|
|
||||||
// *WARNING*: this causes the machine to reboot while removing the NIC.
|
|
||||||
// See API docs: https://apidocs.joyent.com/cloudapi/#RemoveNic
|
|
||||||
func (c *Client) RemoveNIC(machineID, MAC string) error {
|
|
||||||
req := request{
|
|
||||||
method: client.DELETE,
|
|
||||||
url: makeURL(apiMachines, machineID, apiNICs, MAC),
|
|
||||||
expectedStatus: http.StatusNoContent,
|
|
||||||
}
|
|
||||||
if _, err := c.sendRequest(req); err != nil {
|
|
||||||
return errors.Newf(err, "failed to remove NIC: %s", MAC)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
|
@ -1,96 +0,0 @@
|
||||||
package cloudapi
|
|
||||||
|
|
||||||
import (
|
|
||||||
"net/http"
|
|
||||||
|
|
||||||
"github.com/joyent/gocommon/client"
|
|
||||||
"github.com/joyent/gocommon/errors"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Snapshot represent a point in time state of a machine.
|
|
||||||
type Snapshot struct {
|
|
||||||
Name string // Snapshot name
|
|
||||||
State string // Snapshot state
|
|
||||||
}
|
|
||||||
|
|
||||||
// SnapshotOpts represent the option that can be specified
|
|
||||||
// when creating a new machine snapshot.
|
|
||||||
type SnapshotOpts struct {
|
|
||||||
Name string `json:"name"` // Snapshot name
|
|
||||||
}
|
|
||||||
|
|
||||||
// CreateMachineSnapshot creates a new snapshot for the machine with the options specified.
|
|
||||||
// See API docs: http://apidocs.joyent.com/cloudapi/#CreateMachineSnapshot
|
|
||||||
func (c *Client) CreateMachineSnapshot(machineID string, opts SnapshotOpts) (*Snapshot, error) {
|
|
||||||
var resp Snapshot
|
|
||||||
req := request{
|
|
||||||
method: client.POST,
|
|
||||||
url: makeURL(apiMachines, machineID, apiSnapshots),
|
|
||||||
reqValue: opts,
|
|
||||||
resp: &resp,
|
|
||||||
expectedStatus: http.StatusCreated,
|
|
||||||
}
|
|
||||||
if _, err := c.sendRequest(req); err != nil {
|
|
||||||
return nil, errors.Newf(err, "failed to create snapshot %s from machine with id %s", opts.Name, machineID)
|
|
||||||
}
|
|
||||||
return &resp, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// StartMachineFromSnapshot starts the machine from the specified snapshot.
|
|
||||||
// Machine must be in 'stopped' state.
|
|
||||||
// See API docs: http://apidocs.joyent.com/cloudapi/#StartMachineFromSnapshot
|
|
||||||
func (c *Client) StartMachineFromSnapshot(machineID, snapshotName string) error {
|
|
||||||
req := request{
|
|
||||||
method: client.POST,
|
|
||||||
url: makeURL(apiMachines, machineID, apiSnapshots, snapshotName),
|
|
||||||
expectedStatus: http.StatusAccepted,
|
|
||||||
}
|
|
||||||
if _, err := c.sendRequest(req); err != nil {
|
|
||||||
return errors.Newf(err, "failed to start machine with id %s from snapshot %s", machineID, snapshotName)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ListMachineSnapshots lists all snapshots for the specified machine.
|
|
||||||
// See API docs: http://apidocs.joyent.com/cloudapi/#ListMachineSnapshots
|
|
||||||
func (c *Client) ListMachineSnapshots(machineID string) ([]Snapshot, error) {
|
|
||||||
var resp []Snapshot
|
|
||||||
req := request{
|
|
||||||
method: client.GET,
|
|
||||||
url: makeURL(apiMachines, machineID, apiSnapshots),
|
|
||||||
resp: &resp,
|
|
||||||
}
|
|
||||||
if _, err := c.sendRequest(req); err != nil {
|
|
||||||
return nil, errors.Newf(err, "failed to get list of snapshots for machine with id %s", machineID)
|
|
||||||
}
|
|
||||||
return resp, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetMachineSnapshot returns the state of the specified snapshot.
|
|
||||||
// See API docs: http://apidocs.joyent.com/cloudapi/#GetMachineSnapshot
|
|
||||||
func (c *Client) GetMachineSnapshot(machineID, snapshotName string) (*Snapshot, error) {
|
|
||||||
var resp Snapshot
|
|
||||||
req := request{
|
|
||||||
method: client.GET,
|
|
||||||
url: makeURL(apiMachines, machineID, apiSnapshots, snapshotName),
|
|
||||||
resp: &resp,
|
|
||||||
}
|
|
||||||
if _, err := c.sendRequest(req); err != nil {
|
|
||||||
return nil, errors.Newf(err, "failed to get snapshot %s for machine with id %s", snapshotName, machineID)
|
|
||||||
}
|
|
||||||
return &resp, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// DeleteMachineSnapshot deletes the specified snapshot.
|
|
||||||
// See API docs: http://apidocs.joyent.com/cloudapi/#DeleteMachineSnapshot
|
|
||||||
func (c *Client) DeleteMachineSnapshot(machineID, snapshotName string) error {
|
|
||||||
req := request{
|
|
||||||
method: client.DELETE,
|
|
||||||
url: makeURL(apiMachines, machineID, apiSnapshots, snapshotName),
|
|
||||||
expectedStatus: http.StatusNoContent,
|
|
||||||
}
|
|
||||||
if _, err := c.sendRequest(req); err != nil {
|
|
||||||
return errors.Newf(err, "failed to delete snapshot %s for machine with id %s", snapshotName, machineID)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
|
@ -1,103 +0,0 @@
|
||||||
package cloudapi
|
|
||||||
|
|
||||||
import (
|
|
||||||
"net/http"
|
|
||||||
|
|
||||||
"github.com/joyent/gocommon/client"
|
|
||||||
"github.com/joyent/gocommon/errors"
|
|
||||||
)
|
|
||||||
|
|
||||||
// AddMachineTags adds additional tags to the specified machine.
|
|
||||||
// This API lets you append new tags, not overwrite existing tags.
|
|
||||||
// See API docs: http://apidocs.joyent.com/cloudapi/#AddMachineTags
|
|
||||||
func (c *Client) AddMachineTags(machineID string, tags map[string]string) (map[string]string, error) {
|
|
||||||
var resp map[string]string
|
|
||||||
req := request{
|
|
||||||
method: client.POST,
|
|
||||||
url: makeURL(apiMachines, machineID, apiTags),
|
|
||||||
reqValue: tags,
|
|
||||||
resp: &resp,
|
|
||||||
}
|
|
||||||
if _, err := c.sendRequest(req); err != nil {
|
|
||||||
return nil, errors.Newf(err, "failed to add tags for machine with id %s", machineID)
|
|
||||||
}
|
|
||||||
return resp, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ReplaceMachineTags replaces existing tags for the specified machine.
|
|
||||||
// This API lets you overwrite existing tags, not append to existing tags.
|
|
||||||
// See API docs: http://apidocs.joyent.com/cloudapi/#ReplaceMachineTags
|
|
||||||
func (c *Client) ReplaceMachineTags(machineID string, tags map[string]string) (map[string]string, error) {
|
|
||||||
var resp map[string]string
|
|
||||||
req := request{
|
|
||||||
method: client.PUT,
|
|
||||||
url: makeURL(apiMachines, machineID, apiTags),
|
|
||||||
reqValue: tags,
|
|
||||||
resp: &resp,
|
|
||||||
}
|
|
||||||
if _, err := c.sendRequest(req); err != nil {
|
|
||||||
return nil, errors.Newf(err, "failed to replace tags for machine with id %s", machineID)
|
|
||||||
}
|
|
||||||
return resp, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ListMachineTags returns the complete set of tags associated with the specified machine.
|
|
||||||
// See API docs: http://apidocs.joyent.com/cloudapi/#ListMachineTags
|
|
||||||
func (c *Client) ListMachineTags(machineID string) (map[string]string, error) {
|
|
||||||
var resp map[string]string
|
|
||||||
req := request{
|
|
||||||
method: client.GET,
|
|
||||||
url: makeURL(apiMachines, machineID, apiTags),
|
|
||||||
resp: &resp,
|
|
||||||
}
|
|
||||||
if _, err := c.sendRequest(req); err != nil {
|
|
||||||
return nil, errors.Newf(err, "failed to get list of tags for machine with id %s", machineID)
|
|
||||||
}
|
|
||||||
return resp, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetMachineTag returns the value for a single tag on the specified machine.
|
|
||||||
// See API docs: http://apidocs.joyent.com/cloudapi/#GetMachineTag
|
|
||||||
func (c *Client) GetMachineTag(machineID, tagKey string) (string, error) {
|
|
||||||
var resp []byte
|
|
||||||
requestHeaders := make(http.Header)
|
|
||||||
requestHeaders.Set("Accept", "text/plain")
|
|
||||||
req := request{
|
|
||||||
method: client.GET,
|
|
||||||
url: makeURL(apiMachines, machineID, apiTags, tagKey),
|
|
||||||
resp: &resp,
|
|
||||||
reqHeader: requestHeaders,
|
|
||||||
}
|
|
||||||
if _, err := c.sendRequest(req); err != nil {
|
|
||||||
return "", errors.Newf(err, "failed to get tag %s for machine with id %s", tagKey, machineID)
|
|
||||||
}
|
|
||||||
return string(resp), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// DeleteMachineTag deletes a single tag from the specified machine.
|
|
||||||
// See API docs: http://apidocs.joyent.com/cloudapi/#DeleteMachineTag
|
|
||||||
func (c *Client) DeleteMachineTag(machineID, tagKey string) error {
|
|
||||||
req := request{
|
|
||||||
method: client.DELETE,
|
|
||||||
url: makeURL(apiMachines, machineID, apiTags, tagKey),
|
|
||||||
expectedStatus: http.StatusNoContent,
|
|
||||||
}
|
|
||||||
if _, err := c.sendRequest(req); err != nil {
|
|
||||||
return errors.Newf(err, "failed to delete tag with key %s for machine with id %s", tagKey, machineID)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// DeleteMachineTags deletes all tags from the specified machine.
|
|
||||||
// See API docs: http://apidocs.joyent.com/cloudapi/#DeleteMachineTags
|
|
||||||
func (c *Client) DeleteMachineTags(machineID string) error {
|
|
||||||
req := request{
|
|
||||||
method: client.DELETE,
|
|
||||||
url: makeURL(apiMachines, machineID, apiTags),
|
|
||||||
expectedStatus: http.StatusNoContent,
|
|
||||||
}
|
|
||||||
if _, err := c.sendRequest(req); err != nil {
|
|
||||||
return errors.Newf(err, "failed to delete tags for machine with id %s", machineID)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
|
@ -1,306 +0,0 @@
|
||||||
package cloudapi
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
"net/http"
|
|
||||||
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/joyent/gocommon/client"
|
|
||||||
"github.com/joyent/gocommon/errors"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Machine represent a provisioned virtual machines
|
|
||||||
type Machine struct {
|
|
||||||
Id string // Unique identifier for the image
|
|
||||||
Name string // Machine friendly name
|
|
||||||
Type string // Machine type, one of 'smartmachine' or 'virtualmachine'
|
|
||||||
State string // Current state of the machine
|
|
||||||
Dataset string // The dataset URN the machine was provisioned with. For new images/datasets this value will be the dataset id, i.e, same value than the image attribute
|
|
||||||
Memory int // The amount of memory the machine has (in Mb)
|
|
||||||
Disk int // The amount of disk the machine has (in Gb)
|
|
||||||
IPs []string // The IP addresses the machine has
|
|
||||||
Metadata map[string]string // Map of the machine metadata, e.g. authorized-keys
|
|
||||||
Tags map[string]string // Map of the machine tags
|
|
||||||
Created string // When the machine was created
|
|
||||||
Updated string // When the machine was updated
|
|
||||||
Package string // The name of the package used to create the machine
|
|
||||||
Image string // The image id the machine was provisioned with
|
|
||||||
PrimaryIP string // The primary (public) IP address for the machine
|
|
||||||
Networks []string // The network IDs for the machine
|
|
||||||
FirewallEnabled bool // whether or not the firewall is enabled
|
|
||||||
}
|
|
||||||
|
|
||||||
// Equals compares two machines. Ignores state and timestamps.
|
|
||||||
func (m Machine) Equals(other Machine) bool {
|
|
||||||
if m.Id == other.Id && m.Name == other.Name && m.Type == other.Type && m.Dataset == other.Dataset &&
|
|
||||||
m.Memory == other.Memory && m.Disk == other.Disk && m.Package == other.Package && m.Image == other.Image &&
|
|
||||||
m.compareIPs(other) && m.compareMetadata(other) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// Helper method to compare two machines IPs
|
|
||||||
func (m Machine) compareIPs(other Machine) bool {
|
|
||||||
if len(m.IPs) != len(other.IPs) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
for i, v := range m.IPs {
|
|
||||||
if v != other.IPs[i] {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// Helper method to compare two machines metadata
|
|
||||||
func (m Machine) compareMetadata(other Machine) bool {
|
|
||||||
if len(m.Metadata) != len(other.Metadata) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
for k, v := range m.Metadata {
|
|
||||||
if v != other.Metadata[k] {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// CreateMachineOpts represent the option that can be specified
|
|
||||||
// when creating a new machine.
|
|
||||||
type CreateMachineOpts struct {
|
|
||||||
Name string `json:"name"` // Machine friendly name, default is a randomly generated name
|
|
||||||
Package string `json:"package"` // Name of the package to use on provisioning
|
|
||||||
Image string `json:"image"` // The image UUID
|
|
||||||
Networks []string `json:"networks"` // Desired networks IDs
|
|
||||||
Metadata map[string]string `json:"-"` // An arbitrary set of metadata key/value pairs can be set at provision time
|
|
||||||
Tags map[string]string `json:"-"` // An arbitrary set of tags can be set at provision time
|
|
||||||
FirewallEnabled bool `json:"firewall_enabled"` // Completely enable or disable firewall for this machine (new in API version 7.0)
|
|
||||||
}
|
|
||||||
|
|
||||||
// AuditAction represents an action/event accomplished by a machine.
|
|
||||||
type AuditAction struct {
|
|
||||||
Action string // Action name
|
|
||||||
Parameters map[string]interface{} // Original set of parameters sent when the action was requested
|
|
||||||
Time string // When the action finished
|
|
||||||
Success string // Either 'yes' or 'no', depending on the action successfulness
|
|
||||||
Caller Caller // Account requesting the action
|
|
||||||
}
|
|
||||||
|
|
||||||
// Caller represents an account requesting an action.
|
|
||||||
type Caller struct {
|
|
||||||
Type string // Authentication type for the action request. One of 'basic', 'operator', 'signature' or 'token'
|
|
||||||
User string // When the authentication type is 'basic', this member will be present and include user login
|
|
||||||
IP string // The IP addresses this from which the action was requested. Not present if type is 'operator'
|
|
||||||
KeyId string // When authentication type is either 'signature' or 'token', SSH key identifier
|
|
||||||
}
|
|
||||||
|
|
||||||
// appendJSON marshals the given attribute value and appends it as an encoded value to the given json data.
|
|
||||||
// The newly encode (attr, value) is inserted just before the closing "}" in the json data.
|
|
||||||
func appendJSON(data []byte, attr string, value interface{}) ([]byte, error) {
|
|
||||||
newData, err := json.Marshal(&value)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
strData := string(data)
|
|
||||||
result := fmt.Sprintf(`%s, "%s":%s}`, strData[:len(strData)-1], attr, string(newData))
|
|
||||||
return []byte(result), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type jsonOpts CreateMachineOpts
|
|
||||||
|
|
||||||
// MarshalJSON turns the given CreateMachineOpts into JSON
|
|
||||||
func (opts CreateMachineOpts) MarshalJSON() ([]byte, error) {
|
|
||||||
jo := jsonOpts(opts)
|
|
||||||
data, err := json.Marshal(&jo)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
for k, v := range opts.Tags {
|
|
||||||
if !strings.HasPrefix(k, "tag.") {
|
|
||||||
k = "tag." + k
|
|
||||||
}
|
|
||||||
data, err = appendJSON(data, k, v)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for k, v := range opts.Metadata {
|
|
||||||
if !strings.HasPrefix(k, "metadata.") {
|
|
||||||
k = "metadata." + k
|
|
||||||
}
|
|
||||||
data, err = appendJSON(data, k, v)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return data, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ListMachines lists all machines on record for an account.
|
|
||||||
// You can paginate this API by passing in offset, and limit
|
|
||||||
// See API docs: http://apidocs.joyent.com/cloudapi/#ListMachines
|
|
||||||
func (c *Client) ListMachines(filter *Filter) ([]Machine, error) {
|
|
||||||
var resp []Machine
|
|
||||||
req := request{
|
|
||||||
method: client.GET,
|
|
||||||
url: apiMachines,
|
|
||||||
filter: filter,
|
|
||||||
resp: &resp,
|
|
||||||
}
|
|
||||||
if _, err := c.sendRequest(req); err != nil {
|
|
||||||
return nil, errors.Newf(err, "failed to get list of machines")
|
|
||||||
}
|
|
||||||
return resp, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// CountMachines returns the number of machines on record for an account.
|
|
||||||
// See API docs: http://apidocs.joyent.com/cloudapi/#ListMachines
|
|
||||||
func (c *Client) CountMachines() (int, error) {
|
|
||||||
var resp int
|
|
||||||
req := request{
|
|
||||||
method: client.HEAD,
|
|
||||||
url: apiMachines,
|
|
||||||
resp: &resp,
|
|
||||||
}
|
|
||||||
if _, err := c.sendRequest(req); err != nil {
|
|
||||||
return -1, errors.Newf(err, "failed to get count of machines")
|
|
||||||
}
|
|
||||||
return resp, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetMachine returns the machine specified by machineId.
|
|
||||||
// See API docs: http://apidocs.joyent.com/cloudapi/#GetMachine
|
|
||||||
func (c *Client) GetMachine(machineID string) (*Machine, error) {
|
|
||||||
var resp Machine
|
|
||||||
req := request{
|
|
||||||
method: client.GET,
|
|
||||||
url: makeURL(apiMachines, machineID),
|
|
||||||
resp: &resp,
|
|
||||||
}
|
|
||||||
if _, err := c.sendRequest(req); err != nil {
|
|
||||||
return nil, errors.Newf(err, "failed to get machine with id: %s", machineID)
|
|
||||||
}
|
|
||||||
return &resp, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// CreateMachine creates a new machine with the options specified.
|
|
||||||
// See API docs: http://apidocs.joyent.com/cloudapi/#CreateMachine
|
|
||||||
func (c *Client) CreateMachine(opts CreateMachineOpts) (*Machine, error) {
|
|
||||||
var resp Machine
|
|
||||||
req := request{
|
|
||||||
method: client.POST,
|
|
||||||
url: apiMachines,
|
|
||||||
reqValue: opts,
|
|
||||||
resp: &resp,
|
|
||||||
expectedStatus: http.StatusCreated,
|
|
||||||
}
|
|
||||||
if _, err := c.sendRequest(req); err != nil {
|
|
||||||
return nil, errors.Newf(err, "failed to create machine with name: %s", opts.Name)
|
|
||||||
}
|
|
||||||
return &resp, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// StopMachine stops a running machine.
|
|
||||||
// See API docs: http://apidocs.joyent.com/cloudapi/#StopMachine
|
|
||||||
func (c *Client) StopMachine(machineID string) error {
|
|
||||||
req := request{
|
|
||||||
method: client.POST,
|
|
||||||
url: fmt.Sprintf("%s/%s?action=%s", apiMachines, machineID, actionStop),
|
|
||||||
expectedStatus: http.StatusAccepted,
|
|
||||||
}
|
|
||||||
if _, err := c.sendRequest(req); err != nil {
|
|
||||||
return errors.Newf(err, "failed to stop machine with id: %s", machineID)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// StartMachine starts a stopped machine.
|
|
||||||
// See API docs: http://apidocs.joyent.com/cloudapi/#StartMachine
|
|
||||||
func (c *Client) StartMachine(machineID string) error {
|
|
||||||
req := request{
|
|
||||||
method: client.POST,
|
|
||||||
url: fmt.Sprintf("%s/%s?action=%s", apiMachines, machineID, actionStart),
|
|
||||||
expectedStatus: http.StatusAccepted,
|
|
||||||
}
|
|
||||||
if _, err := c.sendRequest(req); err != nil {
|
|
||||||
return errors.Newf(err, "failed to start machine with id: %s", machineID)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// RebootMachine reboots (stop followed by a start) a machine.
|
|
||||||
// See API docs: http://apidocs.joyent.com/cloudapi/#RebootMachine
|
|
||||||
func (c *Client) RebootMachine(machineID string) error {
|
|
||||||
req := request{
|
|
||||||
method: client.POST,
|
|
||||||
url: fmt.Sprintf("%s/%s?action=%s", apiMachines, machineID, actionReboot),
|
|
||||||
expectedStatus: http.StatusAccepted,
|
|
||||||
}
|
|
||||||
if _, err := c.sendRequest(req); err != nil {
|
|
||||||
return errors.Newf(err, "failed to reboot machine with id: %s", machineID)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ResizeMachine allows you to resize a SmartMachine. Virtual machines can also
|
|
||||||
// be resized, but only resizing virtual machines to a higher capacity package
|
|
||||||
// is supported.
|
|
||||||
// See API docs: http://apidocs.joyent.com/cloudapi/#ResizeMachine
|
|
||||||
func (c *Client) ResizeMachine(machineID, packageName string) error {
|
|
||||||
req := request{
|
|
||||||
method: client.POST,
|
|
||||||
url: fmt.Sprintf("%s/%s?action=%s&package=%s", apiMachines, machineID, actionResize, packageName),
|
|
||||||
expectedStatus: http.StatusAccepted,
|
|
||||||
}
|
|
||||||
if _, err := c.sendRequest(req); err != nil {
|
|
||||||
return errors.Newf(err, "failed to resize machine with id: %s", machineID)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// RenameMachine renames an existing machine.
|
|
||||||
// See API docs: http://apidocs.joyent.com/cloudapi/#RenameMachine
|
|
||||||
func (c *Client) RenameMachine(machineID, machineName string) error {
|
|
||||||
req := request{
|
|
||||||
method: client.POST,
|
|
||||||
url: fmt.Sprintf("%s/%s?action=%s&name=%s", apiMachines, machineID, actionRename, machineName),
|
|
||||||
expectedStatus: http.StatusAccepted,
|
|
||||||
}
|
|
||||||
if _, err := c.sendRequest(req); err != nil {
|
|
||||||
return errors.Newf(err, "failed to rename machine with id: %s", machineID)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// DeleteMachine allows you to completely destroy a machine. Machine must be in the 'stopped' state.
|
|
||||||
// See API docs: http://apidocs.joyent.com/cloudapi/#DeleteMachine
|
|
||||||
func (c *Client) DeleteMachine(machineID string) error {
|
|
||||||
req := request{
|
|
||||||
method: client.DELETE,
|
|
||||||
url: makeURL(apiMachines, machineID),
|
|
||||||
expectedStatus: http.StatusNoContent,
|
|
||||||
}
|
|
||||||
if _, err := c.sendRequest(req); err != nil {
|
|
||||||
return errors.Newf(err, "failed to delete machine with id %s", machineID)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// MachineAudit provides a list of machine's accomplished actions, (sorted from
|
|
||||||
// latest to older one).
|
|
||||||
// See API docs: http://apidocs.joyent.com/cloudapi/#MachineAudit
|
|
||||||
func (c *Client) MachineAudit(machineID string) ([]AuditAction, error) {
|
|
||||||
var resp []AuditAction
|
|
||||||
req := request{
|
|
||||||
method: client.GET,
|
|
||||||
url: makeURL(apiMachines, machineID, apiAudit),
|
|
||||||
resp: &resp,
|
|
||||||
}
|
|
||||||
if _, err := c.sendRequest(req); err != nil {
|
|
||||||
return nil, errors.Newf(err, "failed to get actions for machine with id %s", machineID)
|
|
||||||
}
|
|
||||||
return resp, nil
|
|
||||||
}
|
|
|
@ -1,44 +0,0 @@
|
||||||
package cloudapi
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/joyent/gocommon/client"
|
|
||||||
"github.com/joyent/gocommon/errors"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Network represents a network available to a given account
|
|
||||||
type Network struct {
|
|
||||||
Id string // Unique identifier for the network
|
|
||||||
Name string // Network name
|
|
||||||
Public bool // Whether this a public or private (rfc1918) network
|
|
||||||
Description string // Optional description for this network, when name is not enough
|
|
||||||
}
|
|
||||||
|
|
||||||
// ListNetworks lists all the networks which can be used by the given account.
|
|
||||||
// See API docs: http://apidocs.joyent.com/cloudapi/#ListNetworks
|
|
||||||
func (c *Client) ListNetworks() ([]Network, error) {
|
|
||||||
var resp []Network
|
|
||||||
req := request{
|
|
||||||
method: client.GET,
|
|
||||||
url: apiNetworks,
|
|
||||||
resp: &resp,
|
|
||||||
}
|
|
||||||
if _, err := c.sendRequest(req); err != nil {
|
|
||||||
return nil, errors.Newf(err, "failed to get list of networks")
|
|
||||||
}
|
|
||||||
return resp, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetNetwork retrieves an individual network record.
|
|
||||||
// See API docs: http://apidocs.joyent.com/cloudapi/#GetNetwork
|
|
||||||
func (c *Client) GetNetwork(networkID string) (*Network, error) {
|
|
||||||
var resp Network
|
|
||||||
req := request{
|
|
||||||
method: client.GET,
|
|
||||||
url: makeURL(apiNetworks, networkID),
|
|
||||||
resp: &resp,
|
|
||||||
}
|
|
||||||
if _, err := c.sendRequest(req); err != nil {
|
|
||||||
return nil, errors.Newf(err, "failed to get network with id %s", networkID)
|
|
||||||
}
|
|
||||||
return &resp, nil
|
|
||||||
}
|
|
|
@ -1,53 +0,0 @@
|
||||||
package cloudapi
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/joyent/gocommon/client"
|
|
||||||
"github.com/joyent/gocommon/errors"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Package represents a named collections of resources that are used to describe the 'sizes'
|
|
||||||
// of either a smart machine or a virtual machine.
|
|
||||||
type Package struct {
|
|
||||||
Name string // Name for the package
|
|
||||||
Memory int // Memory available (in Mb)
|
|
||||||
Disk int // Disk space available (in Gb)
|
|
||||||
Swap int // Swap memory available (in Mb)
|
|
||||||
VCPUs int // Number of VCPUs for the package
|
|
||||||
Default bool // Indicates whether this is the default package in the datacenter
|
|
||||||
Id string // Unique identifier for the package
|
|
||||||
Version string // Version for the package
|
|
||||||
Group string // Group this package belongs to
|
|
||||||
Description string // Human friendly description for the package
|
|
||||||
}
|
|
||||||
|
|
||||||
// ListPackages provides a list of packages available in the datacenter.
|
|
||||||
// See API docs: http://apidocs.joyent.com/cloudapi/#ListPackages
|
|
||||||
func (c *Client) ListPackages(filter *Filter) ([]Package, error) {
|
|
||||||
var resp []Package
|
|
||||||
req := request{
|
|
||||||
method: client.GET,
|
|
||||||
url: apiPackages,
|
|
||||||
filter: filter,
|
|
||||||
resp: &resp,
|
|
||||||
}
|
|
||||||
if _, err := c.sendRequest(req); err != nil {
|
|
||||||
return nil, errors.Newf(err, "failed to get list of packages")
|
|
||||||
}
|
|
||||||
return resp, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetPackage returns the package specified by packageName. NOTE: packageName can
|
|
||||||
// specify either the package name or package ID.
|
|
||||||
// See API docs: http://apidocs.joyent.com/cloudapi/#GetPackage
|
|
||||||
func (c *Client) GetPackage(packageName string) (*Package, error) {
|
|
||||||
var resp Package
|
|
||||||
req := request{
|
|
||||||
method: client.GET,
|
|
||||||
url: makeURL(apiPackages, packageName),
|
|
||||||
resp: &resp,
|
|
||||||
}
|
|
||||||
if _, err := c.sendRequest(req); err != nil {
|
|
||||||
return nil, errors.Newf(err, "failed to get package with name: %s", packageName)
|
|
||||||
}
|
|
||||||
return &resp, nil
|
|
||||||
}
|
|
|
@ -1,674 +0,0 @@
|
||||||
GNU GENERAL PUBLIC LICENSE
|
|
||||||
Version 3, 29 June 2007
|
|
||||||
|
|
||||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
|
||||||
Everyone is permitted to copy and distribute verbatim copies
|
|
||||||
of this license document, but changing it is not allowed.
|
|
||||||
|
|
||||||
Preamble
|
|
||||||
|
|
||||||
The GNU General Public License is a free, copyleft license for
|
|
||||||
software and other kinds of works.
|
|
||||||
|
|
||||||
The licenses for most software and other practical works are designed
|
|
||||||
to take away your freedom to share and change the works. By contrast,
|
|
||||||
the GNU General Public License is intended to guarantee your freedom to
|
|
||||||
share and change all versions of a program--to make sure it remains free
|
|
||||||
software for all its users. We, the Free Software Foundation, use the
|
|
||||||
GNU General Public License for most of our software; it applies also to
|
|
||||||
any other work released this way by its authors. You can apply it to
|
|
||||||
your programs, too.
|
|
||||||
|
|
||||||
When we speak of free software, we are referring to freedom, not
|
|
||||||
price. Our General Public Licenses are designed to make sure that you
|
|
||||||
have the freedom to distribute copies of free software (and charge for
|
|
||||||
them if you wish), that you receive source code or can get it if you
|
|
||||||
want it, that you can change the software or use pieces of it in new
|
|
||||||
free programs, and that you know you can do these things.
|
|
||||||
|
|
||||||
To protect your rights, we need to prevent others from denying you
|
|
||||||
these rights or asking you to surrender the rights. Therefore, you have
|
|
||||||
certain responsibilities if you distribute copies of the software, or if
|
|
||||||
you modify it: responsibilities to respect the freedom of others.
|
|
||||||
|
|
||||||
For example, if you distribute copies of such a program, whether
|
|
||||||
gratis or for a fee, you must pass on to the recipients the same
|
|
||||||
freedoms that you received. You must make sure that they, too, receive
|
|
||||||
or can get the source code. And you must show them these terms so they
|
|
||||||
know their rights.
|
|
||||||
|
|
||||||
Developers that use the GNU GPL protect your rights with two steps:
|
|
||||||
(1) assert copyright on the software, and (2) offer you this License
|
|
||||||
giving you legal permission to copy, distribute and/or modify it.
|
|
||||||
|
|
||||||
For the developers' and authors' protection, the GPL clearly explains
|
|
||||||
that there is no warranty for this free software. For both users' and
|
|
||||||
authors' sake, the GPL requires that modified versions be marked as
|
|
||||||
changed, so that their problems will not be attributed erroneously to
|
|
||||||
authors of previous versions.
|
|
||||||
|
|
||||||
Some devices are designed to deny users access to install or run
|
|
||||||
modified versions of the software inside them, although the manufacturer
|
|
||||||
can do so. This is fundamentally incompatible with the aim of
|
|
||||||
protecting users' freedom to change the software. The systematic
|
|
||||||
pattern of such abuse occurs in the area of products for individuals to
|
|
||||||
use, which is precisely where it is most unacceptable. Therefore, we
|
|
||||||
have designed this version of the GPL to prohibit the practice for those
|
|
||||||
products. If such problems arise substantially in other domains, we
|
|
||||||
stand ready to extend this provision to those domains in future versions
|
|
||||||
of the GPL, as needed to protect the freedom of users.
|
|
||||||
|
|
||||||
Finally, every program is threatened constantly by software patents.
|
|
||||||
States should not allow patents to restrict development and use of
|
|
||||||
software on general-purpose computers, but in those that do, we wish to
|
|
||||||
avoid the special danger that patents applied to a free program could
|
|
||||||
make it effectively proprietary. To prevent this, the GPL assures that
|
|
||||||
patents cannot be used to render the program non-free.
|
|
||||||
|
|
||||||
The precise terms and conditions for copying, distribution and
|
|
||||||
modification follow.
|
|
||||||
|
|
||||||
TERMS AND CONDITIONS
|
|
||||||
|
|
||||||
0. Definitions.
|
|
||||||
|
|
||||||
"This License" refers to version 3 of the GNU General Public License.
|
|
||||||
|
|
||||||
"Copyright" also means copyright-like laws that apply to other kinds of
|
|
||||||
works, such as semiconductor masks.
|
|
||||||
|
|
||||||
"The Program" refers to any copyrightable work licensed under this
|
|
||||||
License. Each licensee is addressed as "you". "Licensees" and
|
|
||||||
"recipients" may be individuals or organizations.
|
|
||||||
|
|
||||||
To "modify" a work means to copy from or adapt all or part of the work
|
|
||||||
in a fashion requiring copyright permission, other than the making of an
|
|
||||||
exact copy. The resulting work is called a "modified version" of the
|
|
||||||
earlier work or a work "based on" the earlier work.
|
|
||||||
|
|
||||||
A "covered work" means either the unmodified Program or a work based
|
|
||||||
on the Program.
|
|
||||||
|
|
||||||
To "propagate" a work means to do anything with it that, without
|
|
||||||
permission, would make you directly or secondarily liable for
|
|
||||||
infringement under applicable copyright law, except executing it on a
|
|
||||||
computer or modifying a private copy. Propagation includes copying,
|
|
||||||
distribution (with or without modification), making available to the
|
|
||||||
public, and in some countries other activities as well.
|
|
||||||
|
|
||||||
To "convey" a work means any kind of propagation that enables other
|
|
||||||
parties to make or receive copies. Mere interaction with a user through
|
|
||||||
a computer network, with no transfer of a copy, is not conveying.
|
|
||||||
|
|
||||||
An interactive user interface displays "Appropriate Legal Notices"
|
|
||||||
to the extent that it includes a convenient and prominently visible
|
|
||||||
feature that (1) displays an appropriate copyright notice, and (2)
|
|
||||||
tells the user that there is no warranty for the work (except to the
|
|
||||||
extent that warranties are provided), that licensees may convey the
|
|
||||||
work under this License, and how to view a copy of this License. If
|
|
||||||
the interface presents a list of user commands or options, such as a
|
|
||||||
menu, a prominent item in the list meets this criterion.
|
|
||||||
|
|
||||||
1. Source Code.
|
|
||||||
|
|
||||||
The "source code" for a work means the preferred form of the work
|
|
||||||
for making modifications to it. "Object code" means any non-source
|
|
||||||
form of a work.
|
|
||||||
|
|
||||||
A "Standard Interface" means an interface that either is an official
|
|
||||||
standard defined by a recognized standards body, or, in the case of
|
|
||||||
interfaces specified for a particular programming language, one that
|
|
||||||
is widely used among developers working in that language.
|
|
||||||
|
|
||||||
The "System Libraries" of an executable work include anything, other
|
|
||||||
than the work as a whole, that (a) is included in the normal form of
|
|
||||||
packaging a Major Component, but which is not part of that Major
|
|
||||||
Component, and (b) serves only to enable use of the work with that
|
|
||||||
Major Component, or to implement a Standard Interface for which an
|
|
||||||
implementation is available to the public in source code form. A
|
|
||||||
"Major Component", in this context, means a major essential component
|
|
||||||
(kernel, window system, and so on) of the specific operating system
|
|
||||||
(if any) on which the executable work runs, or a compiler used to
|
|
||||||
produce the work, or an object code interpreter used to run it.
|
|
||||||
|
|
||||||
The "Corresponding Source" for a work in object code form means all
|
|
||||||
the source code needed to generate, install, and (for an executable
|
|
||||||
work) run the object code and to modify the work, including scripts to
|
|
||||||
control those activities. However, it does not include the work's
|
|
||||||
System Libraries, or general-purpose tools or generally available free
|
|
||||||
programs which are used unmodified in performing those activities but
|
|
||||||
which are not part of the work. For example, Corresponding Source
|
|
||||||
includes interface definition files associated with source files for
|
|
||||||
the work, and the source code for shared libraries and dynamically
|
|
||||||
linked subprograms that the work is specifically designed to require,
|
|
||||||
such as by intimate data communication or control flow between those
|
|
||||||
subprograms and other parts of the work.
|
|
||||||
|
|
||||||
The Corresponding Source need not include anything that users
|
|
||||||
can regenerate automatically from other parts of the Corresponding
|
|
||||||
Source.
|
|
||||||
|
|
||||||
The Corresponding Source for a work in source code form is that
|
|
||||||
same work.
|
|
||||||
|
|
||||||
2. Basic Permissions.
|
|
||||||
|
|
||||||
All rights granted under this License are granted for the term of
|
|
||||||
copyright on the Program, and are irrevocable provided the stated
|
|
||||||
conditions are met. This License explicitly affirms your unlimited
|
|
||||||
permission to run the unmodified Program. The output from running a
|
|
||||||
covered work is covered by this License only if the output, given its
|
|
||||||
content, constitutes a covered work. This License acknowledges your
|
|
||||||
rights of fair use or other equivalent, as provided by copyright law.
|
|
||||||
|
|
||||||
You may make, run and propagate covered works that you do not
|
|
||||||
convey, without conditions so long as your license otherwise remains
|
|
||||||
in force. You may convey covered works to others for the sole purpose
|
|
||||||
of having them make modifications exclusively for you, or provide you
|
|
||||||
with facilities for running those works, provided that you comply with
|
|
||||||
the terms of this License in conveying all material for which you do
|
|
||||||
not control copyright. Those thus making or running the covered works
|
|
||||||
for you must do so exclusively on your behalf, under your direction
|
|
||||||
and control, on terms that prohibit them from making any copies of
|
|
||||||
your copyrighted material outside their relationship with you.
|
|
||||||
|
|
||||||
Conveying under any other circumstances is permitted solely under
|
|
||||||
the conditions stated below. Sublicensing is not allowed; section 10
|
|
||||||
makes it unnecessary.
|
|
||||||
|
|
||||||
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
|
||||||
|
|
||||||
No covered work shall be deemed part of an effective technological
|
|
||||||
measure under any applicable law fulfilling obligations under article
|
|
||||||
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
|
||||||
similar laws prohibiting or restricting circumvention of such
|
|
||||||
measures.
|
|
||||||
|
|
||||||
When you convey a covered work, you waive any legal power to forbid
|
|
||||||
circumvention of technological measures to the extent such circumvention
|
|
||||||
is effected by exercising rights under this License with respect to
|
|
||||||
the covered work, and you disclaim any intention to limit operation or
|
|
||||||
modification of the work as a means of enforcing, against the work's
|
|
||||||
users, your or third parties' legal rights to forbid circumvention of
|
|
||||||
technological measures.
|
|
||||||
|
|
||||||
4. Conveying Verbatim Copies.
|
|
||||||
|
|
||||||
You may convey verbatim copies of the Program's source code as you
|
|
||||||
receive it, in any medium, provided that you conspicuously and
|
|
||||||
appropriately publish on each copy an appropriate copyright notice;
|
|
||||||
keep intact all notices stating that this License and any
|
|
||||||
non-permissive terms added in accord with section 7 apply to the code;
|
|
||||||
keep intact all notices of the absence of any warranty; and give all
|
|
||||||
recipients a copy of this License along with the Program.
|
|
||||||
|
|
||||||
You may charge any price or no price for each copy that you convey,
|
|
||||||
and you may offer support or warranty protection for a fee.
|
|
||||||
|
|
||||||
5. Conveying Modified Source Versions.
|
|
||||||
|
|
||||||
You may convey a work based on the Program, or the modifications to
|
|
||||||
produce it from the Program, in the form of source code under the
|
|
||||||
terms of section 4, provided that you also meet all of these conditions:
|
|
||||||
|
|
||||||
a) The work must carry prominent notices stating that you modified
|
|
||||||
it, and giving a relevant date.
|
|
||||||
|
|
||||||
b) The work must carry prominent notices stating that it is
|
|
||||||
released under this License and any conditions added under section
|
|
||||||
7. This requirement modifies the requirement in section 4 to
|
|
||||||
"keep intact all notices".
|
|
||||||
|
|
||||||
c) You must license the entire work, as a whole, under this
|
|
||||||
License to anyone who comes into possession of a copy. This
|
|
||||||
License will therefore apply, along with any applicable section 7
|
|
||||||
additional terms, to the whole of the work, and all its parts,
|
|
||||||
regardless of how they are packaged. This License gives no
|
|
||||||
permission to license the work in any other way, but it does not
|
|
||||||
invalidate such permission if you have separately received it.
|
|
||||||
|
|
||||||
d) If the work has interactive user interfaces, each must display
|
|
||||||
Appropriate Legal Notices; however, if the Program has interactive
|
|
||||||
interfaces that do not display Appropriate Legal Notices, your
|
|
||||||
work need not make them do so.
|
|
||||||
|
|
||||||
A compilation of a covered work with other separate and independent
|
|
||||||
works, which are not by their nature extensions of the covered work,
|
|
||||||
and which are not combined with it such as to form a larger program,
|
|
||||||
in or on a volume of a storage or distribution medium, is called an
|
|
||||||
"aggregate" if the compilation and its resulting copyright are not
|
|
||||||
used to limit the access or legal rights of the compilation's users
|
|
||||||
beyond what the individual works permit. Inclusion of a covered work
|
|
||||||
in an aggregate does not cause this License to apply to the other
|
|
||||||
parts of the aggregate.
|
|
||||||
|
|
||||||
6. Conveying Non-Source Forms.
|
|
||||||
|
|
||||||
You may convey a covered work in object code form under the terms
|
|
||||||
of sections 4 and 5, provided that you also convey the
|
|
||||||
machine-readable Corresponding Source under the terms of this License,
|
|
||||||
in one of these ways:
|
|
||||||
|
|
||||||
a) Convey the object code in, or embodied in, a physical product
|
|
||||||
(including a physical distribution medium), accompanied by the
|
|
||||||
Corresponding Source fixed on a durable physical medium
|
|
||||||
customarily used for software interchange.
|
|
||||||
|
|
||||||
b) Convey the object code in, or embodied in, a physical product
|
|
||||||
(including a physical distribution medium), accompanied by a
|
|
||||||
written offer, valid for at least three years and valid for as
|
|
||||||
long as you offer spare parts or customer support for that product
|
|
||||||
model, to give anyone who possesses the object code either (1) a
|
|
||||||
copy of the Corresponding Source for all the software in the
|
|
||||||
product that is covered by this License, on a durable physical
|
|
||||||
medium customarily used for software interchange, for a price no
|
|
||||||
more than your reasonable cost of physically performing this
|
|
||||||
conveying of source, or (2) access to copy the
|
|
||||||
Corresponding Source from a network server at no charge.
|
|
||||||
|
|
||||||
c) Convey individual copies of the object code with a copy of the
|
|
||||||
written offer to provide the Corresponding Source. This
|
|
||||||
alternative is allowed only occasionally and noncommercially, and
|
|
||||||
only if you received the object code with such an offer, in accord
|
|
||||||
with subsection 6b.
|
|
||||||
|
|
||||||
d) Convey the object code by offering access from a designated
|
|
||||||
place (gratis or for a charge), and offer equivalent access to the
|
|
||||||
Corresponding Source in the same way through the same place at no
|
|
||||||
further charge. You need not require recipients to copy the
|
|
||||||
Corresponding Source along with the object code. If the place to
|
|
||||||
copy the object code is a network server, the Corresponding Source
|
|
||||||
may be on a different server (operated by you or a third party)
|
|
||||||
that supports equivalent copying facilities, provided you maintain
|
|
||||||
clear directions next to the object code saying where to find the
|
|
||||||
Corresponding Source. Regardless of what server hosts the
|
|
||||||
Corresponding Source, you remain obligated to ensure that it is
|
|
||||||
available for as long as needed to satisfy these requirements.
|
|
||||||
|
|
||||||
e) Convey the object code using peer-to-peer transmission, provided
|
|
||||||
you inform other peers where the object code and Corresponding
|
|
||||||
Source of the work are being offered to the general public at no
|
|
||||||
charge under subsection 6d.
|
|
||||||
|
|
||||||
A separable portion of the object code, whose source code is excluded
|
|
||||||
from the Corresponding Source as a System Library, need not be
|
|
||||||
included in conveying the object code work.
|
|
||||||
|
|
||||||
A "User Product" is either (1) a "consumer product", which means any
|
|
||||||
tangible personal property which is normally used for personal, family,
|
|
||||||
or household purposes, or (2) anything designed or sold for incorporation
|
|
||||||
into a dwelling. In determining whether a product is a consumer product,
|
|
||||||
doubtful cases shall be resolved in favor of coverage. For a particular
|
|
||||||
product received by a particular user, "normally used" refers to a
|
|
||||||
typical or common use of that class of product, regardless of the status
|
|
||||||
of the particular user or of the way in which the particular user
|
|
||||||
actually uses, or expects or is expected to use, the product. A product
|
|
||||||
is a consumer product regardless of whether the product has substantial
|
|
||||||
commercial, industrial or non-consumer uses, unless such uses represent
|
|
||||||
the only significant mode of use of the product.
|
|
||||||
|
|
||||||
"Installation Information" for a User Product means any methods,
|
|
||||||
procedures, authorization keys, or other information required to install
|
|
||||||
and execute modified versions of a covered work in that User Product from
|
|
||||||
a modified version of its Corresponding Source. The information must
|
|
||||||
suffice to ensure that the continued functioning of the modified object
|
|
||||||
code is in no case prevented or interfered with solely because
|
|
||||||
modification has been made.
|
|
||||||
|
|
||||||
If you convey an object code work under this section in, or with, or
|
|
||||||
specifically for use in, a User Product, and the conveying occurs as
|
|
||||||
part of a transaction in which the right of possession and use of the
|
|
||||||
User Product is transferred to the recipient in perpetuity or for a
|
|
||||||
fixed term (regardless of how the transaction is characterized), the
|
|
||||||
Corresponding Source conveyed under this section must be accompanied
|
|
||||||
by the Installation Information. But this requirement does not apply
|
|
||||||
if neither you nor any third party retains the ability to install
|
|
||||||
modified object code on the User Product (for example, the work has
|
|
||||||
been installed in ROM).
|
|
||||||
|
|
||||||
The requirement to provide Installation Information does not include a
|
|
||||||
requirement to continue to provide support service, warranty, or updates
|
|
||||||
for a work that has been modified or installed by the recipient, or for
|
|
||||||
the User Product in which it has been modified or installed. Access to a
|
|
||||||
network may be denied when the modification itself materially and
|
|
||||||
adversely affects the operation of the network or violates the rules and
|
|
||||||
protocols for communication across the network.
|
|
||||||
|
|
||||||
Corresponding Source conveyed, and Installation Information provided,
|
|
||||||
in accord with this section must be in a format that is publicly
|
|
||||||
documented (and with an implementation available to the public in
|
|
||||||
source code form), and must require no special password or key for
|
|
||||||
unpacking, reading or copying.
|
|
||||||
|
|
||||||
7. Additional Terms.
|
|
||||||
|
|
||||||
"Additional permissions" are terms that supplement the terms of this
|
|
||||||
License by making exceptions from one or more of its conditions.
|
|
||||||
Additional permissions that are applicable to the entire Program shall
|
|
||||||
be treated as though they were included in this License, to the extent
|
|
||||||
that they are valid under applicable law. If additional permissions
|
|
||||||
apply only to part of the Program, that part may be used separately
|
|
||||||
under those permissions, but the entire Program remains governed by
|
|
||||||
this License without regard to the additional permissions.
|
|
||||||
|
|
||||||
When you convey a copy of a covered work, you may at your option
|
|
||||||
remove any additional permissions from that copy, or from any part of
|
|
||||||
it. (Additional permissions may be written to require their own
|
|
||||||
removal in certain cases when you modify the work.) You may place
|
|
||||||
additional permissions on material, added by you to a covered work,
|
|
||||||
for which you have or can give appropriate copyright permission.
|
|
||||||
|
|
||||||
Notwithstanding any other provision of this License, for material you
|
|
||||||
add to a covered work, you may (if authorized by the copyright holders of
|
|
||||||
that material) supplement the terms of this License with terms:
|
|
||||||
|
|
||||||
a) Disclaiming warranty or limiting liability differently from the
|
|
||||||
terms of sections 15 and 16 of this License; or
|
|
||||||
|
|
||||||
b) Requiring preservation of specified reasonable legal notices or
|
|
||||||
author attributions in that material or in the Appropriate Legal
|
|
||||||
Notices displayed by works containing it; or
|
|
||||||
|
|
||||||
c) Prohibiting misrepresentation of the origin of that material, or
|
|
||||||
requiring that modified versions of such material be marked in
|
|
||||||
reasonable ways as different from the original version; or
|
|
||||||
|
|
||||||
d) Limiting the use for publicity purposes of names of licensors or
|
|
||||||
authors of the material; or
|
|
||||||
|
|
||||||
e) Declining to grant rights under trademark law for use of some
|
|
||||||
trade names, trademarks, or service marks; or
|
|
||||||
|
|
||||||
f) Requiring indemnification of licensors and authors of that
|
|
||||||
material by anyone who conveys the material (or modified versions of
|
|
||||||
it) with contractual assumptions of liability to the recipient, for
|
|
||||||
any liability that these contractual assumptions directly impose on
|
|
||||||
those licensors and authors.
|
|
||||||
|
|
||||||
All other non-permissive additional terms are considered "further
|
|
||||||
restrictions" within the meaning of section 10. If the Program as you
|
|
||||||
received it, or any part of it, contains a notice stating that it is
|
|
||||||
governed by this License along with a term that is a further
|
|
||||||
restriction, you may remove that term. If a license document contains
|
|
||||||
a further restriction but permits relicensing or conveying under this
|
|
||||||
License, you may add to a covered work material governed by the terms
|
|
||||||
of that license document, provided that the further restriction does
|
|
||||||
not survive such relicensing or conveying.
|
|
||||||
|
|
||||||
If you add terms to a covered work in accord with this section, you
|
|
||||||
must place, in the relevant source files, a statement of the
|
|
||||||
additional terms that apply to those files, or a notice indicating
|
|
||||||
where to find the applicable terms.
|
|
||||||
|
|
||||||
Additional terms, permissive or non-permissive, may be stated in the
|
|
||||||
form of a separately written license, or stated as exceptions;
|
|
||||||
the above requirements apply either way.
|
|
||||||
|
|
||||||
8. Termination.
|
|
||||||
|
|
||||||
You may not propagate or modify a covered work except as expressly
|
|
||||||
provided under this License. Any attempt otherwise to propagate or
|
|
||||||
modify it is void, and will automatically terminate your rights under
|
|
||||||
this License (including any patent licenses granted under the third
|
|
||||||
paragraph of section 11).
|
|
||||||
|
|
||||||
However, if you cease all violation of this License, then your
|
|
||||||
license from a particular copyright holder is reinstated (a)
|
|
||||||
provisionally, unless and until the copyright holder explicitly and
|
|
||||||
finally terminates your license, and (b) permanently, if the copyright
|
|
||||||
holder fails to notify you of the violation by some reasonable means
|
|
||||||
prior to 60 days after the cessation.
|
|
||||||
|
|
||||||
Moreover, your license from a particular copyright holder is
|
|
||||||
reinstated permanently if the copyright holder notifies you of the
|
|
||||||
violation by some reasonable means, this is the first time you have
|
|
||||||
received notice of violation of this License (for any work) from that
|
|
||||||
copyright holder, and you cure the violation prior to 30 days after
|
|
||||||
your receipt of the notice.
|
|
||||||
|
|
||||||
Termination of your rights under this section does not terminate the
|
|
||||||
licenses of parties who have received copies or rights from you under
|
|
||||||
this License. If your rights have been terminated and not permanently
|
|
||||||
reinstated, you do not qualify to receive new licenses for the same
|
|
||||||
material under section 10.
|
|
||||||
|
|
||||||
9. Acceptance Not Required for Having Copies.
|
|
||||||
|
|
||||||
You are not required to accept this License in order to receive or
|
|
||||||
run a copy of the Program. Ancillary propagation of a covered work
|
|
||||||
occurring solely as a consequence of using peer-to-peer transmission
|
|
||||||
to receive a copy likewise does not require acceptance. However,
|
|
||||||
nothing other than this License grants you permission to propagate or
|
|
||||||
modify any covered work. These actions infringe copyright if you do
|
|
||||||
not accept this License. Therefore, by modifying or propagating a
|
|
||||||
covered work, you indicate your acceptance of this License to do so.
|
|
||||||
|
|
||||||
10. Automatic Licensing of Downstream Recipients.
|
|
||||||
|
|
||||||
Each time you convey a covered work, the recipient automatically
|
|
||||||
receives a license from the original licensors, to run, modify and
|
|
||||||
propagate that work, subject to this License. You are not responsible
|
|
||||||
for enforcing compliance by third parties with this License.
|
|
||||||
|
|
||||||
An "entity transaction" is a transaction transferring control of an
|
|
||||||
organization, or substantially all assets of one, or subdividing an
|
|
||||||
organization, or merging organizations. If propagation of a covered
|
|
||||||
work results from an entity transaction, each party to that
|
|
||||||
transaction who receives a copy of the work also receives whatever
|
|
||||||
licenses to the work the party's predecessor in interest had or could
|
|
||||||
give under the previous paragraph, plus a right to possession of the
|
|
||||||
Corresponding Source of the work from the predecessor in interest, if
|
|
||||||
the predecessor has it or can get it with reasonable efforts.
|
|
||||||
|
|
||||||
You may not impose any further restrictions on the exercise of the
|
|
||||||
rights granted or affirmed under this License. For example, you may
|
|
||||||
not impose a license fee, royalty, or other charge for exercise of
|
|
||||||
rights granted under this License, and you may not initiate litigation
|
|
||||||
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
|
||||||
any patent claim is infringed by making, using, selling, offering for
|
|
||||||
sale, or importing the Program or any portion of it.
|
|
||||||
|
|
||||||
11. Patents.
|
|
||||||
|
|
||||||
A "contributor" is a copyright holder who authorizes use under this
|
|
||||||
License of the Program or a work on which the Program is based. The
|
|
||||||
work thus licensed is called the contributor's "contributor version".
|
|
||||||
|
|
||||||
A contributor's "essential patent claims" are all patent claims
|
|
||||||
owned or controlled by the contributor, whether already acquired or
|
|
||||||
hereafter acquired, that would be infringed by some manner, permitted
|
|
||||||
by this License, of making, using, or selling its contributor version,
|
|
||||||
but do not include claims that would be infringed only as a
|
|
||||||
consequence of further modification of the contributor version. For
|
|
||||||
purposes of this definition, "control" includes the right to grant
|
|
||||||
patent sublicenses in a manner consistent with the requirements of
|
|
||||||
this License.
|
|
||||||
|
|
||||||
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
|
||||||
patent license under the contributor's essential patent claims, to
|
|
||||||
make, use, sell, offer for sale, import and otherwise run, modify and
|
|
||||||
propagate the contents of its contributor version.
|
|
||||||
|
|
||||||
In the following three paragraphs, a "patent license" is any express
|
|
||||||
agreement or commitment, however denominated, not to enforce a patent
|
|
||||||
(such as an express permission to practice a patent or covenant not to
|
|
||||||
sue for patent infringement). To "grant" such a patent license to a
|
|
||||||
party means to make such an agreement or commitment not to enforce a
|
|
||||||
patent against the party.
|
|
||||||
|
|
||||||
If you convey a covered work, knowingly relying on a patent license,
|
|
||||||
and the Corresponding Source of the work is not available for anyone
|
|
||||||
to copy, free of charge and under the terms of this License, through a
|
|
||||||
publicly available network server or other readily accessible means,
|
|
||||||
then you must either (1) cause the Corresponding Source to be so
|
|
||||||
available, or (2) arrange to deprive yourself of the benefit of the
|
|
||||||
patent license for this particular work, or (3) arrange, in a manner
|
|
||||||
consistent with the requirements of this License, to extend the patent
|
|
||||||
license to downstream recipients. "Knowingly relying" means you have
|
|
||||||
actual knowledge that, but for the patent license, your conveying the
|
|
||||||
covered work in a country, or your recipient's use of the covered work
|
|
||||||
in a country, would infringe one or more identifiable patents in that
|
|
||||||
country that you have reason to believe are valid.
|
|
||||||
|
|
||||||
If, pursuant to or in connection with a single transaction or
|
|
||||||
arrangement, you convey, or propagate by procuring conveyance of, a
|
|
||||||
covered work, and grant a patent license to some of the parties
|
|
||||||
receiving the covered work authorizing them to use, propagate, modify
|
|
||||||
or convey a specific copy of the covered work, then the patent license
|
|
||||||
you grant is automatically extended to all recipients of the covered
|
|
||||||
work and works based on it.
|
|
||||||
|
|
||||||
A patent license is "discriminatory" if it does not include within
|
|
||||||
the scope of its coverage, prohibits the exercise of, or is
|
|
||||||
conditioned on the non-exercise of one or more of the rights that are
|
|
||||||
specifically granted under this License. You may not convey a covered
|
|
||||||
work if you are a party to an arrangement with a third party that is
|
|
||||||
in the business of distributing software, under which you make payment
|
|
||||||
to the third party based on the extent of your activity of conveying
|
|
||||||
the work, and under which the third party grants, to any of the
|
|
||||||
parties who would receive the covered work from you, a discriminatory
|
|
||||||
patent license (a) in connection with copies of the covered work
|
|
||||||
conveyed by you (or copies made from those copies), or (b) primarily
|
|
||||||
for and in connection with specific products or compilations that
|
|
||||||
contain the covered work, unless you entered into that arrangement,
|
|
||||||
or that patent license was granted, prior to 28 March 2007.
|
|
||||||
|
|
||||||
Nothing in this License shall be construed as excluding or limiting
|
|
||||||
any implied license or other defenses to infringement that may
|
|
||||||
otherwise be available to you under applicable patent law.
|
|
||||||
|
|
||||||
12. No Surrender of Others' Freedom.
|
|
||||||
|
|
||||||
If conditions are imposed on you (whether by court order, agreement or
|
|
||||||
otherwise) that contradict the conditions of this License, they do not
|
|
||||||
excuse you from the conditions of this License. If you cannot convey a
|
|
||||||
covered work so as to satisfy simultaneously your obligations under this
|
|
||||||
License and any other pertinent obligations, then as a consequence you may
|
|
||||||
not convey it at all. For example, if you agree to terms that obligate you
|
|
||||||
to collect a royalty for further conveying from those to whom you convey
|
|
||||||
the Program, the only way you could satisfy both those terms and this
|
|
||||||
License would be to refrain entirely from conveying the Program.
|
|
||||||
|
|
||||||
13. Use with the GNU Affero General Public License.
|
|
||||||
|
|
||||||
Notwithstanding any other provision of this License, you have
|
|
||||||
permission to link or combine any covered work with a work licensed
|
|
||||||
under version 3 of the GNU Affero General Public License into a single
|
|
||||||
combined work, and to convey the resulting work. The terms of this
|
|
||||||
License will continue to apply to the part which is the covered work,
|
|
||||||
but the special requirements of the GNU Affero General Public License,
|
|
||||||
section 13, concerning interaction through a network will apply to the
|
|
||||||
combination as such.
|
|
||||||
|
|
||||||
14. Revised Versions of this License.
|
|
||||||
|
|
||||||
The Free Software Foundation may publish revised and/or new versions of
|
|
||||||
the GNU General Public License from time to time. Such new versions will
|
|
||||||
be similar in spirit to the present version, but may differ in detail to
|
|
||||||
address new problems or concerns.
|
|
||||||
|
|
||||||
Each version is given a distinguishing version number. If the
|
|
||||||
Program specifies that a certain numbered version of the GNU General
|
|
||||||
Public License "or any later version" applies to it, you have the
|
|
||||||
option of following the terms and conditions either of that numbered
|
|
||||||
version or of any later version published by the Free Software
|
|
||||||
Foundation. If the Program does not specify a version number of the
|
|
||||||
GNU General Public License, you may choose any version ever published
|
|
||||||
by the Free Software Foundation.
|
|
||||||
|
|
||||||
If the Program specifies that a proxy can decide which future
|
|
||||||
versions of the GNU General Public License can be used, that proxy's
|
|
||||||
public statement of acceptance of a version permanently authorizes you
|
|
||||||
to choose that version for the Program.
|
|
||||||
|
|
||||||
Later license versions may give you additional or different
|
|
||||||
permissions. However, no additional obligations are imposed on any
|
|
||||||
author or copyright holder as a result of your choosing to follow a
|
|
||||||
later version.
|
|
||||||
|
|
||||||
15. Disclaimer of Warranty.
|
|
||||||
|
|
||||||
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
|
||||||
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
|
||||||
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
|
||||||
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
|
||||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
|
||||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
|
||||||
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
|
||||||
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
|
||||||
|
|
||||||
16. Limitation of Liability.
|
|
||||||
|
|
||||||
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
|
||||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
|
||||||
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
|
||||||
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
|
||||||
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
|
||||||
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
|
||||||
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
|
||||||
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
|
||||||
SUCH DAMAGES.
|
|
||||||
|
|
||||||
17. Interpretation of Sections 15 and 16.
|
|
||||||
|
|
||||||
If the disclaimer of warranty and limitation of liability provided
|
|
||||||
above cannot be given local legal effect according to their terms,
|
|
||||||
reviewing courts shall apply local law that most closely approximates
|
|
||||||
an absolute waiver of all civil liability in connection with the
|
|
||||||
Program, unless a warranty or assumption of liability accompanies a
|
|
||||||
copy of the Program in return for a fee.
|
|
||||||
|
|
||||||
END OF TERMS AND CONDITIONS
|
|
||||||
|
|
||||||
How to Apply These Terms to Your New Programs
|
|
||||||
|
|
||||||
If you develop a new program, and you want it to be of the greatest
|
|
||||||
possible use to the public, the best way to achieve this is to make it
|
|
||||||
free software which everyone can redistribute and change under these terms.
|
|
||||||
|
|
||||||
To do so, attach the following notices to the program. It is safest
|
|
||||||
to attach them to the start of each source file to most effectively
|
|
||||||
state the exclusion of warranty; and each file should have at least
|
|
||||||
the "copyright" line and a pointer to where the full notice is found.
|
|
||||||
|
|
||||||
<one line to give the program's name and a brief idea of what it does.>
|
|
||||||
Copyright (C) <year> <name of author>
|
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU General Public License as published by
|
|
||||||
the Free Software Foundation, either version 3 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
Also add information on how to contact you by electronic and paper mail.
|
|
||||||
|
|
||||||
If the program does terminal interaction, make it output a short
|
|
||||||
notice like this when it starts in an interactive mode:
|
|
||||||
|
|
||||||
<program> Copyright (C) <year> <name of author>
|
|
||||||
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
|
||||||
This is free software, and you are welcome to redistribute it
|
|
||||||
under certain conditions; type `show c' for details.
|
|
||||||
|
|
||||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
|
||||||
parts of the General Public License. Of course, your program's commands
|
|
||||||
might be different; for a GUI interface, you would use an "about box".
|
|
||||||
|
|
||||||
You should also get your employer (if you work as a programmer) or school,
|
|
||||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
|
||||||
For more information on this, and how to apply and follow the GNU GPL, see
|
|
||||||
<http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
The GNU General Public License does not permit incorporating your program
|
|
||||||
into proprietary programs. If your program is a subroutine library, you
|
|
||||||
may consider it more useful to permit linking proprietary applications with
|
|
||||||
the library. If this is what you want to do, use the GNU Lesser General
|
|
||||||
Public License instead of this License. But first, please read
|
|
||||||
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
|
|
|
@ -1,165 +0,0 @@
|
||||||
GNU LESSER GENERAL PUBLIC LICENSE
|
|
||||||
Version 3, 29 June 2007
|
|
||||||
|
|
||||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
|
||||||
Everyone is permitted to copy and distribute verbatim copies
|
|
||||||
of this license document, but changing it is not allowed.
|
|
||||||
|
|
||||||
|
|
||||||
This version of the GNU Lesser General Public License incorporates
|
|
||||||
the terms and conditions of version 3 of the GNU General Public
|
|
||||||
License, supplemented by the additional permissions listed below.
|
|
||||||
|
|
||||||
0. Additional Definitions.
|
|
||||||
|
|
||||||
As used herein, "this License" refers to version 3 of the GNU Lesser
|
|
||||||
General Public License, and the "GNU GPL" refers to version 3 of the GNU
|
|
||||||
General Public License.
|
|
||||||
|
|
||||||
"The Library" refers to a covered work governed by this License,
|
|
||||||
other than an Application or a Combined Work as defined below.
|
|
||||||
|
|
||||||
An "Application" is any work that makes use of an interface provided
|
|
||||||
by the Library, but which is not otherwise based on the Library.
|
|
||||||
Defining a subclass of a class defined by the Library is deemed a mode
|
|
||||||
of using an interface provided by the Library.
|
|
||||||
|
|
||||||
A "Combined Work" is a work produced by combining or linking an
|
|
||||||
Application with the Library. The particular version of the Library
|
|
||||||
with which the Combined Work was made is also called the "Linked
|
|
||||||
Version".
|
|
||||||
|
|
||||||
The "Minimal Corresponding Source" for a Combined Work means the
|
|
||||||
Corresponding Source for the Combined Work, excluding any source code
|
|
||||||
for portions of the Combined Work that, considered in isolation, are
|
|
||||||
based on the Application, and not on the Linked Version.
|
|
||||||
|
|
||||||
The "Corresponding Application Code" for a Combined Work means the
|
|
||||||
object code and/or source code for the Application, including any data
|
|
||||||
and utility programs needed for reproducing the Combined Work from the
|
|
||||||
Application, but excluding the System Libraries of the Combined Work.
|
|
||||||
|
|
||||||
1. Exception to Section 3 of the GNU GPL.
|
|
||||||
|
|
||||||
You may convey a covered work under sections 3 and 4 of this License
|
|
||||||
without being bound by section 3 of the GNU GPL.
|
|
||||||
|
|
||||||
2. Conveying Modified Versions.
|
|
||||||
|
|
||||||
If you modify a copy of the Library, and, in your modifications, a
|
|
||||||
facility refers to a function or data to be supplied by an Application
|
|
||||||
that uses the facility (other than as an argument passed when the
|
|
||||||
facility is invoked), then you may convey a copy of the modified
|
|
||||||
version:
|
|
||||||
|
|
||||||
a) under this License, provided that you make a good faith effort to
|
|
||||||
ensure that, in the event an Application does not supply the
|
|
||||||
function or data, the facility still operates, and performs
|
|
||||||
whatever part of its purpose remains meaningful, or
|
|
||||||
|
|
||||||
b) under the GNU GPL, with none of the additional permissions of
|
|
||||||
this License applicable to that copy.
|
|
||||||
|
|
||||||
3. Object Code Incorporating Material from Library Header Files.
|
|
||||||
|
|
||||||
The object code form of an Application may incorporate material from
|
|
||||||
a header file that is part of the Library. You may convey such object
|
|
||||||
code under terms of your choice, provided that, if the incorporated
|
|
||||||
material is not limited to numerical parameters, data structure
|
|
||||||
layouts and accessors, or small macros, inline functions and templates
|
|
||||||
(ten or fewer lines in length), you do both of the following:
|
|
||||||
|
|
||||||
a) Give prominent notice with each copy of the object code that the
|
|
||||||
Library is used in it and that the Library and its use are
|
|
||||||
covered by this License.
|
|
||||||
|
|
||||||
b) Accompany the object code with a copy of the GNU GPL and this license
|
|
||||||
document.
|
|
||||||
|
|
||||||
4. Combined Works.
|
|
||||||
|
|
||||||
You may convey a Combined Work under terms of your choice that,
|
|
||||||
taken together, effectively do not restrict modification of the
|
|
||||||
portions of the Library contained in the Combined Work and reverse
|
|
||||||
engineering for debugging such modifications, if you also do each of
|
|
||||||
the following:
|
|
||||||
|
|
||||||
a) Give prominent notice with each copy of the Combined Work that
|
|
||||||
the Library is used in it and that the Library and its use are
|
|
||||||
covered by this License.
|
|
||||||
|
|
||||||
b) Accompany the Combined Work with a copy of the GNU GPL and this license
|
|
||||||
document.
|
|
||||||
|
|
||||||
c) For a Combined Work that displays copyright notices during
|
|
||||||
execution, include the copyright notice for the Library among
|
|
||||||
these notices, as well as a reference directing the user to the
|
|
||||||
copies of the GNU GPL and this license document.
|
|
||||||
|
|
||||||
d) Do one of the following:
|
|
||||||
|
|
||||||
0) Convey the Minimal Corresponding Source under the terms of this
|
|
||||||
License, and the Corresponding Application Code in a form
|
|
||||||
suitable for, and under terms that permit, the user to
|
|
||||||
recombine or relink the Application with a modified version of
|
|
||||||
the Linked Version to produce a modified Combined Work, in the
|
|
||||||
manner specified by section 6 of the GNU GPL for conveying
|
|
||||||
Corresponding Source.
|
|
||||||
|
|
||||||
1) Use a suitable shared library mechanism for linking with the
|
|
||||||
Library. A suitable mechanism is one that (a) uses at run time
|
|
||||||
a copy of the Library already present on the user's computer
|
|
||||||
system, and (b) will operate properly with a modified version
|
|
||||||
of the Library that is interface-compatible with the Linked
|
|
||||||
Version.
|
|
||||||
|
|
||||||
e) Provide Installation Information, but only if you would otherwise
|
|
||||||
be required to provide such information under section 6 of the
|
|
||||||
GNU GPL, and only to the extent that such information is
|
|
||||||
necessary to install and execute a modified version of the
|
|
||||||
Combined Work produced by recombining or relinking the
|
|
||||||
Application with a modified version of the Linked Version. (If
|
|
||||||
you use option 4d0, the Installation Information must accompany
|
|
||||||
the Minimal Corresponding Source and Corresponding Application
|
|
||||||
Code. If you use option 4d1, you must provide the Installation
|
|
||||||
Information in the manner specified by section 6 of the GNU GPL
|
|
||||||
for conveying Corresponding Source.)
|
|
||||||
|
|
||||||
5. Combined Libraries.
|
|
||||||
|
|
||||||
You may place library facilities that are a work based on the
|
|
||||||
Library side by side in a single library together with other library
|
|
||||||
facilities that are not Applications and are not covered by this
|
|
||||||
License, and convey such a combined library under terms of your
|
|
||||||
choice, if you do both of the following:
|
|
||||||
|
|
||||||
a) Accompany the combined library with a copy of the same work based
|
|
||||||
on the Library, uncombined with any other library facilities,
|
|
||||||
conveyed under the terms of this License.
|
|
||||||
|
|
||||||
b) Give prominent notice with the combined library that part of it
|
|
||||||
is a work based on the Library, and explaining where to find the
|
|
||||||
accompanying uncombined form of the same work.
|
|
||||||
|
|
||||||
6. Revised Versions of the GNU Lesser General Public License.
|
|
||||||
|
|
||||||
The Free Software Foundation may publish revised and/or new versions
|
|
||||||
of the GNU Lesser General Public License from time to time. Such new
|
|
||||||
versions will be similar in spirit to the present version, but may
|
|
||||||
differ in detail to address new problems or concerns.
|
|
||||||
|
|
||||||
Each version is given a distinguishing version number. If the
|
|
||||||
Library as you received it specifies that a certain numbered version
|
|
||||||
of the GNU Lesser General Public License "or any later version"
|
|
||||||
applies to it, you have the option of following the terms and
|
|
||||||
conditions either of that published version or of any later version
|
|
||||||
published by the Free Software Foundation. If the Library as you
|
|
||||||
received it does not specify a version number of the GNU Lesser
|
|
||||||
General Public License, you may choose any version of the GNU Lesser
|
|
||||||
General Public License ever published by the Free Software Foundation.
|
|
||||||
|
|
||||||
If the Library as you received it specifies that a proxy can decide
|
|
||||||
whether future versions of the GNU Lesser General Public License shall
|
|
||||||
apply, that proxy's public statement of acceptance of any version is
|
|
||||||
permanent authorization for you to choose that version for the
|
|
||||||
Library.
|
|
|
@ -1,15 +0,0 @@
|
||||||
GoSign - Go HTTP signing library for the Joyent Public Cloud
|
|
||||||
|
|
||||||
Copyright (c) 2013, Joyent Inc.
|
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify it under
|
|
||||||
the terms of the GNU Lesser General Public License as published by the Free
|
|
||||||
Software Foundation, either version 3 of the License, or (at your option) any
|
|
||||||
later version.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
||||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
|
||||||
PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
|
|
||||||
|
|
||||||
See both COPYING and COPYING.LESSER for the full terms of the GNU Lesser
|
|
||||||
General Public License.
|
|
|
@ -1,135 +0,0 @@
|
||||||
//
|
|
||||||
// gosign - Go HTTP signing library for the Joyent Public Cloud and Joyent Manta
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// Copyright (c) 2013 Joyent Inc.
|
|
||||||
//
|
|
||||||
// Written by Daniele Stroppa <daniele.stroppa@joyent.com>
|
|
||||||
//
|
|
||||||
|
|
||||||
package auth
|
|
||||||
|
|
||||||
import (
|
|
||||||
"crypto"
|
|
||||||
"crypto/rand"
|
|
||||||
"crypto/rsa"
|
|
||||||
"crypto/x509"
|
|
||||||
"encoding/base64"
|
|
||||||
"encoding/pem"
|
|
||||||
"fmt"
|
|
||||||
"net/http"
|
|
||||||
"net/url"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
// Authorization Headers
|
|
||||||
SdcSignature = "Signature keyId=\"/%s/keys/%s\",algorithm=\"%s\" %s"
|
|
||||||
MantaSignature = "Signature keyId=\"/%s/keys/%s\",algorithm=\"%s\",signature=\"%s\""
|
|
||||||
)
|
|
||||||
|
|
||||||
type Endpoint struct {
|
|
||||||
URL string
|
|
||||||
}
|
|
||||||
|
|
||||||
type Auth struct {
|
|
||||||
User string
|
|
||||||
PrivateKey PrivateKey
|
|
||||||
Algorithm string
|
|
||||||
}
|
|
||||||
|
|
||||||
type Credentials struct {
|
|
||||||
UserAuthentication *Auth
|
|
||||||
SdcKeyId string
|
|
||||||
SdcEndpoint Endpoint
|
|
||||||
MantaKeyId string
|
|
||||||
MantaEndpoint Endpoint
|
|
||||||
}
|
|
||||||
|
|
||||||
type PrivateKey struct {
|
|
||||||
key *rsa.PrivateKey
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewAuth creates a new Auth.
|
|
||||||
func NewAuth(user, privateKey, algorithm string) (*Auth, error) {
|
|
||||||
block, _ := pem.Decode([]byte(privateKey))
|
|
||||||
if block == nil {
|
|
||||||
return nil, fmt.Errorf("invalid private key data: %s", privateKey)
|
|
||||||
}
|
|
||||||
rsakey, err := x509.ParsePKCS1PrivateKey(block.Bytes)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("An error occurred while parsing the key: %s", err)
|
|
||||||
}
|
|
||||||
return &Auth{user, PrivateKey{rsakey}, algorithm}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// The CreateAuthorizationHeader returns the Authorization header for the give request.
|
|
||||||
func CreateAuthorizationHeader(headers http.Header, credentials *Credentials, isMantaRequest bool) (string, error) {
|
|
||||||
if isMantaRequest {
|
|
||||||
signature, err := GetSignature(credentials.UserAuthentication, "date: "+headers.Get("Date"))
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
return fmt.Sprintf(MantaSignature, credentials.UserAuthentication.User, credentials.MantaKeyId,
|
|
||||||
credentials.UserAuthentication.Algorithm, signature), nil
|
|
||||||
}
|
|
||||||
signature, err := GetSignature(credentials.UserAuthentication, headers.Get("Date"))
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
return fmt.Sprintf(SdcSignature, credentials.UserAuthentication.User, credentials.SdcKeyId,
|
|
||||||
credentials.UserAuthentication.Algorithm, signature), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// The GetSignature method signs the specified key according to http://apidocs.joyent.com/cloudapi/#issuing-requests
|
|
||||||
// and http://apidocs.joyent.com/manta/api.html#authentication.
|
|
||||||
func GetSignature(auth *Auth, signing string) (string, error) {
|
|
||||||
hashFunc := getHashFunction(auth.Algorithm)
|
|
||||||
hash := hashFunc.New()
|
|
||||||
hash.Write([]byte(signing))
|
|
||||||
|
|
||||||
digest := hash.Sum(nil)
|
|
||||||
|
|
||||||
signed, err := rsa.SignPKCS1v15(rand.Reader, auth.PrivateKey.key, hashFunc, digest)
|
|
||||||
if err != nil {
|
|
||||||
return "", fmt.Errorf("An error occurred while signing the key: %s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return base64.StdEncoding.EncodeToString(signed), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Helper method to get the Hash function based on the algorithm
|
|
||||||
func getHashFunction(algorithm string) (hashFunc crypto.Hash) {
|
|
||||||
switch strings.ToLower(algorithm) {
|
|
||||||
case "rsa-sha1":
|
|
||||||
hashFunc = crypto.SHA1
|
|
||||||
case "rsa-sha224", "rsa-sha256":
|
|
||||||
hashFunc = crypto.SHA256
|
|
||||||
case "rsa-sha384", "rsa-sha512":
|
|
||||||
hashFunc = crypto.SHA512
|
|
||||||
default:
|
|
||||||
hashFunc = crypto.SHA256
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (cred *Credentials) Region() string {
|
|
||||||
sdcUrl := cred.SdcEndpoint.URL
|
|
||||||
|
|
||||||
if isLocalhost(sdcUrl) {
|
|
||||||
return "some-region"
|
|
||||||
}
|
|
||||||
return sdcUrl[strings.LastIndex(sdcUrl, "/")+1 : strings.Index(sdcUrl, ".")]
|
|
||||||
}
|
|
||||||
|
|
||||||
func isLocalhost(u string) bool {
|
|
||||||
parsedUrl, err := url.Parse(u)
|
|
||||||
if err != nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
if strings.HasPrefix(parsedUrl.Host, "localhost") || strings.HasPrefix(parsedUrl.Host, "127.0.0.1") {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
|
|
@ -1 +0,0 @@
|
||||||
example/example
|
|
|
@ -1,191 +0,0 @@
|
||||||
All files in this repository are licensed as follows. If you contribute
|
|
||||||
to this repository, it is assumed that you license your contribution
|
|
||||||
under the same license unless you state otherwise.
|
|
||||||
|
|
||||||
All files Copyright (C) 2015 Canonical Ltd. unless otherwise specified in the file.
|
|
||||||
|
|
||||||
This software is licensed under the LGPLv3, included below.
|
|
||||||
|
|
||||||
As a special exception to the GNU Lesser General Public License version 3
|
|
||||||
("LGPL3"), the copyright holders of this Library give you permission to
|
|
||||||
convey to a third party a Combined Work that links statically or dynamically
|
|
||||||
to this Library without providing any Minimal Corresponding Source or
|
|
||||||
Minimal Application Code as set out in 4d or providing the installation
|
|
||||||
information set out in section 4e, provided that you comply with the other
|
|
||||||
provisions of LGPL3 and provided that you meet, for the Application the
|
|
||||||
terms and conditions of the license(s) which apply to the Application.
|
|
||||||
|
|
||||||
Except as stated in this special exception, the provisions of LGPL3 will
|
|
||||||
continue to comply in full to this Library. If you modify this Library, you
|
|
||||||
may apply this exception to your version of this Library, but you are not
|
|
||||||
obliged to do so. If you do not wish to do so, delete this exception
|
|
||||||
statement from your version. This exception does not (and cannot) modify any
|
|
||||||
license terms which apply to the Application, with which you must still
|
|
||||||
comply.
|
|
||||||
|
|
||||||
|
|
||||||
GNU LESSER GENERAL PUBLIC LICENSE
|
|
||||||
Version 3, 29 June 2007
|
|
||||||
|
|
||||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
|
||||||
Everyone is permitted to copy and distribute verbatim copies
|
|
||||||
of this license document, but changing it is not allowed.
|
|
||||||
|
|
||||||
|
|
||||||
This version of the GNU Lesser General Public License incorporates
|
|
||||||
the terms and conditions of version 3 of the GNU General Public
|
|
||||||
License, supplemented by the additional permissions listed below.
|
|
||||||
|
|
||||||
0. Additional Definitions.
|
|
||||||
|
|
||||||
As used herein, "this License" refers to version 3 of the GNU Lesser
|
|
||||||
General Public License, and the "GNU GPL" refers to version 3 of the GNU
|
|
||||||
General Public License.
|
|
||||||
|
|
||||||
"The Library" refers to a covered work governed by this License,
|
|
||||||
other than an Application or a Combined Work as defined below.
|
|
||||||
|
|
||||||
An "Application" is any work that makes use of an interface provided
|
|
||||||
by the Library, but which is not otherwise based on the Library.
|
|
||||||
Defining a subclass of a class defined by the Library is deemed a mode
|
|
||||||
of using an interface provided by the Library.
|
|
||||||
|
|
||||||
A "Combined Work" is a work produced by combining or linking an
|
|
||||||
Application with the Library. The particular version of the Library
|
|
||||||
with which the Combined Work was made is also called the "Linked
|
|
||||||
Version".
|
|
||||||
|
|
||||||
The "Minimal Corresponding Source" for a Combined Work means the
|
|
||||||
Corresponding Source for the Combined Work, excluding any source code
|
|
||||||
for portions of the Combined Work that, considered in isolation, are
|
|
||||||
based on the Application, and not on the Linked Version.
|
|
||||||
|
|
||||||
The "Corresponding Application Code" for a Combined Work means the
|
|
||||||
object code and/or source code for the Application, including any data
|
|
||||||
and utility programs needed for reproducing the Combined Work from the
|
|
||||||
Application, but excluding the System Libraries of the Combined Work.
|
|
||||||
|
|
||||||
1. Exception to Section 3 of the GNU GPL.
|
|
||||||
|
|
||||||
You may convey a covered work under sections 3 and 4 of this License
|
|
||||||
without being bound by section 3 of the GNU GPL.
|
|
||||||
|
|
||||||
2. Conveying Modified Versions.
|
|
||||||
|
|
||||||
If you modify a copy of the Library, and, in your modifications, a
|
|
||||||
facility refers to a function or data to be supplied by an Application
|
|
||||||
that uses the facility (other than as an argument passed when the
|
|
||||||
facility is invoked), then you may convey a copy of the modified
|
|
||||||
version:
|
|
||||||
|
|
||||||
a) under this License, provided that you make a good faith effort to
|
|
||||||
ensure that, in the event an Application does not supply the
|
|
||||||
function or data, the facility still operates, and performs
|
|
||||||
whatever part of its purpose remains meaningful, or
|
|
||||||
|
|
||||||
b) under the GNU GPL, with none of the additional permissions of
|
|
||||||
this License applicable to that copy.
|
|
||||||
|
|
||||||
3. Object Code Incorporating Material from Library Header Files.
|
|
||||||
|
|
||||||
The object code form of an Application may incorporate material from
|
|
||||||
a header file that is part of the Library. You may convey such object
|
|
||||||
code under terms of your choice, provided that, if the incorporated
|
|
||||||
material is not limited to numerical parameters, data structure
|
|
||||||
layouts and accessors, or small macros, inline functions and templates
|
|
||||||
(ten or fewer lines in length), you do both of the following:
|
|
||||||
|
|
||||||
a) Give prominent notice with each copy of the object code that the
|
|
||||||
Library is used in it and that the Library and its use are
|
|
||||||
covered by this License.
|
|
||||||
|
|
||||||
b) Accompany the object code with a copy of the GNU GPL and this license
|
|
||||||
document.
|
|
||||||
|
|
||||||
4. Combined Works.
|
|
||||||
|
|
||||||
You may convey a Combined Work under terms of your choice that,
|
|
||||||
taken together, effectively do not restrict modification of the
|
|
||||||
portions of the Library contained in the Combined Work and reverse
|
|
||||||
engineering for debugging such modifications, if you also do each of
|
|
||||||
the following:
|
|
||||||
|
|
||||||
a) Give prominent notice with each copy of the Combined Work that
|
|
||||||
the Library is used in it and that the Library and its use are
|
|
||||||
covered by this License.
|
|
||||||
|
|
||||||
b) Accompany the Combined Work with a copy of the GNU GPL and this license
|
|
||||||
document.
|
|
||||||
|
|
||||||
c) For a Combined Work that displays copyright notices during
|
|
||||||
execution, include the copyright notice for the Library among
|
|
||||||
these notices, as well as a reference directing the user to the
|
|
||||||
copies of the GNU GPL and this license document.
|
|
||||||
|
|
||||||
d) Do one of the following:
|
|
||||||
|
|
||||||
0) Convey the Minimal Corresponding Source under the terms of this
|
|
||||||
License, and the Corresponding Application Code in a form
|
|
||||||
suitable for, and under terms that permit, the user to
|
|
||||||
recombine or relink the Application with a modified version of
|
|
||||||
the Linked Version to produce a modified Combined Work, in the
|
|
||||||
manner specified by section 6 of the GNU GPL for conveying
|
|
||||||
Corresponding Source.
|
|
||||||
|
|
||||||
1) Use a suitable shared library mechanism for linking with the
|
|
||||||
Library. A suitable mechanism is one that (a) uses at run time
|
|
||||||
a copy of the Library already present on the user's computer
|
|
||||||
system, and (b) will operate properly with a modified version
|
|
||||||
of the Library that is interface-compatible with the Linked
|
|
||||||
Version.
|
|
||||||
|
|
||||||
e) Provide Installation Information, but only if you would otherwise
|
|
||||||
be required to provide such information under section 6 of the
|
|
||||||
GNU GPL, and only to the extent that such information is
|
|
||||||
necessary to install and execute a modified version of the
|
|
||||||
Combined Work produced by recombining or relinking the
|
|
||||||
Application with a modified version of the Linked Version. (If
|
|
||||||
you use option 4d0, the Installation Information must accompany
|
|
||||||
the Minimal Corresponding Source and Corresponding Application
|
|
||||||
Code. If you use option 4d1, you must provide the Installation
|
|
||||||
Information in the manner specified by section 6 of the GNU GPL
|
|
||||||
for conveying Corresponding Source.)
|
|
||||||
|
|
||||||
5. Combined Libraries.
|
|
||||||
|
|
||||||
You may place library facilities that are a work based on the
|
|
||||||
Library side by side in a single library together with other library
|
|
||||||
facilities that are not Applications and are not covered by this
|
|
||||||
License, and convey such a combined library under terms of your
|
|
||||||
choice, if you do both of the following:
|
|
||||||
|
|
||||||
a) Accompany the combined library with a copy of the same work based
|
|
||||||
on the Library, uncombined with any other library facilities,
|
|
||||||
conveyed under the terms of this License.
|
|
||||||
|
|
||||||
b) Give prominent notice with the combined library that part of it
|
|
||||||
is a work based on the Library, and explaining where to find the
|
|
||||||
accompanying uncombined form of the same work.
|
|
||||||
|
|
||||||
6. Revised Versions of the GNU Lesser General Public License.
|
|
||||||
|
|
||||||
The Free Software Foundation may publish revised and/or new versions
|
|
||||||
of the GNU Lesser General Public License from time to time. Such new
|
|
||||||
versions will be similar in spirit to the present version, but may
|
|
||||||
differ in detail to address new problems or concerns.
|
|
||||||
|
|
||||||
Each version is given a distinguishing version number. If the
|
|
||||||
Library as you received it specifies that a certain numbered version
|
|
||||||
of the GNU Lesser General Public License "or any later version"
|
|
||||||
applies to it, you have the option of following the terms and
|
|
||||||
conditions either of that published version or of any later version
|
|
||||||
published by the Free Software Foundation. If the Library as you
|
|
||||||
received it does not specify a version number of the GNU Lesser
|
|
||||||
General Public License, you may choose any version of the GNU Lesser
|
|
||||||
General Public License ever published by the Free Software Foundation.
|
|
||||||
|
|
||||||
If the Library as you received it specifies that a proxy can decide
|
|
||||||
whether future versions of the GNU Lesser General Public License shall
|
|
||||||
apply, that proxy's public statement of acceptance of any version is
|
|
||||||
permanent authorization for you to choose that version for the
|
|
||||||
Library.
|
|
|
@ -1,11 +0,0 @@
|
||||||
default: check
|
|
||||||
|
|
||||||
check:
|
|
||||||
go test && go test -compiler gccgo
|
|
||||||
|
|
||||||
docs:
|
|
||||||
godoc2md github.com/juju/loggo > README.md
|
|
||||||
sed -i 's|\[godoc-link-here\]|[![GoDoc](https://godoc.org/github.com/juju/loggo?status.svg)](https://godoc.org/github.com/juju/loggo)|' README.md
|
|
||||||
|
|
||||||
|
|
||||||
.PHONY: default check docs
|
|
|
@ -1,548 +0,0 @@
|
||||||
|
|
||||||
# loggo
|
|
||||||
import "github.com/juju/loggo"
|
|
||||||
|
|
||||||
[![GoDoc](https://godoc.org/github.com/juju/loggo?status.svg)](https://godoc.org/github.com/juju/loggo)
|
|
||||||
|
|
||||||
### Module level logging for Go
|
|
||||||
This package provides an alternative to the standard library log package.
|
|
||||||
|
|
||||||
The actual logging functions never return errors. If you are logging
|
|
||||||
something, you really don't want to be worried about the logging
|
|
||||||
having trouble.
|
|
||||||
|
|
||||||
Modules have names that are defined by dotted strings.
|
|
||||||
|
|
||||||
|
|
||||||
"first.second.third"
|
|
||||||
|
|
||||||
There is a root module that has the name `""`. Each module
|
|
||||||
(except the root module) has a parent, identified by the part of
|
|
||||||
the name without the last dotted value.
|
|
||||||
* the parent of "first.second.third" is "first.second"
|
|
||||||
* the parent of "first.second" is "first"
|
|
||||||
* the parent of "first" is "" (the root module)
|
|
||||||
|
|
||||||
Each module can specify its own severity level. Logging calls that are of
|
|
||||||
a lower severity than the module's effective severity level are not written
|
|
||||||
out.
|
|
||||||
|
|
||||||
Loggers are created using the GetLogger function.
|
|
||||||
|
|
||||||
|
|
||||||
logger := loggo.GetLogger("foo.bar")
|
|
||||||
|
|
||||||
By default there is one writer registered, which will write to Stderr,
|
|
||||||
and the root module, which will only emit warnings and above.
|
|
||||||
If you want to continue using the default
|
|
||||||
logger, but have it emit all logging levels you need to do the following.
|
|
||||||
|
|
||||||
|
|
||||||
writer, _, err := loggo.RemoveWriter("default")
|
|
||||||
// err is non-nil if and only if the name isn't found.
|
|
||||||
loggo.RegisterWriter("default", writer, loggo.TRACE)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## func ConfigureLoggers
|
|
||||||
``` go
|
|
||||||
func ConfigureLoggers(specification string) error
|
|
||||||
```
|
|
||||||
ConfigureLoggers configures loggers according to the given string
|
|
||||||
specification, which specifies a set of modules and their associated
|
|
||||||
logging levels. Loggers are colon- or semicolon-separated; each
|
|
||||||
module is specified as <modulename>=<level>. White space outside of
|
|
||||||
module names and levels is ignored. The root module is specified
|
|
||||||
with the name "<root>".
|
|
||||||
|
|
||||||
An example specification:
|
|
||||||
|
|
||||||
|
|
||||||
`<root>=ERROR; foo.bar=WARNING`
|
|
||||||
|
|
||||||
|
|
||||||
## func LoggerInfo
|
|
||||||
``` go
|
|
||||||
func LoggerInfo() string
|
|
||||||
```
|
|
||||||
LoggerInfo returns information about the configured loggers and their logging
|
|
||||||
levels. The information is returned in the format expected by
|
|
||||||
ConfigureModules. Loggers with UNSPECIFIED level will not
|
|
||||||
be included.
|
|
||||||
|
|
||||||
|
|
||||||
## func ParseConfigurationString
|
|
||||||
``` go
|
|
||||||
func ParseConfigurationString(specification string) (map[string]Level, error)
|
|
||||||
```
|
|
||||||
ParseConfigurationString parses a logger configuration string into a map of
|
|
||||||
logger names and their associated log level. This method is provided to
|
|
||||||
allow other programs to pre-validate a configuration string rather than
|
|
||||||
just calling ConfigureLoggers.
|
|
||||||
|
|
||||||
Loggers are colon- or semicolon-separated; each module is specified as
|
|
||||||
<modulename>=<level>. White space outside of module names and levels is
|
|
||||||
ignored. The root module is specified with the name "<root>".
|
|
||||||
|
|
||||||
As a special case, a log level may be specified on its own.
|
|
||||||
This is equivalent to specifying the level of the root module,
|
|
||||||
so "DEBUG" is equivalent to `<root>=DEBUG`
|
|
||||||
|
|
||||||
An example specification:
|
|
||||||
|
|
||||||
|
|
||||||
`<root>=ERROR; foo.bar=WARNING`
|
|
||||||
|
|
||||||
|
|
||||||
## func RegisterWriter
|
|
||||||
``` go
|
|
||||||
func RegisterWriter(name string, writer Writer, minLevel Level) error
|
|
||||||
```
|
|
||||||
RegisterWriter adds the writer to the list of writers that get notified
|
|
||||||
when logging. When registering, the caller specifies the minimum logging
|
|
||||||
level that will be written, and a name for the writer. If there is already
|
|
||||||
a registered writer with that name, an error is returned.
|
|
||||||
|
|
||||||
|
|
||||||
## func ResetLoggers
|
|
||||||
``` go
|
|
||||||
func ResetLoggers()
|
|
||||||
```
|
|
||||||
ResetLogging iterates through the known modules and sets the levels of all
|
|
||||||
to UNSPECIFIED, except for <root> which is set to WARNING.
|
|
||||||
|
|
||||||
|
|
||||||
## func ResetWriters
|
|
||||||
``` go
|
|
||||||
func ResetWriters()
|
|
||||||
```
|
|
||||||
ResetWriters puts the list of writers back into the initial state.
|
|
||||||
|
|
||||||
|
|
||||||
## func WillWrite
|
|
||||||
``` go
|
|
||||||
func WillWrite(level Level) bool
|
|
||||||
```
|
|
||||||
WillWrite returns whether there are any writers registered
|
|
||||||
at or above the given severity level. If it returns
|
|
||||||
false, a log message at the given level will be discarded.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## type DefaultFormatter
|
|
||||||
``` go
|
|
||||||
type DefaultFormatter struct{}
|
|
||||||
```
|
|
||||||
DefaultFormatter provides a simple concatenation of all the components.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### func (\*DefaultFormatter) Format
|
|
||||||
``` go
|
|
||||||
func (*DefaultFormatter) Format(level Level, module, filename string, line int, timestamp time.Time, message string) string
|
|
||||||
```
|
|
||||||
Format returns the parameters separated by spaces except for filename and
|
|
||||||
line which are separated by a colon. The timestamp is shown to second
|
|
||||||
resolution in UTC.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## type Formatter
|
|
||||||
``` go
|
|
||||||
type Formatter interface {
|
|
||||||
Format(level Level, module, filename string, line int, timestamp time.Time, message string) string
|
|
||||||
}
|
|
||||||
```
|
|
||||||
Formatter defines the single method Format, which takes the logging
|
|
||||||
information, and converts it to a string.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## type Level
|
|
||||||
``` go
|
|
||||||
type Level uint32
|
|
||||||
```
|
|
||||||
Level holds a severity level.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
``` go
|
|
||||||
const (
|
|
||||||
UNSPECIFIED Level = iota
|
|
||||||
TRACE
|
|
||||||
DEBUG
|
|
||||||
INFO
|
|
||||||
WARNING
|
|
||||||
ERROR
|
|
||||||
CRITICAL
|
|
||||||
)
|
|
||||||
```
|
|
||||||
The severity levels. Higher values are more considered more
|
|
||||||
important.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### func ParseLevel
|
|
||||||
``` go
|
|
||||||
func ParseLevel(level string) (Level, bool)
|
|
||||||
```
|
|
||||||
ParseLevel converts a string representation of a logging level to a
|
|
||||||
Level. It returns the level and whether it was valid or not.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### func (Level) String
|
|
||||||
``` go
|
|
||||||
func (level Level) String() string
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
## type Logger
|
|
||||||
``` go
|
|
||||||
type Logger struct {
|
|
||||||
// contains filtered or unexported fields
|
|
||||||
}
|
|
||||||
```
|
|
||||||
A Logger represents a logging module. It has an associated logging
|
|
||||||
level which can be changed; messages of lesser severity will
|
|
||||||
be dropped. Loggers have a hierarchical relationship - see
|
|
||||||
the package documentation.
|
|
||||||
|
|
||||||
The zero Logger value is usable - any messages logged
|
|
||||||
to it will be sent to the root Logger.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### func GetLogger
|
|
||||||
``` go
|
|
||||||
func GetLogger(name string) Logger
|
|
||||||
```
|
|
||||||
GetLogger returns a Logger for the given module name,
|
|
||||||
creating it and its parents if necessary.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### func (Logger) Criticalf
|
|
||||||
``` go
|
|
||||||
func (logger Logger) Criticalf(message string, args ...interface{})
|
|
||||||
```
|
|
||||||
Criticalf logs the printf-formatted message at critical level.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### func (Logger) Debugf
|
|
||||||
``` go
|
|
||||||
func (logger Logger) Debugf(message string, args ...interface{})
|
|
||||||
```
|
|
||||||
Debugf logs the printf-formatted message at debug level.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### func (Logger) EffectiveLogLevel
|
|
||||||
``` go
|
|
||||||
func (logger Logger) EffectiveLogLevel() Level
|
|
||||||
```
|
|
||||||
EffectiveLogLevel returns the effective log level of
|
|
||||||
the receiver - that is, messages with a lesser severity
|
|
||||||
level will be discarded.
|
|
||||||
|
|
||||||
If the log level of the receiver is unspecified,
|
|
||||||
it will be taken from the effective log level of its
|
|
||||||
parent.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### func (Logger) Errorf
|
|
||||||
``` go
|
|
||||||
func (logger Logger) Errorf(message string, args ...interface{})
|
|
||||||
```
|
|
||||||
Errorf logs the printf-formatted message at error level.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### func (Logger) Infof
|
|
||||||
``` go
|
|
||||||
func (logger Logger) Infof(message string, args ...interface{})
|
|
||||||
```
|
|
||||||
Infof logs the printf-formatted message at info level.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### func (Logger) IsDebugEnabled
|
|
||||||
``` go
|
|
||||||
func (logger Logger) IsDebugEnabled() bool
|
|
||||||
```
|
|
||||||
IsDebugEnabled returns whether debugging is enabled
|
|
||||||
at debug level.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### func (Logger) IsErrorEnabled
|
|
||||||
``` go
|
|
||||||
func (logger Logger) IsErrorEnabled() bool
|
|
||||||
```
|
|
||||||
IsErrorEnabled returns whether debugging is enabled
|
|
||||||
at error level.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### func (Logger) IsInfoEnabled
|
|
||||||
``` go
|
|
||||||
func (logger Logger) IsInfoEnabled() bool
|
|
||||||
```
|
|
||||||
IsInfoEnabled returns whether debugging is enabled
|
|
||||||
at info level.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### func (Logger) IsLevelEnabled
|
|
||||||
``` go
|
|
||||||
func (logger Logger) IsLevelEnabled(level Level) bool
|
|
||||||
```
|
|
||||||
IsLevelEnabled returns whether debugging is enabled
|
|
||||||
for the given log level.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### func (Logger) IsTraceEnabled
|
|
||||||
``` go
|
|
||||||
func (logger Logger) IsTraceEnabled() bool
|
|
||||||
```
|
|
||||||
IsTraceEnabled returns whether debugging is enabled
|
|
||||||
at trace level.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### func (Logger) IsWarningEnabled
|
|
||||||
``` go
|
|
||||||
func (logger Logger) IsWarningEnabled() bool
|
|
||||||
```
|
|
||||||
IsWarningEnabled returns whether debugging is enabled
|
|
||||||
at warning level.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### func (Logger) LogCallf
|
|
||||||
``` go
|
|
||||||
func (logger Logger) LogCallf(calldepth int, level Level, message string, args ...interface{})
|
|
||||||
```
|
|
||||||
LogCallf logs a printf-formatted message at the given level.
|
|
||||||
The location of the call is indicated by the calldepth argument.
|
|
||||||
A calldepth of 1 means the function that called this function.
|
|
||||||
A message will be discarded if level is less than the
|
|
||||||
the effective log level of the logger.
|
|
||||||
Note that the writers may also filter out messages that
|
|
||||||
are less than their registered minimum severity level.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### func (Logger) LogLevel
|
|
||||||
``` go
|
|
||||||
func (logger Logger) LogLevel() Level
|
|
||||||
```
|
|
||||||
LogLevel returns the configured log level of the logger.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### func (Logger) Logf
|
|
||||||
``` go
|
|
||||||
func (logger Logger) Logf(level Level, message string, args ...interface{})
|
|
||||||
```
|
|
||||||
Logf logs a printf-formatted message at the given level.
|
|
||||||
A message will be discarded if level is less than the
|
|
||||||
the effective log level of the logger.
|
|
||||||
Note that the writers may also filter out messages that
|
|
||||||
are less than their registered minimum severity level.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### func (Logger) Name
|
|
||||||
``` go
|
|
||||||
func (logger Logger) Name() string
|
|
||||||
```
|
|
||||||
Name returns the logger's module name.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### func (Logger) SetLogLevel
|
|
||||||
``` go
|
|
||||||
func (logger Logger) SetLogLevel(level Level)
|
|
||||||
```
|
|
||||||
SetLogLevel sets the severity level of the given logger.
|
|
||||||
The root logger cannot be set to UNSPECIFIED level.
|
|
||||||
See EffectiveLogLevel for how this affects the
|
|
||||||
actual messages logged.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### func (Logger) Tracef
|
|
||||||
``` go
|
|
||||||
func (logger Logger) Tracef(message string, args ...interface{})
|
|
||||||
```
|
|
||||||
Tracef logs the printf-formatted message at trace level.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### func (Logger) Warningf
|
|
||||||
``` go
|
|
||||||
func (logger Logger) Warningf(message string, args ...interface{})
|
|
||||||
```
|
|
||||||
Warningf logs the printf-formatted message at warning level.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## type TestLogValues
|
|
||||||
``` go
|
|
||||||
type TestLogValues struct {
|
|
||||||
Level Level
|
|
||||||
Module string
|
|
||||||
Filename string
|
|
||||||
Line int
|
|
||||||
Timestamp time.Time
|
|
||||||
Message string
|
|
||||||
}
|
|
||||||
```
|
|
||||||
TestLogValues represents a single logging call.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## type TestWriter
|
|
||||||
``` go
|
|
||||||
type TestWriter struct {
|
|
||||||
// contains filtered or unexported fields
|
|
||||||
}
|
|
||||||
```
|
|
||||||
TestWriter is a useful Writer for testing purposes. Each component of the
|
|
||||||
logging message is stored in the Log array.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### func (\*TestWriter) Clear
|
|
||||||
``` go
|
|
||||||
func (writer *TestWriter) Clear()
|
|
||||||
```
|
|
||||||
Clear removes any saved log messages.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### func (\*TestWriter) Log
|
|
||||||
``` go
|
|
||||||
func (writer *TestWriter) Log() []TestLogValues
|
|
||||||
```
|
|
||||||
Log returns a copy of the current logged values.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### func (\*TestWriter) Write
|
|
||||||
``` go
|
|
||||||
func (writer *TestWriter) Write(level Level, module, filename string, line int, timestamp time.Time, message string)
|
|
||||||
```
|
|
||||||
Write saves the params as members in the TestLogValues struct appended to the Log array.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## type Writer
|
|
||||||
``` go
|
|
||||||
type Writer interface {
|
|
||||||
// Write writes a message to the Writer with the given
|
|
||||||
// level and module name. The filename and line hold
|
|
||||||
// the file name and line number of the code that is
|
|
||||||
// generating the log message; the time stamp holds
|
|
||||||
// the time the log message was generated, and
|
|
||||||
// message holds the log message itself.
|
|
||||||
Write(level Level, name, filename string, line int, timestamp time.Time, message string)
|
|
||||||
}
|
|
||||||
```
|
|
||||||
Writer is implemented by any recipient of log messages.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### func NewSimpleWriter
|
|
||||||
``` go
|
|
||||||
func NewSimpleWriter(writer io.Writer, formatter Formatter) Writer
|
|
||||||
```
|
|
||||||
NewSimpleWriter returns a new writer that writes
|
|
||||||
log messages to the given io.Writer formatting the
|
|
||||||
messages with the given formatter.
|
|
||||||
|
|
||||||
|
|
||||||
### func RemoveWriter
|
|
||||||
``` go
|
|
||||||
func RemoveWriter(name string) (Writer, Level, error)
|
|
||||||
```
|
|
||||||
RemoveWriter removes the Writer identified by 'name' and returns it.
|
|
||||||
If the Writer is not found, an error is returned.
|
|
||||||
|
|
||||||
|
|
||||||
### func ReplaceDefaultWriter
|
|
||||||
``` go
|
|
||||||
func ReplaceDefaultWriter(writer Writer) (Writer, error)
|
|
||||||
```
|
|
||||||
ReplaceDefaultWriter is a convenience method that does the equivalent of
|
|
||||||
RemoveWriter and then RegisterWriter with the name "default". The previous
|
|
||||||
default writer, if any is returned.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
- - -
|
|
||||||
Generated by [godoc2md](http://godoc.org/github.com/davecheney/godoc2md)
|
|
|
@ -1,42 +0,0 @@
|
||||||
// Copyright 2014 Canonical Ltd.
|
|
||||||
// Licensed under the LGPLv3, see LICENCE file for details.
|
|
||||||
|
|
||||||
/*
|
|
||||||
[godoc-link-here]
|
|
||||||
|
|
||||||
Module level logging for Go
|
|
||||||
|
|
||||||
This package provides an alternative to the standard library log package.
|
|
||||||
|
|
||||||
The actual logging functions never return errors. If you are logging
|
|
||||||
something, you really don't want to be worried about the logging
|
|
||||||
having trouble.
|
|
||||||
|
|
||||||
Modules have names that are defined by dotted strings.
|
|
||||||
"first.second.third"
|
|
||||||
|
|
||||||
There is a root module that has the name `""`. Each module
|
|
||||||
(except the root module) has a parent, identified by the part of
|
|
||||||
the name without the last dotted value.
|
|
||||||
* the parent of "first.second.third" is "first.second"
|
|
||||||
* the parent of "first.second" is "first"
|
|
||||||
* the parent of "first" is "" (the root module)
|
|
||||||
|
|
||||||
Each module can specify its own severity level. Logging calls that are of
|
|
||||||
a lower severity than the module's effective severity level are not written
|
|
||||||
out.
|
|
||||||
|
|
||||||
Loggers are created using the GetLogger function.
|
|
||||||
logger := loggo.GetLogger("foo.bar")
|
|
||||||
|
|
||||||
By default there is one writer registered, which will write to Stderr,
|
|
||||||
and the root module, which will only emit warnings and above.
|
|
||||||
If you want to continue using the default
|
|
||||||
logger, but have it emit all logging levels you need to do the following.
|
|
||||||
|
|
||||||
writer, _, err := loggo.RemoveWriter("default")
|
|
||||||
// err is non-nil if and only if the name isn't found.
|
|
||||||
loggo.RegisterWriter("default", writer, loggo.TRACE)
|
|
||||||
|
|
||||||
*/
|
|
||||||
package loggo
|
|
|
@ -1,27 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/juju/loggo"
|
|
||||||
)
|
|
||||||
|
|
||||||
var first = loggo.GetLogger("first")
|
|
||||||
|
|
||||||
func FirstCritical(message string) {
|
|
||||||
first.Criticalf(message)
|
|
||||||
}
|
|
||||||
|
|
||||||
func FirstError(message string) {
|
|
||||||
first.Errorf(message)
|
|
||||||
}
|
|
||||||
|
|
||||||
func FirstWarning(message string) {
|
|
||||||
first.Warningf(message)
|
|
||||||
}
|
|
||||||
|
|
||||||
func FirstInfo(message string) {
|
|
||||||
first.Infof(message)
|
|
||||||
}
|
|
||||||
|
|
||||||
func FirstTrace(message string) {
|
|
||||||
first.Tracef(message)
|
|
||||||
}
|
|
|
@ -1,39 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
|
|
||||||
"github.com/juju/loggo"
|
|
||||||
)
|
|
||||||
|
|
||||||
var logger = loggo.GetLogger("main")
|
|
||||||
var rootLogger = loggo.GetLogger("")
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
args := os.Args
|
|
||||||
if len(args) > 1 {
|
|
||||||
loggo.ConfigureLoggers(args[1])
|
|
||||||
} else {
|
|
||||||
fmt.Println("Add a parameter to configure the logging:")
|
|
||||||
fmt.Println("E.g. \"<root>=INFO;first=TRACE\"")
|
|
||||||
}
|
|
||||||
fmt.Println("\nCurrent logging levels:")
|
|
||||||
fmt.Println(loggo.LoggerInfo())
|
|
||||||
fmt.Println("")
|
|
||||||
|
|
||||||
rootLogger.Infof("Start of test.")
|
|
||||||
|
|
||||||
FirstCritical("first critical")
|
|
||||||
FirstError("first error")
|
|
||||||
FirstWarning("first warning")
|
|
||||||
FirstInfo("first info")
|
|
||||||
FirstTrace("first trace")
|
|
||||||
|
|
||||||
SecondCritical("first critical")
|
|
||||||
SecondError("first error")
|
|
||||||
SecondWarning("first warning")
|
|
||||||
SecondInfo("first info")
|
|
||||||
SecondTrace("first trace")
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,27 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/juju/loggo"
|
|
||||||
)
|
|
||||||
|
|
||||||
var second = loggo.GetLogger("second")
|
|
||||||
|
|
||||||
func SecondCritical(message string) {
|
|
||||||
second.Criticalf(message)
|
|
||||||
}
|
|
||||||
|
|
||||||
func SecondError(message string) {
|
|
||||||
second.Errorf(message)
|
|
||||||
}
|
|
||||||
|
|
||||||
func SecondWarning(message string) {
|
|
||||||
second.Warningf(message)
|
|
||||||
}
|
|
||||||
|
|
||||||
func SecondInfo(message string) {
|
|
||||||
second.Infof(message)
|
|
||||||
}
|
|
||||||
|
|
||||||
func SecondTrace(message string) {
|
|
||||||
second.Tracef(message)
|
|
||||||
}
|
|
|
@ -1,29 +0,0 @@
|
||||||
// Copyright 2014 Canonical Ltd.
|
|
||||||
// Licensed under the LGPLv3, see LICENCE file for details.
|
|
||||||
|
|
||||||
package loggo
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"path/filepath"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Formatter defines the single method Format, which takes the logging
|
|
||||||
// information, and converts it to a string.
|
|
||||||
type Formatter interface {
|
|
||||||
Format(level Level, module, filename string, line int, timestamp time.Time, message string) string
|
|
||||||
}
|
|
||||||
|
|
||||||
// DefaultFormatter provides a simple concatenation of all the components.
|
|
||||||
type DefaultFormatter struct{}
|
|
||||||
|
|
||||||
// Format returns the parameters separated by spaces except for filename and
|
|
||||||
// line which are separated by a colon. The timestamp is shown to second
|
|
||||||
// resolution in UTC.
|
|
||||||
func (*DefaultFormatter) Format(level Level, module, filename string, line int, timestamp time.Time, message string) string {
|
|
||||||
ts := timestamp.In(time.UTC).Format("2006-01-02 15:04:05")
|
|
||||||
// Just get the basename from the filename
|
|
||||||
filename = filepath.Base(filename)
|
|
||||||
return fmt.Sprintf("%s %s %s %s:%d %s", ts, level, module, filename, line, message)
|
|
||||||
}
|
|
|
@ -1,417 +0,0 @@
|
||||||
// Copyright 2014 Canonical Ltd.
|
|
||||||
// Licensed under the LGPLv3, see LICENCE file for details.
|
|
||||||
|
|
||||||
package loggo
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"runtime"
|
|
||||||
"sort"
|
|
||||||
"strings"
|
|
||||||
"sync"
|
|
||||||
"sync/atomic"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Level holds a severity level.
|
|
||||||
type Level uint32
|
|
||||||
|
|
||||||
// The severity levels. Higher values are more considered more
|
|
||||||
// important.
|
|
||||||
const (
|
|
||||||
UNSPECIFIED Level = iota
|
|
||||||
TRACE
|
|
||||||
DEBUG
|
|
||||||
INFO
|
|
||||||
WARNING
|
|
||||||
ERROR
|
|
||||||
CRITICAL
|
|
||||||
)
|
|
||||||
|
|
||||||
// A Logger represents a logging module. It has an associated logging
|
|
||||||
// level which can be changed; messages of lesser severity will
|
|
||||||
// be dropped. Loggers have a hierarchical relationship - see
|
|
||||||
// the package documentation.
|
|
||||||
//
|
|
||||||
// The zero Logger value is usable - any messages logged
|
|
||||||
// to it will be sent to the root Logger.
|
|
||||||
type Logger struct {
|
|
||||||
impl *module
|
|
||||||
}
|
|
||||||
|
|
||||||
type module struct {
|
|
||||||
name string
|
|
||||||
level Level
|
|
||||||
parent *module
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initially the modules map only contains the root module.
|
|
||||||
var (
|
|
||||||
root = &module{level: WARNING}
|
|
||||||
modulesMutex sync.Mutex
|
|
||||||
modules = map[string]*module{
|
|
||||||
"": root,
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
func (level Level) String() string {
|
|
||||||
switch level {
|
|
||||||
case UNSPECIFIED:
|
|
||||||
return "UNSPECIFIED"
|
|
||||||
case TRACE:
|
|
||||||
return "TRACE"
|
|
||||||
case DEBUG:
|
|
||||||
return "DEBUG"
|
|
||||||
case INFO:
|
|
||||||
return "INFO"
|
|
||||||
case WARNING:
|
|
||||||
return "WARNING"
|
|
||||||
case ERROR:
|
|
||||||
return "ERROR"
|
|
||||||
case CRITICAL:
|
|
||||||
return "CRITICAL"
|
|
||||||
}
|
|
||||||
return "<unknown>"
|
|
||||||
}
|
|
||||||
|
|
||||||
// get atomically gets the value of the given level.
|
|
||||||
func (level *Level) get() Level {
|
|
||||||
return Level(atomic.LoadUint32((*uint32)(level)))
|
|
||||||
}
|
|
||||||
|
|
||||||
// set atomically sets the value of the receiver
|
|
||||||
// to the given level.
|
|
||||||
func (level *Level) set(newLevel Level) {
|
|
||||||
atomic.StoreUint32((*uint32)(level), uint32(newLevel))
|
|
||||||
}
|
|
||||||
|
|
||||||
// getLoggerInternal assumes that the modulesMutex is locked.
|
|
||||||
func getLoggerInternal(name string) Logger {
|
|
||||||
impl, found := modules[name]
|
|
||||||
if found {
|
|
||||||
return Logger{impl}
|
|
||||||
}
|
|
||||||
parentName := ""
|
|
||||||
if i := strings.LastIndex(name, "."); i >= 0 {
|
|
||||||
parentName = name[0:i]
|
|
||||||
}
|
|
||||||
parent := getLoggerInternal(parentName).impl
|
|
||||||
impl = &module{name, UNSPECIFIED, parent}
|
|
||||||
modules[name] = impl
|
|
||||||
return Logger{impl}
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetLogger returns a Logger for the given module name,
|
|
||||||
// creating it and its parents if necessary.
|
|
||||||
func GetLogger(name string) Logger {
|
|
||||||
// Lowercase the module name, and look for it in the modules map.
|
|
||||||
name = strings.ToLower(name)
|
|
||||||
modulesMutex.Lock()
|
|
||||||
defer modulesMutex.Unlock()
|
|
||||||
return getLoggerInternal(name)
|
|
||||||
}
|
|
||||||
|
|
||||||
// LoggerInfo returns information about the configured loggers and their logging
|
|
||||||
// levels. The information is returned in the format expected by
|
|
||||||
// ConfigureModules. Loggers with UNSPECIFIED level will not
|
|
||||||
// be included.
|
|
||||||
func LoggerInfo() string {
|
|
||||||
output := []string{}
|
|
||||||
// output in alphabetical order.
|
|
||||||
keys := []string{}
|
|
||||||
modulesMutex.Lock()
|
|
||||||
defer modulesMutex.Unlock()
|
|
||||||
for key := range modules {
|
|
||||||
keys = append(keys, key)
|
|
||||||
}
|
|
||||||
sort.Strings(keys)
|
|
||||||
for _, name := range keys {
|
|
||||||
mod := modules[name]
|
|
||||||
severity := mod.level.get()
|
|
||||||
if severity == UNSPECIFIED {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
output = append(output, fmt.Sprintf("%s=%s", mod.Name(), severity))
|
|
||||||
}
|
|
||||||
return strings.Join(output, ";")
|
|
||||||
}
|
|
||||||
|
|
||||||
// ParseConfigurationString parses a logger configuration string into a map of
|
|
||||||
// logger names and their associated log level. This method is provided to
|
|
||||||
// allow other programs to pre-validate a configuration string rather than
|
|
||||||
// just calling ConfigureLoggers.
|
|
||||||
//
|
|
||||||
// Loggers are colon- or semicolon-separated; each module is specified as
|
|
||||||
// <modulename>=<level>. White space outside of module names and levels is
|
|
||||||
// ignored. The root module is specified with the name "<root>".
|
|
||||||
//
|
|
||||||
// As a special case, a log level may be specified on its own.
|
|
||||||
// This is equivalent to specifying the level of the root module,
|
|
||||||
// so "DEBUG" is equivalent to `<root>=DEBUG`
|
|
||||||
//
|
|
||||||
// An example specification:
|
|
||||||
// `<root>=ERROR; foo.bar=WARNING`
|
|
||||||
func ParseConfigurationString(specification string) (map[string]Level, error) {
|
|
||||||
levels := make(map[string]Level)
|
|
||||||
if level, ok := ParseLevel(specification); ok {
|
|
||||||
levels[""] = level
|
|
||||||
return levels, nil
|
|
||||||
}
|
|
||||||
values := strings.FieldsFunc(specification, func(r rune) bool { return r == ';' || r == ':' })
|
|
||||||
for _, value := range values {
|
|
||||||
s := strings.SplitN(value, "=", 2)
|
|
||||||
if len(s) < 2 {
|
|
||||||
return nil, fmt.Errorf("logger specification expected '=', found %q", value)
|
|
||||||
}
|
|
||||||
name := strings.TrimSpace(s[0])
|
|
||||||
levelStr := strings.TrimSpace(s[1])
|
|
||||||
if name == "" || levelStr == "" {
|
|
||||||
return nil, fmt.Errorf("logger specification %q has blank name or level", value)
|
|
||||||
}
|
|
||||||
if name == "<root>" {
|
|
||||||
name = ""
|
|
||||||
}
|
|
||||||
level, ok := ParseLevel(levelStr)
|
|
||||||
if !ok {
|
|
||||||
return nil, fmt.Errorf("unknown severity level %q", levelStr)
|
|
||||||
}
|
|
||||||
levels[name] = level
|
|
||||||
}
|
|
||||||
return levels, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ConfigureLoggers configures loggers according to the given string
|
|
||||||
// specification, which specifies a set of modules and their associated
|
|
||||||
// logging levels. Loggers are colon- or semicolon-separated; each
|
|
||||||
// module is specified as <modulename>=<level>. White space outside of
|
|
||||||
// module names and levels is ignored. The root module is specified
|
|
||||||
// with the name "<root>".
|
|
||||||
//
|
|
||||||
// An example specification:
|
|
||||||
// `<root>=ERROR; foo.bar=WARNING`
|
|
||||||
func ConfigureLoggers(specification string) error {
|
|
||||||
if specification == "" {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
levels, err := ParseConfigurationString(specification)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
for name, level := range levels {
|
|
||||||
GetLogger(name).SetLogLevel(level)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ResetLogging iterates through the known modules and sets the levels of all
|
|
||||||
// to UNSPECIFIED, except for <root> which is set to WARNING.
|
|
||||||
func ResetLoggers() {
|
|
||||||
modulesMutex.Lock()
|
|
||||||
defer modulesMutex.Unlock()
|
|
||||||
for name, module := range modules {
|
|
||||||
if name == "" {
|
|
||||||
module.level.set(WARNING)
|
|
||||||
} else {
|
|
||||||
module.level.set(UNSPECIFIED)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ParseLevel converts a string representation of a logging level to a
|
|
||||||
// Level. It returns the level and whether it was valid or not.
|
|
||||||
func ParseLevel(level string) (Level, bool) {
|
|
||||||
level = strings.ToUpper(level)
|
|
||||||
switch level {
|
|
||||||
case "UNSPECIFIED":
|
|
||||||
return UNSPECIFIED, true
|
|
||||||
case "TRACE":
|
|
||||||
return TRACE, true
|
|
||||||
case "DEBUG":
|
|
||||||
return DEBUG, true
|
|
||||||
case "INFO":
|
|
||||||
return INFO, true
|
|
||||||
case "WARN", "WARNING":
|
|
||||||
return WARNING, true
|
|
||||||
case "ERROR":
|
|
||||||
return ERROR, true
|
|
||||||
case "CRITICAL":
|
|
||||||
return CRITICAL, true
|
|
||||||
}
|
|
||||||
return UNSPECIFIED, false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (logger Logger) getModule() *module {
|
|
||||||
if logger.impl == nil {
|
|
||||||
return root
|
|
||||||
}
|
|
||||||
return logger.impl
|
|
||||||
}
|
|
||||||
|
|
||||||
// Name returns the logger's module name.
|
|
||||||
func (logger Logger) Name() string {
|
|
||||||
return logger.getModule().Name()
|
|
||||||
}
|
|
||||||
|
|
||||||
// LogLevel returns the configured log level of the logger.
|
|
||||||
func (logger Logger) LogLevel() Level {
|
|
||||||
return logger.getModule().level.get()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (module *module) getEffectiveLogLevel() Level {
|
|
||||||
// Note: the root module is guaranteed to have a
|
|
||||||
// specified logging level, so acts as a suitable sentinel
|
|
||||||
// for this loop.
|
|
||||||
for {
|
|
||||||
if level := module.level.get(); level != UNSPECIFIED {
|
|
||||||
return level
|
|
||||||
}
|
|
||||||
module = module.parent
|
|
||||||
}
|
|
||||||
panic("unreachable")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (module *module) Name() string {
|
|
||||||
if module.name == "" {
|
|
||||||
return "<root>"
|
|
||||||
}
|
|
||||||
return module.name
|
|
||||||
}
|
|
||||||
|
|
||||||
// EffectiveLogLevel returns the effective log level of
|
|
||||||
// the receiver - that is, messages with a lesser severity
|
|
||||||
// level will be discarded.
|
|
||||||
//
|
|
||||||
// If the log level of the receiver is unspecified,
|
|
||||||
// it will be taken from the effective log level of its
|
|
||||||
// parent.
|
|
||||||
func (logger Logger) EffectiveLogLevel() Level {
|
|
||||||
return logger.getModule().getEffectiveLogLevel()
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetLogLevel sets the severity level of the given logger.
|
|
||||||
// The root logger cannot be set to UNSPECIFIED level.
|
|
||||||
// See EffectiveLogLevel for how this affects the
|
|
||||||
// actual messages logged.
|
|
||||||
func (logger Logger) SetLogLevel(level Level) {
|
|
||||||
module := logger.getModule()
|
|
||||||
// The root module can't be unspecified.
|
|
||||||
if module.name == "" && level == UNSPECIFIED {
|
|
||||||
level = WARNING
|
|
||||||
}
|
|
||||||
module.level.set(level)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Logf logs a printf-formatted message at the given level.
|
|
||||||
// A message will be discarded if level is less than the
|
|
||||||
// the effective log level of the logger.
|
|
||||||
// Note that the writers may also filter out messages that
|
|
||||||
// are less than their registered minimum severity level.
|
|
||||||
func (logger Logger) Logf(level Level, message string, args ...interface{}) {
|
|
||||||
logger.LogCallf(2, level, message, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// LogCallf logs a printf-formatted message at the given level.
|
|
||||||
// The location of the call is indicated by the calldepth argument.
|
|
||||||
// A calldepth of 1 means the function that called this function.
|
|
||||||
// A message will be discarded if level is less than the
|
|
||||||
// the effective log level of the logger.
|
|
||||||
// Note that the writers may also filter out messages that
|
|
||||||
// are less than their registered minimum severity level.
|
|
||||||
func (logger Logger) LogCallf(calldepth int, level Level, message string, args ...interface{}) {
|
|
||||||
if logger.getModule().getEffectiveLogLevel() > level ||
|
|
||||||
!WillWrite(level) ||
|
|
||||||
level < TRACE ||
|
|
||||||
level > CRITICAL {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
// Gather time, and filename, line number.
|
|
||||||
now := time.Now() // get this early.
|
|
||||||
// Param to Caller is the call depth. Since this method is called from
|
|
||||||
// the Logger methods, we want the place that those were called from.
|
|
||||||
_, file, line, ok := runtime.Caller(calldepth + 1)
|
|
||||||
if !ok {
|
|
||||||
file = "???"
|
|
||||||
line = 0
|
|
||||||
}
|
|
||||||
// Trim newline off format string, following usual
|
|
||||||
// Go logging conventions.
|
|
||||||
if len(message) > 0 && message[len(message)-1] == '\n' {
|
|
||||||
message = message[0 : len(message)-1]
|
|
||||||
}
|
|
||||||
|
|
||||||
// To avoid having a proliferation of Info/Infof methods,
|
|
||||||
// only use Sprintf if there are any args, and rely on the
|
|
||||||
// `go vet` tool for the obvious cases where someone has forgotten
|
|
||||||
// to provide an arg.
|
|
||||||
formattedMessage := message
|
|
||||||
if len(args) > 0 {
|
|
||||||
formattedMessage = fmt.Sprintf(message, args...)
|
|
||||||
}
|
|
||||||
writeToWriters(level, logger.impl.name, file, line, now, formattedMessage)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Criticalf logs the printf-formatted message at critical level.
|
|
||||||
func (logger Logger) Criticalf(message string, args ...interface{}) {
|
|
||||||
logger.Logf(CRITICAL, message, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Errorf logs the printf-formatted message at error level.
|
|
||||||
func (logger Logger) Errorf(message string, args ...interface{}) {
|
|
||||||
logger.Logf(ERROR, message, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Warningf logs the printf-formatted message at warning level.
|
|
||||||
func (logger Logger) Warningf(message string, args ...interface{}) {
|
|
||||||
logger.Logf(WARNING, message, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Infof logs the printf-formatted message at info level.
|
|
||||||
func (logger Logger) Infof(message string, args ...interface{}) {
|
|
||||||
logger.Logf(INFO, message, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Debugf logs the printf-formatted message at debug level.
|
|
||||||
func (logger Logger) Debugf(message string, args ...interface{}) {
|
|
||||||
logger.Logf(DEBUG, message, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Tracef logs the printf-formatted message at trace level.
|
|
||||||
func (logger Logger) Tracef(message string, args ...interface{}) {
|
|
||||||
logger.Logf(TRACE, message, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsLevelEnabled returns whether debugging is enabled
|
|
||||||
// for the given log level.
|
|
||||||
func (logger Logger) IsLevelEnabled(level Level) bool {
|
|
||||||
return logger.getModule().getEffectiveLogLevel() <= level
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsErrorEnabled returns whether debugging is enabled
|
|
||||||
// at error level.
|
|
||||||
func (logger Logger) IsErrorEnabled() bool {
|
|
||||||
return logger.IsLevelEnabled(ERROR)
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsWarningEnabled returns whether debugging is enabled
|
|
||||||
// at warning level.
|
|
||||||
func (logger Logger) IsWarningEnabled() bool {
|
|
||||||
return logger.IsLevelEnabled(WARNING)
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsInfoEnabled returns whether debugging is enabled
|
|
||||||
// at info level.
|
|
||||||
func (logger Logger) IsInfoEnabled() bool {
|
|
||||||
return logger.IsLevelEnabled(INFO)
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsDebugEnabled returns whether debugging is enabled
|
|
||||||
// at debug level.
|
|
||||||
func (logger Logger) IsDebugEnabled() bool {
|
|
||||||
return logger.IsLevelEnabled(DEBUG)
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsTraceEnabled returns whether debugging is enabled
|
|
||||||
// at trace level.
|
|
||||||
func (logger Logger) IsTraceEnabled() bool {
|
|
||||||
return logger.IsLevelEnabled(TRACE)
|
|
||||||
}
|
|
|
@ -1,51 +0,0 @@
|
||||||
// Copyright 2014 Canonical Ltd.
|
|
||||||
// Licensed under the LGPLv3, see LICENCE file for details.
|
|
||||||
|
|
||||||
package loggo
|
|
||||||
|
|
||||||
import (
|
|
||||||
"path"
|
|
||||||
"sync"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
// TestLogValues represents a single logging call.
|
|
||||||
type TestLogValues struct {
|
|
||||||
Level Level
|
|
||||||
Module string
|
|
||||||
Filename string
|
|
||||||
Line int
|
|
||||||
Timestamp time.Time
|
|
||||||
Message string
|
|
||||||
}
|
|
||||||
|
|
||||||
// TestWriter is a useful Writer for testing purposes. Each component of the
|
|
||||||
// logging message is stored in the Log array.
|
|
||||||
type TestWriter struct {
|
|
||||||
mu sync.Mutex
|
|
||||||
log []TestLogValues
|
|
||||||
}
|
|
||||||
|
|
||||||
// Write saves the params as members in the TestLogValues struct appended to the Log array.
|
|
||||||
func (writer *TestWriter) Write(level Level, module, filename string, line int, timestamp time.Time, message string) {
|
|
||||||
writer.mu.Lock()
|
|
||||||
defer writer.mu.Unlock()
|
|
||||||
writer.log = append(writer.log,
|
|
||||||
TestLogValues{level, module, path.Base(filename), line, timestamp, message})
|
|
||||||
}
|
|
||||||
|
|
||||||
// Clear removes any saved log messages.
|
|
||||||
func (writer *TestWriter) Clear() {
|
|
||||||
writer.mu.Lock()
|
|
||||||
defer writer.mu.Unlock()
|
|
||||||
writer.log = nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Log returns a copy of the current logged values.
|
|
||||||
func (writer *TestWriter) Log() []TestLogValues {
|
|
||||||
writer.mu.Lock()
|
|
||||||
defer writer.mu.Unlock()
|
|
||||||
v := make([]TestLogValues, len(writer.log))
|
|
||||||
copy(v, writer.log)
|
|
||||||
return v
|
|
||||||
}
|
|
|
@ -1,152 +0,0 @@
|
||||||
// Copyright 2014 Canonical Ltd.
|
|
||||||
// Licensed under the LGPLv3, see LICENCE file for details.
|
|
||||||
|
|
||||||
package loggo
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"os"
|
|
||||||
"sync"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Writer is implemented by any recipient of log messages.
|
|
||||||
type Writer interface {
|
|
||||||
// Write writes a message to the Writer with the given
|
|
||||||
// level and module name. The filename and line hold
|
|
||||||
// the file name and line number of the code that is
|
|
||||||
// generating the log message; the time stamp holds
|
|
||||||
// the time the log message was generated, and
|
|
||||||
// message holds the log message itself.
|
|
||||||
Write(level Level, name, filename string, line int, timestamp time.Time, message string)
|
|
||||||
}
|
|
||||||
|
|
||||||
type registeredWriter struct {
|
|
||||||
writer Writer
|
|
||||||
level Level
|
|
||||||
}
|
|
||||||
|
|
||||||
// defaultName is the name of a writer that is registered
|
|
||||||
// by default that writes to stderr.
|
|
||||||
const defaultName = "default"
|
|
||||||
|
|
||||||
var (
|
|
||||||
writerMutex sync.Mutex
|
|
||||||
writers = map[string]*registeredWriter{
|
|
||||||
defaultName: ®isteredWriter{
|
|
||||||
writer: NewSimpleWriter(os.Stderr, &DefaultFormatter{}),
|
|
||||||
level: TRACE,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
globalMinLevel = TRACE
|
|
||||||
)
|
|
||||||
|
|
||||||
// ResetWriters puts the list of writers back into the initial state.
|
|
||||||
func ResetWriters() {
|
|
||||||
writerMutex.Lock()
|
|
||||||
defer writerMutex.Unlock()
|
|
||||||
writers = map[string]*registeredWriter{
|
|
||||||
"default": ®isteredWriter{
|
|
||||||
writer: NewSimpleWriter(os.Stderr, &DefaultFormatter{}),
|
|
||||||
level: TRACE,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
findMinLevel()
|
|
||||||
}
|
|
||||||
|
|
||||||
// ReplaceDefaultWriter is a convenience method that does the equivalent of
|
|
||||||
// RemoveWriter and then RegisterWriter with the name "default". The previous
|
|
||||||
// default writer, if any is returned.
|
|
||||||
func ReplaceDefaultWriter(writer Writer) (Writer, error) {
|
|
||||||
if writer == nil {
|
|
||||||
return nil, fmt.Errorf("Writer cannot be nil")
|
|
||||||
}
|
|
||||||
writerMutex.Lock()
|
|
||||||
defer writerMutex.Unlock()
|
|
||||||
reg, found := writers[defaultName]
|
|
||||||
if !found {
|
|
||||||
return nil, fmt.Errorf("there is no %q writer", defaultName)
|
|
||||||
}
|
|
||||||
oldWriter := reg.writer
|
|
||||||
reg.writer = writer
|
|
||||||
return oldWriter, nil
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// RegisterWriter adds the writer to the list of writers that get notified
|
|
||||||
// when logging. When registering, the caller specifies the minimum logging
|
|
||||||
// level that will be written, and a name for the writer. If there is already
|
|
||||||
// a registered writer with that name, an error is returned.
|
|
||||||
func RegisterWriter(name string, writer Writer, minLevel Level) error {
|
|
||||||
if writer == nil {
|
|
||||||
return fmt.Errorf("Writer cannot be nil")
|
|
||||||
}
|
|
||||||
writerMutex.Lock()
|
|
||||||
defer writerMutex.Unlock()
|
|
||||||
if _, found := writers[name]; found {
|
|
||||||
return fmt.Errorf("there is already a Writer registered with the name %q", name)
|
|
||||||
}
|
|
||||||
writers[name] = ®isteredWriter{writer: writer, level: minLevel}
|
|
||||||
findMinLevel()
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// RemoveWriter removes the Writer identified by 'name' and returns it.
|
|
||||||
// If the Writer is not found, an error is returned.
|
|
||||||
func RemoveWriter(name string) (Writer, Level, error) {
|
|
||||||
writerMutex.Lock()
|
|
||||||
defer writerMutex.Unlock()
|
|
||||||
registered, found := writers[name]
|
|
||||||
if !found {
|
|
||||||
return nil, UNSPECIFIED, fmt.Errorf("Writer %q is not registered", name)
|
|
||||||
}
|
|
||||||
delete(writers, name)
|
|
||||||
findMinLevel()
|
|
||||||
return registered.writer, registered.level, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func findMinLevel() {
|
|
||||||
// We assume the lock is already held
|
|
||||||
minLevel := CRITICAL
|
|
||||||
for _, registered := range writers {
|
|
||||||
if registered.level < minLevel {
|
|
||||||
minLevel = registered.level
|
|
||||||
}
|
|
||||||
}
|
|
||||||
globalMinLevel.set(minLevel)
|
|
||||||
}
|
|
||||||
|
|
||||||
// WillWrite returns whether there are any writers registered
|
|
||||||
// at or above the given severity level. If it returns
|
|
||||||
// false, a log message at the given level will be discarded.
|
|
||||||
func WillWrite(level Level) bool {
|
|
||||||
return level >= globalMinLevel.get()
|
|
||||||
}
|
|
||||||
|
|
||||||
func writeToWriters(level Level, module, filename string, line int, timestamp time.Time, message string) {
|
|
||||||
writerMutex.Lock()
|
|
||||||
defer writerMutex.Unlock()
|
|
||||||
for _, registered := range writers {
|
|
||||||
if level >= registered.level {
|
|
||||||
registered.writer.Write(level, module, filename, line, timestamp, message)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type simpleWriter struct {
|
|
||||||
writer io.Writer
|
|
||||||
formatter Formatter
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewSimpleWriter returns a new writer that writes
|
|
||||||
// log messages to the given io.Writer formatting the
|
|
||||||
// messages with the given formatter.
|
|
||||||
func NewSimpleWriter(writer io.Writer, formatter Formatter) Writer {
|
|
||||||
return &simpleWriter{writer, formatter}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (simple *simpleWriter) Write(level Level, module, filename string, line int, timestamp time.Time, message string) {
|
|
||||||
logLine := simple.formatter.Format(level, module, filename, line, timestamp, message)
|
|
||||||
fmt.Fprintln(simple.writer, logLine)
|
|
||||||
}
|
|
|
@ -33,7 +33,6 @@ body.layout-rundeck,
|
||||||
body.layout-statuscake,
|
body.layout-statuscake,
|
||||||
body.layout-template,
|
body.layout-template,
|
||||||
body.layout-tls,
|
body.layout-tls,
|
||||||
body.layout-triton,
|
|
||||||
body.layout-vcd,
|
body.layout-vcd,
|
||||||
body.layout-vsphere,
|
body.layout-vsphere,
|
||||||
body.layout-docs,
|
body.layout-docs,
|
||||||
|
|
|
@ -1,35 +0,0 @@
|
||||||
---
|
|
||||||
layout: "triton"
|
|
||||||
page_title: "Provider: Triton"
|
|
||||||
sidebar_current: "docs-triton-index"
|
|
||||||
description: |-
|
|
||||||
Used to provision infrastructure in Joyent's Triton public or on-premise clouds.
|
|
||||||
---
|
|
||||||
|
|
||||||
# Triton Provider
|
|
||||||
|
|
||||||
The Triton provider is used to interact with resources in Joyent's Triton cloud. It is compatible with both public- and on-premise installations of Triton. The provider needs to be configured with the proper credentials before it can be used.
|
|
||||||
|
|
||||||
Use the navigation to the left to read about the available resources.
|
|
||||||
|
|
||||||
## Example Usage
|
|
||||||
|
|
||||||
```
|
|
||||||
provider "triton" {
|
|
||||||
account = "AccountName"
|
|
||||||
key_path = "~/.ssh/id_rsa"
|
|
||||||
key_id = "25:d4:a9:fe:ef:e6:c0:bf:b4:4b:4b:d4:a8:8f:01:0f"
|
|
||||||
|
|
||||||
# If using a private installation of Triton, specify the URL
|
|
||||||
url = "https://us-west-1.api.joyentcloud.com"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Argument Reference
|
|
||||||
|
|
||||||
The following arguments are supported in the `provider` block:
|
|
||||||
|
|
||||||
* `account` - (Required) This is the name of the Triton account. It can also be provided via the `SDC_ACCOUNT` environment variable.
|
|
||||||
* `key_path` - (Required) This is the path to the private key of an SSH key associated with the Triton account to be used.
|
|
||||||
* `key_id` - (Required) This is the fingerprint of the public key matching the key specified in `key_path`. It can be obtained via the command `ssh-keygen -l -E md5 -f /path/to/key`
|
|
||||||
* `url` - (Optional) This is the URL to the Triton API endpoint. It is required if using a private installation of Triton. The default is to use the Joyent public cloud.
|
|
|
@ -1,50 +0,0 @@
|
||||||
---
|
|
||||||
layout: "triton"
|
|
||||||
page_title: "Triton: triton_firewall_rule"
|
|
||||||
sidebar_current: "docs-triton-firewall"
|
|
||||||
description: |-
|
|
||||||
The `triton_firewall_rule` resource represents a rule for the Triton cloud firewall.
|
|
||||||
---
|
|
||||||
|
|
||||||
# triton\_firewall\_rule
|
|
||||||
|
|
||||||
The `triton_firewall_rule` resource represents a rule for the Triton cloud firewall.
|
|
||||||
|
|
||||||
## Example Usages
|
|
||||||
|
|
||||||
Allow traffic on ports tcp/80 and tcp/443 to machines with the 'www' tag from any source
|
|
||||||
|
|
||||||
|
|
||||||
```
|
|
||||||
resource "triton_firewall_rule" "www" {
|
|
||||||
rule = "FROM any TO tag www ALLOW tcp (PORT 80 AND PORT 443)"
|
|
||||||
enabled = true
|
|
||||||
}
|
|
||||||
|
|
||||||
```
|
|
||||||
Block traffic on port tcp/143 to all machines
|
|
||||||
|
|
||||||
|
|
||||||
```
|
|
||||||
resource "triton_firewall_rule" "imap" {
|
|
||||||
rule = "FROM any TO all vms BLOCK tcp port 143"
|
|
||||||
enabled = true
|
|
||||||
}
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
## Argument Reference
|
|
||||||
|
|
||||||
The following arguments are supported:
|
|
||||||
|
|
||||||
* `rule` - (string, Required)
|
|
||||||
The firewall rule described using the Cloud API rule syntax defined at https://docs.joyent.com/public-cloud/network/firewall/cloud-firewall-rules-reference.
|
|
||||||
|
|
||||||
* `enabled` - (boolean) Default: `false`
|
|
||||||
Whether the rule should be effective.
|
|
||||||
|
|
||||||
## Attribute Reference
|
|
||||||
|
|
||||||
The following attributes are exported:
|
|
||||||
|
|
||||||
* `id` - (string) - The identifier representing the firewall rule in Triton.
|
|
|
@ -1,35 +0,0 @@
|
||||||
---
|
|
||||||
layout: "triton"
|
|
||||||
page_title: "Triton: triton_key"
|
|
||||||
sidebar_current: "docs-triton-firewall"
|
|
||||||
description: |-
|
|
||||||
The `triton_key` resource represents an SSH key for a Triton account.
|
|
||||||
---
|
|
||||||
|
|
||||||
# triton\_key
|
|
||||||
|
|
||||||
The `triton_key` resource represents an SSH key for a Triton account.
|
|
||||||
|
|
||||||
## Example Usages
|
|
||||||
|
|
||||||
Create a key
|
|
||||||
|
|
||||||
|
|
||||||
```
|
|
||||||
resource "triton_key" "example" {
|
|
||||||
name = "Example Key"
|
|
||||||
key = "${file("keys/id_rsa")}"
|
|
||||||
}
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
## Argument Reference
|
|
||||||
|
|
||||||
The following arguments are supported:
|
|
||||||
|
|
||||||
* `name` - (string, Change forces new resource)
|
|
||||||
The name of the key. If this is left empty, the name is inferred from the comment in the SSH key material.
|
|
||||||
|
|
||||||
* `key` - (string, Required, Change forces new resource)
|
|
||||||
The SSH key material. In order to read this from a file, use the `file` interpolation.
|
|
||||||
|
|
|
@ -1,78 +0,0 @@
|
||||||
---
|
|
||||||
layout: "triton"
|
|
||||||
page_title: "Triton: triton_machine"
|
|
||||||
sidebar_current: "docs-triton-firewall"
|
|
||||||
description: |-
|
|
||||||
The `triton_machine` resource represents a virtual machine or infrastructure container running in Triton.
|
|
||||||
---
|
|
||||||
|
|
||||||
# triton\_machine
|
|
||||||
|
|
||||||
The `triton_machine` resource represents a virtual machine or infrastructure container running in Triton.
|
|
||||||
|
|
||||||
## Example Usages
|
|
||||||
|
|
||||||
Run a SmartOS base-64 machine.
|
|
||||||
|
|
||||||
|
|
||||||
```
|
|
||||||
resource "triton_machine" "test" {
|
|
||||||
name = "example-machine"
|
|
||||||
package = "g3-standard-0.25-smartos"
|
|
||||||
image = "842e6fa6-6e9b-11e5-8402-1b490459e334"
|
|
||||||
|
|
||||||
tags = {
|
|
||||||
hello = "world"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
## Argument Reference
|
|
||||||
|
|
||||||
The following arguments are supported:
|
|
||||||
|
|
||||||
* `name` - (string)
|
|
||||||
The friendly name for the machine. Triton will generate a name if one is not specified.
|
|
||||||
|
|
||||||
* `tags` - (map)
|
|
||||||
A mapping of tags to apply to the machine.
|
|
||||||
|
|
||||||
* `package` - (string, Required)
|
|
||||||
The name of the package to use for provisioning.
|
|
||||||
|
|
||||||
* `image` - (string, Required)
|
|
||||||
The UUID of the image to provision.
|
|
||||||
|
|
||||||
* `networks` - (list of string)
|
|
||||||
A list of the IDs of the desired networks for the machine.
|
|
||||||
|
|
||||||
* `firewall_enabled` - (boolean) Default: `false`
|
|
||||||
Whether the cloud firewall should be enabled for this machine.
|
|
||||||
|
|
||||||
* `root_authorized_keys` - (string)
|
|
||||||
The public keys authorized for root access via SSH to the machine.
|
|
||||||
|
|
||||||
* `user_data` - (string)
|
|
||||||
Data to be copied to the machine on boot.
|
|
||||||
|
|
||||||
* `user_script` - (string)
|
|
||||||
The user script to run on boot (every boot on SmartMachines).
|
|
||||||
|
|
||||||
* `administrator_pw` - (string)
|
|
||||||
The initial password for the Administrator user. Only used for Windows virtual machines.
|
|
||||||
|
|
||||||
## Attribute Reference
|
|
||||||
|
|
||||||
The following attributes are exported:
|
|
||||||
|
|
||||||
* `id` - (string) - The identifier representing the firewall rule in Triton.
|
|
||||||
* `type` - (string) - The type of the machine (`smartmachine` or `virtualmachine`).
|
|
||||||
* `state` - (string) - The current state of the machine.
|
|
||||||
* `dataset` - (string) - The dataset URN with which the machine was provisioned.
|
|
||||||
* `memory` - (int) - The amount of memory the machine has (in Mb).
|
|
||||||
* `disk` - (int) - The amount of disk the machine has (in Gb).
|
|
||||||
* `ips` - (list of strings) - IP addresses of the machine.
|
|
||||||
* `primaryip` - (string) - The primary (public) IP address for the machine.
|
|
||||||
* `created` - (string) - The time at which the machine was created.
|
|
||||||
* `updated` - (string) - The time at which the machine was last updated.
|
|
|
@ -225,9 +225,9 @@
|
||||||
<a href="/docs/providers/rundeck/index.html">Rundeck</a>
|
<a href="/docs/providers/rundeck/index.html">Rundeck</a>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<li<%= sidebar_current("docs-providers-statuscake") %>>
|
<li<%= sidebar_current("docs-providers-statuscake") %>>
|
||||||
<a href="/docs/providers/statuscake/index.html">StatusCake</a>
|
<a href="/docs/providers/statuscake/index.html">StatusCake</a>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<li<%= sidebar_current("docs-providers-template") %>>
|
<li<%= sidebar_current("docs-providers-template") %>>
|
||||||
<a href="/docs/providers/template/index.html">Template</a>
|
<a href="/docs/providers/template/index.html">Template</a>
|
||||||
|
@ -241,10 +241,6 @@
|
||||||
<a href="/docs/providers/tls/index.html">TLS</a>
|
<a href="/docs/providers/tls/index.html">TLS</a>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<li<%= sidebar_current("docs-providers-triton") %>>
|
|
||||||
<a href="/docs/providers/triton/index.html">Triton</a>
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li<%= sidebar_current("docs-providers-vcd") %>>
|
<li<%= sidebar_current("docs-providers-vcd") %>>
|
||||||
<a href="/docs/providers/vcd/index.html">VMware vCloud Director</a>
|
<a href="/docs/providers/vcd/index.html">VMware vCloud Director</a>
|
||||||
</li>
|
</li>
|
||||||
|
|
|
@ -1,39 +0,0 @@
|
||||||
<% 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">« Documentation Home</a>
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li<%= sidebar_current("docs-triton-index") %>>
|
|
||||||
<a href="/docs/providers/triton/index.html">Triton Provider</a>
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li<%= sidebar_current(/^docs-triton-resource/) %>>
|
|
||||||
<a href="#">Resources</a>
|
|
||||||
|
|
||||||
<ul class="nav nav-visible">
|
|
||||||
<li<%= sidebar_current("docs-triton-resource-firewall-rule") %>>
|
|
||||||
<a href="/docs/providers/triton/r/triton_firewall_rule.html">triton_firewall_rule</a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<ul class="nav nav-visible">
|
|
||||||
<li<%= sidebar_current("docs-triton-resource-key") %>>
|
|
||||||
<a href="/docs/providers/triton/r/triton_key.html">triton_key</a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<ul class="nav nav-visible">
|
|
||||||
<li<%= sidebar_current("docs-triton-resource-machine") %>>
|
|
||||||
<a href="/docs/providers/triton/r/triton_machine.html">triton_machine</a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
<% end %>
|
|
||||||
|
|
||||||
<%= yield %>
|
|
||||||
<% end %>
|
|
Loading…
Reference in New Issue